diff --git a/app/build.gradle b/app/build.gradle index e46fec9a6..c8e43568f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,7 +14,7 @@ android { //noinspection ExpiredTargetSdkVersion targetSdk 28 versionCode 237 - versionName "0604" + versionName "0607" javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] @@ -121,6 +121,7 @@ dependencies { implementation 'androidx.biometric:biometric:1.1.0' implementation 'androidx.room:room-runtime:2.6.1' implementation 'androidx.media:media:1.7.0' + implementation ('com.github.anilbeesetti.nextlib:nextlib-media3ext:0.7.1') { exclude group: 'androidx.media3', module: 'media3-exoplayer' } implementation 'cat.ereza:customactivityoncrash:2.4.0' implementation 'com.github.bassaer:materialdesigncolors:1.0.0' implementation 'com.github.bumptech.glide:glide:4.16.0' diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java index f51815d6f..8b6bb1110 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/CastActivity.java @@ -69,7 +69,7 @@ public class CastActivity extends BaseActivity implements CustomKeyDownCast.List private int scale; private PlayerView getExo() { - return Setting.getRender() == 0 ? mBinding.surface : mBinding.texture; + return mBinding.exo; } private IjkVideoView getIjk() { diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java index ab36fcfd6..6cdd828b8 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java @@ -105,7 +105,7 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, GroupP } private PlayerView getExo() { - return Setting.getRender() == 0 ? mBinding.surface : mBinding.texture; + return mBinding.exo; } private IjkVideoView getIjk() { @@ -756,7 +756,6 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, GroupP setMetadata(); hideProgress(); mPlayers.reset(); - setSpeedVisible(); setTrackVisible(true); mBinding.widget.size.setText(mPlayers.getSizeText()); break; @@ -766,12 +765,9 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, GroupP } } - private void setSpeedVisible() { - mBinding.control.speed.setVisibility(mPlayers.isVod() ? View.VISIBLE : View.GONE); - } - private void setTrackVisible(boolean visible) { mBinding.control.text.setVisibility(visible && mPlayers.haveTrack(C.TRACK_TYPE_TEXT) ? View.VISIBLE : View.GONE); + mBinding.control.speed.setVisibility(visible && mPlayers.isVod() ? View.VISIBLE : View.GONE); mBinding.control.audio.setVisibility(visible && mPlayers.haveTrack(C.TRACK_TYPE_AUDIO) ? View.VISIBLE : View.GONE); mBinding.control.video.setVisibility(visible && mPlayers.haveTrack(C.TRACK_TYPE_VIDEO) ? View.VISIBLE : View.GONE); } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java index 09bd544f7..a6ded15bf 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/SettingPlayerActivity.java @@ -31,6 +31,7 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B private String[] scale; private String[] http; private String[] flag; + private String[] rtsp; public static void start(Activity activity) { activity.startActivity(new Intent(activity, SettingPlayerActivity.class)); @@ -53,6 +54,7 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B mBinding.tunnelText.setText(getSwitch(Setting.isTunnel())); mBinding.bufferText.setText(String.valueOf(Setting.getBuffer())); mBinding.subtitleText.setText(String.valueOf(Setting.getSubtitle())); + mBinding.rtspText.setText((rtsp = ResUtil.getStringArray(R.array.select_rtsp))[Setting.getRtsp()]); mBinding.flagText.setText((flag = ResUtil.getStringArray(R.array.select_flag))[Setting.getFlag()]); mBinding.httpText.setText((http = ResUtil.getStringArray(R.array.select_exo_http))[Setting.getHttp()]); mBinding.scaleText.setText((scale = ResUtil.getStringArray(R.array.select_scale))[Setting.getScale()]); @@ -65,6 +67,7 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B @Override protected void initEvent() { mBinding.ua.setOnClickListener(this::onUa); + mBinding.rtsp.setOnClickListener(this::setRtsp); mBinding.http.setOnClickListener(this::setHttp); mBinding.flag.setOnClickListener(this::setFlag); mBinding.scale.setOnClickListener(this::setScale); @@ -95,6 +98,12 @@ public class SettingPlayerActivity extends BaseActivity implements UaCallback, B Setting.putUa(ua); } + private void setRtsp(View view) { + int index = Setting.getRtsp(); + Setting.putRtsp(index = index == rtsp.length - 1 ? 0 : ++index); + mBinding.rtspText.setText(rtsp[index]); + } + private void setHttp(View view) { int index = Setting.getHttp(); Setting.putHttp(index = index == http.length - 1 ? 0 : ++index); diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index 7e1fd73a4..e217fbe0d 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -280,7 +280,7 @@ public class VideoActivity extends BaseActivity implements CustomKeyDownVod.List } private PlayerView getExo() { - return Setting.getRender() == 0 ? mBinding.surface : mBinding.texture; + return mBinding.exo; } private IjkVideoView getIjk() { diff --git a/app/src/leanback/res/layout/activity_cast.xml b/app/src/leanback/res/layout/activity_cast.xml index 8786dd095..14c219bc7 100644 --- a/app/src/leanback/res/layout/activity_cast.xml +++ b/app/src/leanback/res/layout/activity_cast.xml @@ -8,20 +8,11 @@ android:keepScreenOn="true"> - - + app:surface_type="none" /> - - + app:surface_type="none" /> + + + + + + + + - - + app:surface_type="none" /> getHeaders() { return headers == null ? new HashMap<>() : checkUa(headers); } @@ -280,6 +287,10 @@ public class Players implements Player.Listener, IMediaPlayer.Listener, Analytic return TextUtils.isEmpty(getUrl()); } + public boolean isLive() { + return getDuration() < 5 * 60 * 1000; + } + public boolean isVod() { return getDuration() > 5 * 60 * 1000; } diff --git a/app/src/main/java/com/fongmi/android/tv/player/custom/NextRenderersFactory.java b/app/src/main/java/com/fongmi/android/tv/player/custom/NextRenderersFactory.java new file mode 100644 index 000000000..f4d01fefa --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/player/custom/NextRenderersFactory.java @@ -0,0 +1,56 @@ +package com.fongmi.android.tv.player.custom; + +import android.content.Context; +import android.os.Handler; + +import androidx.annotation.NonNull; +import androidx.media3.common.util.Log; +import androidx.media3.exoplayer.DefaultRenderersFactory; +import androidx.media3.exoplayer.Renderer; +import androidx.media3.exoplayer.audio.AudioRendererEventListener; +import androidx.media3.exoplayer.audio.AudioSink; +import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; +import androidx.media3.exoplayer.video.VideoRendererEventListener; + +import java.util.ArrayList; + +import io.github.anilbeesetti.nextlib.media3ext.ffdecoder.FfmpegAudioRenderer; +import io.github.anilbeesetti.nextlib.media3ext.ffdecoder.FfmpegVideoRenderer; + +public class NextRenderersFactory extends DefaultRenderersFactory { + + private static final String TAG = NextRenderersFactory.class.getSimpleName(); + + public NextRenderersFactory(@NonNull Context context) { + super(context); + } + + @Override + protected void buildAudioRenderers(@NonNull Context context, int extensionRendererMode, @NonNull MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, @NonNull AudioSink audioSink, @NonNull Handler eventHandler, @NonNull AudioRendererEventListener eventListener, @NonNull ArrayList out) { + super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out); + int extensionRendererIndex = out.size(); + if (extensionRendererMode == EXTENSION_RENDERER_MODE_PREFER) { + extensionRendererIndex--; + } + try { + Renderer renderer = new FfmpegAudioRenderer(eventHandler, eventListener, audioSink); + out.add(extensionRendererIndex++, renderer); + Log.i(TAG, "Loaded FfmpegAudioRenderer."); + } catch (Exception e) { + throw new RuntimeException("Error instantiating Ffmpeg extension", e); + } + } + + @Override + protected void buildVideoRenderers(@NonNull Context context, int extensionRendererMode, @NonNull MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, @NonNull Handler eventHandler, @NonNull VideoRendererEventListener eventListener, long allowedVideoJoiningTimeMs, @NonNull ArrayList out) { + super.buildVideoRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, eventHandler, eventListener, allowedVideoJoiningTimeMs, out); + int extensionRendererIndex = out.size(); + try { + Renderer renderer = new FfmpegVideoRenderer(allowedVideoJoiningTimeMs, eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); + out.add(extensionRendererIndex++, renderer); + Log.i(TAG, "Loaded FfmpegVideoRenderer."); + } catch (Exception e) { + throw new RuntimeException("Error instantiating Ffmpeg extension", e); + } + } +} diff --git a/app/src/main/java/com/fongmi/android/tv/player/TrackNameProvider.java b/app/src/main/java/com/fongmi/android/tv/player/custom/TrackNameProvider.java similarity index 99% rename from app/src/main/java/com/fongmi/android/tv/player/TrackNameProvider.java rename to app/src/main/java/com/fongmi/android/tv/player/custom/TrackNameProvider.java index 4a15a7995..4c01bb7d3 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/TrackNameProvider.java +++ b/app/src/main/java/com/fongmi/android/tv/player/custom/TrackNameProvider.java @@ -1,4 +1,4 @@ -package com.fongmi.android.tv.player; +package com.fongmi.android.tv.player.custom; import android.content.res.Resources; import android.text.TextUtils; diff --git a/app/src/main/java/com/fongmi/android/tv/ui/dialog/TrackDialog.java b/app/src/main/java/com/fongmi/android/tv/ui/dialog/TrackDialog.java index 689a229c5..f1cbb6d0c 100644 --- a/app/src/main/java/com/fongmi/android/tv/ui/dialog/TrackDialog.java +++ b/app/src/main/java/com/fongmi/android/tv/ui/dialog/TrackDialog.java @@ -20,7 +20,7 @@ import com.fongmi.android.tv.bean.Sub; import com.fongmi.android.tv.bean.Track; import com.fongmi.android.tv.databinding.DialogTrackBinding; import com.fongmi.android.tv.player.Players; -import com.fongmi.android.tv.player.TrackNameProvider; +import com.fongmi.android.tv.player.custom.TrackNameProvider; import com.fongmi.android.tv.ui.adapter.TrackAdapter; import com.fongmi.android.tv.ui.custom.SpaceItemDecoration; import com.fongmi.android.tv.utils.FileChooser; diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index faaa04711..7a4e096fc 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,7 +1,7 @@ - 影视 + OK影视 再按一次返回键退出 @@ -122,6 +122,7 @@ 隧道模式 连线方式 缓冲时间 + RTSP 通道 User-Agent @@ -309,4 +310,9 @@ 选择字幕 + + UDP + TCP + + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index af89bb2f5..e6ff78d0a 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,7 +1,7 @@ - 影視 + OK影視 再按一次返回鍵退出 @@ -122,6 +122,7 @@ 隧道模式 連線方式 緩衝時間 + RTSP 通道 User-Agent @@ -310,4 +311,9 @@ 選擇字幕 + + UDP + TCP + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4ab9337e..5ada77697 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ - TV + OKTV Press back again to exit @@ -122,6 +122,7 @@ Tunnel mode HTTP method Buffer time + RTSP channel User-Agent @@ -314,4 +315,9 @@ Select subtitle track + + UDP + TCP + + \ No newline at end of file diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java index a33ddaf7d..92a696a08 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java @@ -117,7 +117,7 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, Custom } private PlayerView getExo() { - return Setting.getRender() == 0 ? mBinding.surface : mBinding.texture; + return mBinding.exo; } private IjkVideoView getIjk() { @@ -819,7 +819,6 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, Custom resetToggle(); hideProgress(); mPlayers.reset(); - setSpeedVisible(); setTrackVisible(true); checkPlayImg(mPlayers.isPlaying()); mBinding.control.size.setText(mPlayers.getSizeText()); @@ -831,12 +830,9 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, Custom } } - private void setSpeedVisible() { - mBinding.control.action.speed.setVisibility(mPlayers.isVod() ? View.VISIBLE : View.GONE); - } - private void setTrackVisible(boolean visible) { mBinding.control.action.text.setVisibility(visible && mPlayers.haveTrack(C.TRACK_TYPE_TEXT) ? View.VISIBLE : View.GONE); + mBinding.control.action.speed.setVisibility(visible && mPlayers.isVod() ? View.VISIBLE : View.GONE); mBinding.control.action.audio.setVisibility(visible && mPlayers.haveTrack(C.TRACK_TYPE_AUDIO) ? View.VISIBLE : View.GONE); mBinding.control.action.video.setVisibility(visible && mPlayers.haveTrack(C.TRACK_TYPE_VIDEO) ? View.VISIBLE : View.GONE); } @@ -1143,7 +1139,7 @@ public class LiveActivity extends BaseActivity implements Clock.Callback, Custom super.onUserLeaveHint(); if (isRedirect()) return; if (isLock()) App.post(this::onLock, 500); - if (mPlayers.haveTrack(C.TRACK_TYPE_VIDEO)) mPiP.enter(this, Setting.getLiveScale() == 2); + if (mPlayers.haveTrack(C.TRACK_TYPE_VIDEO)) mPiP.enter(this, mPlayers.getVideoSize(), Setting.getLiveScale()); } @Override diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index a150294f3..0e86fc6a5 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -249,7 +249,7 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo } private PlayerView getExo() { - return Setting.getRender() == 0 ? mBinding.surface : mBinding.texture; + return mBinding.exo; } private IjkVideoView getIjk() { @@ -1700,7 +1700,7 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo super.onUserLeaveHint(); if (isRedirect()) return; if (isLock()) App.post(this::onLock, 500); - if (mPlayers.haveTrack(C.TRACK_TYPE_VIDEO)) mPiP.enter(this, getScale() == 2); + if (mPlayers.haveTrack(C.TRACK_TYPE_VIDEO)) mPiP.enter(this, mPlayers.getVideoSize(), getScale()); } @Override diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java index cdae5eeee..328d927f4 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/fragment/SettingPlayerFragment.java @@ -36,6 +36,7 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B private String[] scale; private String[] http; private String[] flag; + private String[] rtsp; public static SettingPlayerFragment newInstance() { return new SettingPlayerFragment(); @@ -59,6 +60,7 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B mBinding.bufferText.setText(String.valueOf(Setting.getBuffer())); mBinding.subtitleText.setText(String.valueOf(Setting.getSubtitle())); mBinding.danmuLoadText.setText(getSwitch(Setting.isDanmuLoad())); + mBinding.rtspText.setText((rtsp = ResUtil.getStringArray(R.array.select_rtsp))[Setting.getRtsp()]); mBinding.flagText.setText((flag = ResUtil.getStringArray(R.array.select_flag))[Setting.getFlag()]); mBinding.httpText.setText((http = ResUtil.getStringArray(R.array.select_exo_http))[Setting.getHttp()]); mBinding.scaleText.setText((scale = ResUtil.getStringArray(R.array.select_scale))[Setting.getScale()]); @@ -72,6 +74,7 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B @Override protected void initEvent() { mBinding.ua.setOnClickListener(this::onUa); + mBinding.rtsp.setOnClickListener(this::setRtsp); mBinding.http.setOnClickListener(this::setHttp); mBinding.flag.setOnClickListener(this::setFlag); mBinding.scale.setOnClickListener(this::onScale); @@ -104,6 +107,12 @@ public class SettingPlayerFragment extends BaseFragment implements UaCallback, B Setting.putUa(ua); } + private void setRtsp(View view) { + int index = Setting.getRtsp(); + Setting.putRtsp(index = index == rtsp.length - 1 ? 0 : ++index); + mBinding.rtspText.setText(rtsp[index]); + } + private void setHttp(View view) { int index = Setting.getHttp(); Setting.putHttp(index = index == http.length - 1 ? 0 : ++index); diff --git a/app/src/mobile/java/com/fongmi/android/tv/utils/PiP.java b/app/src/mobile/java/com/fongmi/android/tv/utils/PiP.java index e3392fe3e..2ba4d333c 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/utils/PiP.java +++ b/app/src/mobile/java/com/fongmi/android/tv/utils/PiP.java @@ -13,6 +13,7 @@ import android.view.View; import androidx.annotation.DrawableRes; import androidx.annotation.StringRes; +import androidx.media3.common.VideoSize; import androidx.media3.ui.R; import com.fongmi.android.tv.App; @@ -71,15 +72,27 @@ public class PiP { } } - public void enter(Activity activity, boolean four) { + public void enter(Activity activity, VideoSize size, int scale) { try { if (noPiP() || activity.isInPictureInPictureMode() || !Setting.isBackgroundPiP()) return; - builder.setAspectRatio(new Rational(four ? 4 : 16, four ? 3 : 9)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) builder.setAutoEnterEnabled(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) builder.setSeamlessResizeEnabled(true); + if (scale == 1) builder.setAspectRatio(new Rational(16, 9)); + else if (scale == 2) builder.setAspectRatio(new Rational(4, 3)); + else builder.setAspectRatio(getRational(size)); activity.enterPictureInPictureMode(builder.build()); } catch (Exception e) { e.printStackTrace(); } } + + private Rational getRational(VideoSize size) { + Rational limitWide = new Rational(239, 100); + Rational limitTall = new Rational(100, 239); + Rational rational = new Rational(size.width, size.height); + if (rational.isInfinite()) return new Rational(16, 9); + if (rational.floatValue() > limitWide.floatValue()) return limitWide; + if (rational.floatValue() < limitTall.floatValue()) return limitTall; + return rational; + } } diff --git a/app/src/mobile/res/layout-sw600dp/activity_video.xml b/app/src/mobile/res/layout-sw600dp/activity_video.xml index 277392001..96b0a5333 100644 --- a/app/src/mobile/res/layout-sw600dp/activity_video.xml +++ b/app/src/mobile/res/layout-sw600dp/activity_video.xml @@ -22,20 +22,11 @@ android:focusable="true"> - - + app:surface_type="none" /> - - + app:surface_type="none" /> - - + app:surface_type="none" /> + + + + + + + +