提交 8b82f635 authored 作者: kongdywang's avatar kongdywang

1. fix issue of ext method txFormat

2. avoid the issue of repeated rendering of player components in certain scenarios 3. android side compatible with multiple FlutterActivity scenarios 4. add HEVC fallback playback. 5. introduce Picture-in-Picture 2.0 resources on the iOS side, and the project uses the Picture-in-Picture 2.0 capability by default. (cherry picked from commit 44800b08)
上级 6d4b66a1
......@@ -29,6 +29,7 @@ import com.tencent.liteav.base.util.LiteavLog;
import com.tencent.vod.flutter.model.TXPipResult;
import com.tencent.vod.flutter.model.TXPlayerHolder;
import com.tencent.vod.flutter.tools.TXCommonUtil;
import com.tencent.vod.flutter.tools.TXFlutterEngineHolder;
import com.tencent.vod.flutter.tools.TXSimpleEventBus;
import com.tencent.vod.flutter.ui.FlutterPipImplActivity;
......@@ -40,7 +41,6 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
/**
......@@ -54,7 +54,7 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
private boolean misInit = false;
private final Map<Integer, PipCallback> pipCallbacks = new HashMap<>();
private final ActivityPluginBinding mActivityBinding;
private final FlutterPlugin.FlutterPluginBinding mFlutterPluginBinding;
private final FlutterPlugin.FlutterAssets mFlutterAssets;
private final EventChannel mPipEventChannel;
private final FTXPlayerEventSink mPipEventSink = new FTXPlayerEventSink();
......@@ -64,15 +64,14 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
* Picture-in-picture management.
*
* 画中画管理
* @param activityBinding activityBinding
* @param flutterAssets Flutter resource management.
* flutter资源管理
* @param flutterPluginBinding FlutterPluginBinding.
*
*/
public FTXPIPManager(@NonNull EventChannel pipEventChannel, ActivityPluginBinding activityBinding,
FlutterPlugin.FlutterAssets flutterAssets) {
public FTXPIPManager(@NonNull EventChannel pipEventChannel,
FlutterPlugin.FlutterPluginBinding flutterPluginBinding) {
this.mPipEventChannel = pipEventChannel;
this.mActivityBinding = activityBinding;
this.mFlutterAssets = flutterAssets;
this.mFlutterAssets = flutterPluginBinding.getFlutterAssets();
this.mFlutterPluginBinding = flutterPluginBinding;
registerActivityListener();
initPipEventChannel();
}
......@@ -99,7 +98,7 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
* 注册activityResult回调,<h1>必须调用</h1>
*/
public void registerActivityListener() {
if (!mActivityBinding.getActivity().isDestroyed() && !misInit) {
if (!misInit) {
TXSimpleEventBus.getInstance().register(FTXEvent.EVENT_PIP_ACTION, this);
TXSimpleEventBus.getInstance().register(FTXEvent.EVENT_PIP_PLAYER_EVENT_ACTION, this);
misInit = true;
......@@ -130,7 +129,8 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
public int enterPip(PipParams params, TXPlayerHolder playerHolder) {
int pipResult = isSupportDevice();
if (pipResult == FTXEvent.NO_ERROR) {
pipResult = FlutterPipImplActivity.startPip(mActivityBinding.getActivity(), params, playerHolder);
pipResult = FlutterPipImplActivity.startPip(TXFlutterEngineHolder.getInstance().getCurActivity(),
params, playerHolder);
if (pipResult == FTXEvent.NO_ERROR) {
mPipEventSink.success(TXCommonUtil.getParams(FTXEvent.EVENT_PIP_MODE_REQUEST_START, null));
}
......@@ -146,10 +146,13 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
*/
public void exitPip() {
if (mIsInPipMode) {
Intent intent = new Intent(mActivityBinding.getActivity(), FlutterPipImplActivity.class);
intent.setAction(FTXEvent.PIP_ACTION_EXIT);
mActivityBinding.getActivity().startActivity(intent);
mIsInPipMode = false;
final Activity curActivity = TXFlutterEngineHolder.getInstance().getCurActivity();
if (null != curActivity) {
Intent intent = new Intent(curActivity, FlutterPipImplActivity.class);
intent.setAction(FTXEvent.PIP_ACTION_EXIT);
curActivity.startActivity(intent);
mIsInPipMode = false;
}
}
}
......@@ -160,7 +163,7 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
*/
public int isSupportDevice() {
int pipResult = FTXEvent.NO_ERROR;
Activity activity = mActivityBinding.getActivity();
Activity activity = TXFlutterEngineHolder.getInstance().getCurActivity();
if (!activity.isDestroyed()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// check permission
......@@ -208,7 +211,7 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
playOrPauseData.putInt(FTXEvent.EXTRA_NAME_IS_PLAYING, isPlaying ? 1 : 2);
Intent playOrPauseIntent =
new Intent(FTXEvent.ACTION_PIP_PLAY_CONTROL).putExtras(playOrPauseData);
mActivityBinding.getActivity().sendBroadcast(playOrPauseIntent);
mFlutterPluginBinding.getApplicationContext().sendBroadcast(playOrPauseIntent);
}
/**
......@@ -249,12 +252,15 @@ public class FTXPIPManager implements TXSimpleEventBus.EventSubscriber {
* 更新PIP悬浮框按钮
*/
public void updatePipActions(PipParams params) {
Intent intent = new Intent(mActivityBinding.getActivity(), FlutterPipImplActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelable(FTXEvent.EXTRA_NAME_PARAMS, params);
intent.setAction(FTXEvent.PIP_ACTION_UPDATE);
intent.putExtra("data", bundle);
mActivityBinding.getActivity().startActivity(intent);
final Activity mAct = TXFlutterEngineHolder.getInstance().getCurActivity();
if (null != mAct) {
Intent intent = new Intent(mAct, FlutterPipImplActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelable(FTXEvent.EXTRA_NAME_PARAMS, params);
intent.setAction(FTXEvent.PIP_ACTION_UPDATE);
intent.putExtra("data", bundle);
mAct.startActivity(intent);
}
}
public String toAndroidPath(String path) {
......
......@@ -13,7 +13,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
public class TXFlutterEngineHolder {
......@@ -34,7 +34,7 @@ public class TXFlutterEngineHolder {
return SingletonInstance.instance;
}
public void attachBindLife(ActivityPluginBinding binding) {
public void attachBindLife(FlutterPlugin.FlutterPluginBinding binding) {
if (mLifeCallback != null) {
LiteavLog.w(TAG, "TXFlutterEngineHolder is already attach");
return;
......@@ -42,12 +42,6 @@ public class TXFlutterEngineHolder {
if (null == binding) {
return;
}
if (binding.getActivity().isDestroyed() || binding.getActivity().isFinishing()) {
return;
}
if (null == binding.getActivity().getApplication()) {
return;
}
mLifeCallback = new Application.ActivityLifecycleCallbacks() {
@Override
......@@ -98,11 +92,12 @@ public class TXFlutterEngineHolder {
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
synchronized (mActivityList) {
mActivityList.remove(activity);
int index = findIndexByAct(activity);
mActivityList.remove(index);
}
}
};
binding.getActivity().getApplication().registerActivityLifecycleCallbacks(mLifeCallback);
((Application)binding.getApplicationContext()).registerActivityLifecycleCallbacks(mLifeCallback);
}
private int findIndexByAct(Activity activity) {
......@@ -140,20 +135,22 @@ public class TXFlutterEngineHolder {
}
}
public void destroy(ActivityPluginBinding binding) {
public Activity getCurActivity() {
synchronized (mActivityList) {
final int size = mActivityList.size();
final int preIndex = size - 1;
return getActivityByIndex(preIndex);
}
}
public void destroy(FlutterPlugin.FlutterPluginBinding binding) {
if (null == mLifeCallback) {
return;
}
if (null == binding) {
return;
}
if (binding.getActivity().isDestroyed()) {
return;
}
if (null == binding.getActivity().getApplication()) {
return;
}
binding.getActivity().getApplication().unregisterActivityLifecycleCallbacks(mLifeCallback);
((Application)binding.getApplicationContext()).unregisterActivityLifecycleCallbacks(mLifeCallback);
}
public void addAppLifeListener(TXAppStatusListener listener) {
......
......@@ -14,6 +14,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
B484F5A12C2BF0FF0066B1E9 /* TXVodPlayer.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B4C561652C2BBC86005E98E7 /* TXVodPlayer.bundle */; };
E20A0B07B7C48946D41D19CC /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2827D54B4B5A86D43D05BAA7 /* libPods-Runner.a */; };
/* End PBXBuildFile section */
......@@ -48,6 +49,7 @@
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A2ECC199933FCD64A2FE00A3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
B4C561652C2BBC86005E98E7 /* TXVodPlayer.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TXVodPlayer.bundle; sourceTree = "<group>"; };
DAABB34E0246BA7AB0D053FD /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -95,6 +97,7 @@
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
B4C561652C2BBC86005E98E7 /* TXVodPlayer.bundle */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
......@@ -198,6 +201,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B484F5A12C2BF0FF0066B1E9 /* TXVodPlayer.bundle in Resources */,
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
......
// Copyright (c) 2022 Tencent. All rights reserved.
part of SuperPlayer;
const reg = "{@}";
// const reg = "{@}";
const reg = r'\{\@\}';
// extension for string format
extension StringExt on String {
String txFormat(List<String> args) {
String str = this;
if (str.isNotEmpty) {
RegExp regExp = RegExp(reg);
Iterable<Match> findResult = regExp.allMatches(str);
for (int i = 0; i < findResult.length && i < args.length; i++) {
Match match = findResult.elementAt(i);
str = str.replaceRange(match.start, match.end, args[i]);
}
int index = 0;
str = str.replaceAllMapped(RegExp(reg), (match) {
if (index < args.length) {
return args[index++];
} else {
return match[0]!;
}
});
}
return str;
}
......
......@@ -173,6 +173,9 @@ abstract class TXVodPlayEvent {
// Video SEI frame information, Player Premium version 11.6 starts to support
// 视频 SEI 帧信息, 播放器高级版 11.6 版本开始支持
static const VOD_PLAY_EVT_VIDEO_SEI = 2030;
// HEVC downgrade playback, Player Premium version 12.0 starts to support
// HEVC 降级播放,播放器高级版 12.0 版本开始支持
static const VOD_PLAY_EVT_HEVC_DOWNGRADE_PLAYBACK = 2031;
// video loop once complete
static const VOD_PLAY_EVT_LOOP_ONCE_COMPLETE = 6001;
......
......@@ -165,7 +165,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
_fullScreenController.switchToOrientation(orientation);
}
});
_updateState();
_initPlayerState();
}
void _registerObserver() {
......@@ -339,13 +339,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
void _updateState() {
// Refresh the binding of the observer.
_registerObserver();
// Because no callbacks can be triggered after `pop`, and calling `setState` on the fullscreen controller is invalid,
// a task is added to the UI thread here. This task will be triggered after returning to this interface to
// ensure that the playback status is correct.
WidgetsBinding.instance.addPostFrameCallback((timeStamp) => setState(() {
_initPlayerState();
_calculateSize(_playController.videoWidth, _playController.videoHeight);
}));
_calculateSize(_playController.videoWidth, _playController.videoHeight);
}
void _refreshDownloadStatus() async {
......@@ -436,6 +430,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
@override
Widget build(BuildContext context) {
_updateState();
return Center(
child: widget.renderMode == SuperPlayerRenderMode.ADJUST_RESOLUTION ?
IntrinsicHeight(
......@@ -770,13 +765,13 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
void _startHideRunnable() {
_cancelHideRunnable();
_controlViewTimer = Timer(const Duration(milliseconds: _controlViewShowTime), () {
hideControlView();
hideControlView(needHideMenuView: false);
});
}
/// Hide all control components.
/// 隐藏所有控制组件
void hideControlView() {
void hideControlView({bool needHideMenuView = true}) {
if (!_isShowControlView || !mounted) {
return;
}
......@@ -785,12 +780,16 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
}
// Hide moreView
_moreViewKey.currentState?.hideShowMoreView();
if (needHideMenuView) {
_moreViewKey.currentState?.hideShowMoreView();
}
setState(() {
_isShowQualityListView = false;
_isShowControlView = false;
_isShowSubtitleListView = false;
_isShowAudioListView = false;
if (needHideMenuView) {
_isShowQualityListView = false;
_isShowSubtitleListView = false;
_isShowAudioListView = false;
}
});
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论