diff --git a/XixunPlayer/app/build.gradle b/XixunPlayer/app/build.gradle index 9788a72..0fe7371 100644 --- a/XixunPlayer/app/build.gradle +++ b/XixunPlayer/app/build.gradle @@ -35,7 +35,7 @@ android { dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' -// implementation 'androidx.media3:media3-exoplayer:1.2.0' + implementation 'androidx.media3:media3-exoplayer:1.2.0' // implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8' // implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25' diff --git a/XixunPlayer/app/libs/ijkplayer-armv7a-0.8.8.aar b/XixunPlayer/app/libs/ijkplayer-armv7a-0.8.8.aar deleted file mode 100644 index 8db5d43..0000000 Binary files a/XixunPlayer/app/libs/ijkplayer-armv7a-0.8.8.aar and /dev/null differ diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleAnaClock.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleAnaClock.java index 8ae2841..50afac2 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleAnaClock.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleAnaClock.java @@ -32,7 +32,8 @@ public class EleAnaClock extends View implements Choreographer.FrameCallback { public EleAnaClock(float w, float h, String path, JSMap layer, Context context) { super(context); - timeZone = ZoneId.of(layer.stnn("timeZone")); + var aTimeZone = layer.str("timeZone"); + if(aTimeZone!=null) timeZone = ZoneId.of(aTimeZone); img = BitmapFactory.decodeFile(path); pinHourColor = Color.parseColor(layer.stnn("pinHourColor")); pinMinColor = Color.parseColor(layer.stnn("pinMinColor")); @@ -75,7 +76,7 @@ public class EleAnaClock extends View implements Choreographer.FrameCallback { sPath.close(); } void cal() { - var time = LocalTime.now(timeZone); + var time = timeZone==null ? LocalTime.now() : LocalTime.now(timeZone); sAngle = time.getSecond() * 6; mAngle = time.getMinute() * 6 + sAngle/60; hAngle = time.getHour() * 30 + mAngle/12; diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleDigiClock.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleDigiClock.java index 1d4e1db..6ffd273 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleDigiClock.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleDigiClock.java @@ -38,7 +38,8 @@ public class EleDigiClock extends LinearBox implements Choreographer.FrameCallba public EleDigiClock(String prefix, JSMap json, Context context) { super(context); setGravity(Gravity.CENTER); - timeZone = ZoneId.of(json.stnn("timeZone")); + var aZone = json.str("timeZone"); + if(aZone!=null) timeZone = ZoneId.of(aZone); var spaceWidth = json.dbl("spaceWidth"); JSList pics = json.jslist("arrayPics"); for(var pic : pics) imgs.put(pic.stnn("name"), BitmapFactory.decodeFile(prefix+pic.stnn("id"))); @@ -227,7 +228,7 @@ public class EleDigiClock extends LinearBox implements Choreographer.FrameCallba } void cal() { - var dt = LocalDateTime.now(timeZone); + var dt = timeZone==null ? LocalDateTime.now() : LocalDateTime.now(timeZone); var time = dt.toLocalTime(); var hms = Dates.fmt(time, timeptn); ampmComp.setImageBitmap(imgs.get(time.getHour()<12?"AM":"PM")); diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java index b54eefb..eedc1d4 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleScroll.java @@ -14,12 +14,15 @@ import gnph.util.JSMap; public class EleScroll extends View implements DrawOther, Choreographer.FrameCallback { ArrayList others; + int w, h; Bitmap img; int interval, cur, end, step; char effect; - public EleScroll(String dirPre, JSMap json, Context context) { + public EleScroll(Context context, String dirPre, JSMap json, int w, int h) { super(context); + this.w = w; + this.h = h; img = BitmapFactory.decodeFile(dirPre + json.stnn("id")); var effStr = json.str("effect"); if(effStr==null || effStr.equals("no")) return; @@ -61,7 +64,7 @@ public class EleScroll extends View implements DrawOther, Choreographer.FrameCal canvas.drawBitmap(img, cur, 0, null); canvas.drawBitmap(img, cur+img.getWidth(), 0, null); } else if(effect=='r') { - var x = cur-img.getWidth()+getWidth(); + var x = cur-img.getWidth()+w; canvas.drawBitmap(img, x, 0, null); canvas.drawBitmap(img, x-img.getWidth(), 0, null); } else if(effect=='t') { diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java index a77ad8e..fbdfe77 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/EleVideo.java @@ -4,49 +4,58 @@ import android.content.Context; import android.view.SurfaceHolder; import android.view.SurfaceView; +import androidx.annotation.OptIn; +import androidx.media3.common.MediaItem; +import androidx.media3.common.util.UnstableApi; +import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.exoplayer.SeekParameters; + +import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IjkMediaPlayer; -public class EleVideo extends SurfaceView { +public class EleVideo extends SurfaceView implements SurfaceHolder.Callback { + String path; + float vol; IjkMediaPlayer ijkPlayer; + ExoPlayer exoPlayer; public EleVideo(Context context, String path, float vol) { super(context); - initIjk(path, vol); + this.path = path; + this.vol = vol; + initIjk(); } -// @OptIn(markerClass = UnstableApi.class) -// void initExo(String path, float vol) { -// exoPlayer = new ExoPlayer.Builder(getContext()).build(); -// exoPlayer.setMediaItem(MediaItem.fromUri(path)); -// exoPlayer.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); -// exoPlayer.setSeekParameters(SeekParameters.CLOSEST_SYNC); -// exoPlayer.setVolume(vol); -// exoPlayer.setVideoSurfaceView(this); -// } - void initIjk(String path, float vol) { + @OptIn(markerClass = UnstableApi.class) + void initExo() { + exoPlayer = new ExoPlayer.Builder(getContext()).build(); + exoPlayer.setMediaItem(MediaItem.fromUri(path)); + exoPlayer.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); + exoPlayer.setSeekParameters(SeekParameters.CLOSEST_SYNC); + exoPlayer.setVolume(vol); + exoPlayer.setVideoSurfaceView(this); + exoPlayer.prepare(); + } + void initIjk() { ijkPlayer = new IjkMediaPlayer(); + //ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1); ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0); ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzeduration", 1); ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48); try { - getHolder().addCallback(new SurfaceHolder.Callback() { - @Override - public void surfaceCreated(SurfaceHolder holder) { - ijkPlayer.setDisplay(holder); - } - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - System.out.println("surfaceChanged"); - } - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - System.out.println("surfaceDestroyed"); - } - }); + getHolder().addCallback(this); ijkPlayer.setDataSource(path); ijkPlayer.setLooping(true); ijkPlayer.setVolume(vol, vol); + ijkPlayer.setOnPreparedListener((IMediaPlayer var1)->{ + if(ijkPlayer.getBitRate() > 12000000) { + getHolder().removeCallback(this); + release(); + initExo(); + } + if(isShown()) start(); + }); ijkPlayer.prepareAsync(); } catch (Throwable e) { Util.makeText(getContext(), e.getMessage()).show(); @@ -54,43 +63,55 @@ public class EleVideo extends SurfaceView { ijkPlayer = null; } } + @Override + public void surfaceCreated(SurfaceHolder holder) { + if(ijkPlayer!=null) ijkPlayer.setDisplay(holder); + } + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + System.out.println("surfaceChanged"); + } + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + System.out.println("surfaceDestroyed"); + } void start() { if(ijkPlayer!=null) ijkPlayer.start(); -// else if(exoPlayer!=null) { -// if(exoPlayer.getPlaybackState()==ExoPlayer.STATE_IDLE) exoPlayer.prepare(); -// exoPlayer.play(); -// } + else if(exoPlayer!=null) { + if(exoPlayer.getPlaybackState()==ExoPlayer.STATE_IDLE) exoPlayer.prepare(); + exoPlayer.play(); + } } void pause() { if(ijkPlayer!=null) { ijkPlayer.pause(); ijkPlayer.seekTo(0); } -// if(exoPlayer!=null && exoPlayer.isPlaying()) { -// exoPlayer.pause(); -// exoPlayer.seekToDefaultPosition(); -// } + if(exoPlayer!=null && exoPlayer.isPlaying()) { + exoPlayer.pause(); + exoPlayer.seekToDefaultPosition(); + } } void release() { if(ijkPlayer!=null) { ijkPlayer.release(); ijkPlayer = null; } -// if(exoPlayer!=null) { -// exoPlayer.release(); -// exoPlayer = null; -// } + if(exoPlayer!=null) { + exoPlayer.release(); + exoPlayer = null; + } } String getState() { -// else if(exoPlayer!=null) { -// var state = exoPlayer.getPlaybackState(); -// if(state==ExoPlayer.STATE_IDLE) return "STATE_IDLE"; -// if(state==ExoPlayer.STATE_BUFFERING) return "STATE_BUFFERING"; -// if(state==ExoPlayer.STATE_READY) return "STATE_READY"; -// if(state==ExoPlayer.STATE_ENDED) return "STATE_ENDED"; -// } + if(exoPlayer!=null) { + var state = exoPlayer.getPlaybackState(); + if(state==ExoPlayer.STATE_IDLE) return "STATE_IDLE"; + if(state==ExoPlayer.STATE_BUFFERING) return "STATE_BUFFERING"; + if(state==ExoPlayer.STATE_READY) return "STATE_READY"; + if(state==ExoPlayer.STATE_ENDED) return "STATE_ENDED"; + } return "null"; } diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java index 5d9dab4..dddd581 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/MainActivity.java @@ -26,6 +26,7 @@ import androidx.annotation.OptIn; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import androidx.media3.common.util.UnstableApi; import com.xixun.joey.aidlset.CardService; @@ -49,6 +50,7 @@ import gnph.util.JSList; import gnph.util.JSMap; import gnph.util.NumFmts; import gnph.util.O; +import tv.danmaku.ijk.media.player.IjkMediaMeta; public class MainActivity extends ComponentActivity implements Choreographer.FrameCallback, Runnable { @@ -180,7 +182,6 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra waitTo = 0; var page = page(0); dur = page.tDur; - progView.stopAndPrepare(curAva); page.setMillis(millis); if(state != 6) { setContentView(progView); @@ -200,12 +201,14 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra new Thread(this).start(); } + public void stopProg() { + if(progView==null) return; + progView.release(); + progView = null; + setContentView(backView); + } public boolean delProgFile() { - if(progView!=null) { - progView.release(); - progView = null; - setContentView(backView); - } + stopProg(); var files = new File(Util.programDir).listFiles(); var ok = true; if(files != null) for(var file : files) if(! file.delete()) ok = false; @@ -281,7 +284,6 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra choreographer.postFrameCallback(this); return; } - progView.stopAndPrepare(curAva); } } page(curAva).setMillis(lastPage.endMilli); @@ -347,7 +349,6 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra syncMs = milli; buf.append("Sync. milli:").append(milli).append(" start:").append(start).append(" diff:").append(milli - start).append("\n"); } - progView.stopAndPrepare(curAva); page(curAva).setMillis(start); if(state != 6) { setContentView(progView); @@ -360,7 +361,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra return progView.pages.get(progView.avas.get(i)); } - public void run() { + @OptIn(markerClass = UnstableApi.class) public void run() { try { var serverSocket = new ServerSocket(3333); while(true) { @@ -386,35 +387,7 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra } new JSMap("_type", _type, "idList", ids).write(out); } else if("proStart".equals(_type)) { - var proSize = obj.intg("proSize"); - var statFs = new StatFs(Environment.getExternalStorageDirectory().getPath()); - var remain = statFs.getAvailableBytes() - proSize - 1048576; - if(remain < 0) { - var latch = new CountDownLatch(1); - runOnUiThread(() -> { - System.out.println("removeAllViews ..."); - if(progView!=null) { - progView.release(); - progView = null; - setContentView(backView); - } - latch.countDown(); - }); - var files = new File(Util.programDir).listFiles(); - if(files == null) return; - Arrays.sort(files, (f1, f2) -> (int) (f1.lastModified() - f2.lastModified())); - try { - latch.await(); - } catch (InterruptedException ignored) {} - for(var file : files) { - if(hases!=null && hases.contains(file.getName())) continue; - var len = file.length(); - if(file.delete()) { - remain += len; - if(remain>=0) break; - } - } - } + Util.deleteFiles(obj.intg("proSize"), hases); } else if("fileStart".equals(_type)) { var size = obj.intg("size"); var name = obj.stnn("id"); @@ -439,7 +412,6 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra new JSMap("success", true).write(out); } else if("proEnd".equals(_type)) { new JSMap("success", true).write(out); - buf.append("proEnd\n"); runOnUiThread(this::initProg); } else if("DelPrograms".equals(_type)) { var latch = new CountDownLatch(1); @@ -475,12 +447,14 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra writer.append(" Sync: ").append(Dates.fmt(syncMs, fmt)).append("\n"); writer.append("Page End: ").append(progView==null || progView.avas.isEmpty() ? "0" : Dates.fmt(page(curAva).endMilli, fmt)).append(" CurPage: ").append(String.valueOf(curAva)).append(" / ").append(progView==null || progView.avas.isEmpty() ? "0" : String.valueOf(progView.avas.get(curAva))).append("\n"); writer.append(" Current: ").append(Dates.fmt(System.currentTimeMillis(), fmt)).append("\n"); + var statFs = new StatFs(Environment.getExternalStorageDirectory().getPath()); + writer.append(" Disk: ").append(String.valueOf(statFs.getTotalBytes()/1000000)).append(" ").append(String.valueOf(statFs.getAvailableBytes()/1000000)).append(" ").append(String.valueOf(statFs.getFreeBytes()/1000000)).append(" (total avail free)\n"); var actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); var memoryInfo = new ActivityManager.MemoryInfo(); actManager.getMemoryInfo(memoryInfo); - writer.append("Memory: ").append(String.valueOf(memoryInfo.totalMem/1000000)).append(" ").append(String.valueOf(memoryInfo.availMem/1000000)).append(" ").append(String.valueOf(memoryInfo.threshold/1000000)).append(" ").append(String.valueOf(memoryInfo.lowMemory)).append(" (total avail threshold low)\n"); + writer.append(" Memory: ").append(String.valueOf(memoryInfo.totalMem/1000000)).append(" ").append(String.valueOf(memoryInfo.availMem/1000000)).append(" ").append(String.valueOf(memoryInfo.threshold/1000000)).append(" ").append(String.valueOf(memoryInfo.lowMemory)).append(" (total avail threshold low)\n"); var runtime = Runtime.getRuntime(); - writer.append("Runtime Memory: ").append(String.valueOf(runtime.maxMemory()/1000000)).append(" ").append(String.valueOf(runtime.totalMemory()/1000000)).append(" ").append(NumFmts.cfix2().format(runtime.freeMemory()*0.000001)).append(" (max total free)\n"); + writer.append("Runtime: ").append(String.valueOf(runtime.maxMemory()/1000000)).append(" ").append(String.valueOf(runtime.totalMemory()/1000000)).append(" ").append(NumFmts.cfix2().format(runtime.freeMemory()*0.000001)).append(" (max total free)\n"); var latch = new CountDownLatch(1); runOnUiThread(() -> { if(! progView.avas.isEmpty()) { @@ -490,26 +464,24 @@ public class MainActivity extends ComponentActivity implements Choreographer.Fra if(ele.view instanceof EleVideo) { var view = (EleVideo) ele.view; if(view.ijkPlayer!=null) { - writer.append("isVideoPlaying: ").append(String.valueOf(view.ijkPlayer.isPlaying())).append("\n"); - writer.append("getVideoDecoder: ").append(String.valueOf(view.ijkPlayer.getVideoDecoder())).append("\n"); - var MediaInfo = view.ijkPlayer.getMediaInfo(); - writer.append("mMediaPlayerName: ").append(MediaInfo.mMediaPlayerName).append("\n"); - writer.append("mVideoDecoder: ").append(MediaInfo.mVideoDecoder).append("\n"); - writer.append("mVideoDecoderImpl: ").append(MediaInfo.mVideoDecoderImpl).append("\n"); - writer.append("mAudioDecoder: ").append(MediaInfo.mAudioDecoder).append("\n"); - writer.append("mAudioDecoderImpl: ").append(MediaInfo.mAudioDecoderImpl).append("\n"); - writer.append("mFormat: ").append(MediaInfo.mMeta.mFormat).append("\n"); + writer.append("VideoPlaying: ").append(String.valueOf(view.ijkPlayer.isPlaying())).append(" ").append(String.valueOf(view.ijkPlayer.getCurrentPosition())).append("/").append(String.valueOf(view.ijkPlayer.getDuration())).append("\n"); + writer.append(" BitRate: ").append(String.valueOf(view.ijkPlayer.getBitRate()/1000)).append("\n"); + writer.append("VideoDecoder: ").append(String.valueOf(view.ijkPlayer.getVideoDecoder())).append("\n"); + var mediaInfo = view.ijkPlayer.getMediaInfo(); + writer.append("Format: ").append(mediaInfo.mMeta.mFormat).append("\n"); + writer.append("VideoDecoder: ").append(mediaInfo.mVideoDecoder).append(" ").append(mediaInfo.mVideoDecoderImpl).append("\n"); + writer.append("AudioDecoder: ").append(mediaInfo.mAudioDecoder).append(" ").append(mediaInfo.mAudioDecoderImpl).append("\n"); + //writer.append("PROFILE: ").append(mediaInfo.mMeta.getString(IjkMediaMeta.IJKM_KEY_CODEC_PROFILE)).append("\n"); + } else if(view.exoPlayer!=null) { + writer.append("isVideoPlaying: ").append(String.valueOf(view.exoPlayer.isPlaying())).append(" ").append(String.valueOf(view.exoPlayer.getCurrentPosition())).append("/").append(String.valueOf(view.exoPlayer.getDuration())).append("\n"); + writer.append("getPlaybackState: ").append(view.getState()).append("\n"); + writer.append("getPlayerError: ").append(String.valueOf(view.exoPlayer.getPlayerError())).append("\n"); + writer.append("getVideoFormat: ").append(String.valueOf(view.exoPlayer.getVideoFormat())).append("\n"); + var cnt = view.exoPlayer.getRendererCount(); + for(int rr=0; rr (int) (f2.lastModified() - f1.lastModified())); + var writer = new OutputStreamWriter(out); + for(var file : files) { + var len = file.length(); + writer.append(file.getName()).append(' ').append(String.valueOf(file.length())).append('\n'); + } + writer.append('\n'); + writer.flush(); } else if("GetFile".equals(_type)) { var name = obj.str("name"); if(name!=null) IOs.writeCloseIn(out, new FileInputStream(Util.programDir+"/"+name)); diff --git a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java index 3ae63d0..0d1f7af 100644 --- a/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java +++ b/XixunPlayer/app/src/main/java/com/xixun/xixunplayer/Prog.java @@ -80,7 +80,7 @@ public class Prog extends AbsLayout { } else if(ele.type.equals("MultiPng")) { JSList imgs = source.jslist("arrayPics"); if(imgs.isEmpty()) continue; - if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) ele.view = new EleScroll(Util.programDir+"/", imgs.get(0), context); + if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) ele.view = new EleScroll(context, Util.programDir+"/", imgs.get(0), w, h); else ele.view = new EleFlip(Util.programDir+"/", imgs, context); } else if(ele.type.equals("SplitText")) { JSList imgs = source.jslist("arrayPics"); @@ -88,7 +88,7 @@ public class Prog extends AbsLayout { ele.view = new AbsLayout(context); var partHeight = _program.intg("height"); if(imgs.size()==1 && imgs.get(0).intg("picDuration")==0) { - var view = new EleScroll(Util.programDir+"/", imgs.get(0), context); + var view = new EleScroll(context, Util.programDir+"/", imgs.get(0), w, h); ((AbsLayout) ele.view).addView(view, new AbsLayout.LayoutParams(x, y, splitWidths.get(0).intValue(), h)); view.others = new ArrayList<>(); for(int i=1; i keeps) { + var statFs = new StatFs(Environment.getExternalStorageDirectory().getPath()); + var remain = statFs.getAvailableBytes() - proSize - 1048576; + if(remain >= 0) return; + var latch = new CountDownLatch(1); + MainActivity.ins.runOnUiThread(() -> { + System.out.println("stopProg ..."); + MainActivity.ins.stopProg(); + latch.countDown(); + }); + var files = new File(Util.programDir).listFiles(); + if(files == null) return; + Arrays.sort(files, (f1, f2) -> (int) (f1.lastModified() - f2.lastModified())); + try { + latch.await(); + } catch (InterruptedException ignored) {} + for(var file : files) { + if(keeps!=null && keeps.contains(file.getName())) continue; + var len = file.length(); + if(file.delete()) { + remain += len; + if(remain>=0) break; + } + } + } }