提交 876a66bc authored 作者: kongdywang's avatar kongdywang

fix ios miss first frame error & fix player bug

上级 c77ab8e4
...@@ -68,7 +68,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method ...@@ -68,7 +68,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method
* 直播播放器 * 直播播放器
*/ */
public FTXLivePlayer(FlutterPlugin.FlutterPluginBinding flutterPluginBinding, Activity activity, public FTXLivePlayer(FlutterPlugin.FlutterPluginBinding flutterPluginBinding, Activity activity,
FTXPIPManager pipManager) { FTXPIPManager pipManager) {
super(); super();
mFlutterPluginBinding = flutterPluginBinding; mFlutterPluginBinding = flutterPluginBinding;
mActivity = activity; mActivity = activity;
...@@ -184,7 +184,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method ...@@ -184,7 +184,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method
result.success(null); result.success(null);
} else if (call.method.equals("startLivePlay")) { } else if (call.method.equals("startLivePlay")) {
String url = call.argument("url"); String url = call.argument("url");
int type = call.argument("playType"); Integer type = call.argument("playType");
int r = startLivePlay(url, type); int r = startLivePlay(url, type);
result.success(r); result.success(r);
} else if (call.method.equals("stop")) { } else if (call.method.equals("stop")) {
...@@ -248,7 +248,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method ...@@ -248,7 +248,7 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method
mPipManager.toAndroidPath(playResumeAssetPath), mPipManager.toAndroidPath(playResumeAssetPath),
mPipManager.toAndroidPath(playPauseAssetPath), mPipManager.toAndroidPath(playPauseAssetPath),
mPipManager.toAndroidPath(playForwardAssetPath), mPipManager.toAndroidPath(playForwardAssetPath),
getPlayerId(),false, false, true); getPlayerId(), false, false, true);
mPipParams.setIsPlaying(isPlaying()); mPipParams.setIsPlaying(isPlaying());
int pipResult = mPipManager.enterPip(mPipParams, mVideoModel); int pipResult = mPipManager.enterPip(mPipParams, mVideoModel);
// 启动成功之后,暂停当前界面视频 // 启动成功之后,暂停当前界面视频
...@@ -277,8 +277,11 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method ...@@ -277,8 +277,11 @@ public class FTXLivePlayer extends FTXBasePlayer implements MethodChannel.Method
return mSurfaceTextureEntry == null ? -1 : mSurfaceTextureEntry.id(); return mSurfaceTextureEntry == null ? -1 : mSurfaceTextureEntry.id();
} }
int startLivePlay(String url, int type) { int startLivePlay(String url, Integer type) {
Log.d(TAG, "startLivePlay:"); Log.d(TAG, "startLivePlay:");
if (null == type) {
type = TXLivePlayer.PLAY_TYPE_LIVE_FLV;
}
mVideoModel.setVideoUrl(url); mVideoModel.setVideoUrl(url);
mVideoModel.setLiveType(type); mVideoModel.setLiveType(type);
if (mLivePlayer != null) { if (mLivePlayer != null) {
......
...@@ -47,17 +47,16 @@ class _DemoShortVideoPlayerState extends State<DemoShortVideoPlayer> with Widget ...@@ -47,17 +47,16 @@ class _DemoShortVideoPlayerState extends State<DemoShortVideoPlayer> with Widget
children: widgetList, children: widgetList,
), ),
SafeArea( SafeArea(
child: Positioned( child: Container(
left: 0, child: InkWell(
top: 0, onTap: _onBackTap,
child: InkWell( child: const Image(
onTap: _onBackTap, width: 40,
child: const Image( height: 40,
width: 40, image: AssetImage("images/superplayer_btn_back_play.png", package: StringResource.PKG_NAME),
height: 40, ),
image: AssetImage("images/superplayer_btn_back_play.png", package: StringResource.PKG_NAME), ),
), )),
))),
], ],
); );
} }
......
...@@ -6,6 +6,7 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:super_player/super_player.dart'; import 'package:super_player/super_player.dart';
import 'package:super_player_example/ui/demo_inputdialog.dart'; import 'package:super_player_example/ui/demo_inputdialog.dart';
import 'package:superplayer_widget/demo_superplayer_lib.dart'; import 'package:superplayer_widget/demo_superplayer_lib.dart';
import 'dart:ui';
/// flutter superplayer demo /// flutter superplayer demo
class DemoSuperPlayer extends StatefulWidget { class DemoSuperPlayer extends StatefulWidget {
...@@ -22,6 +23,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -22,6 +23,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
static const ARGUMENT_TYPE_POS = "arg_type_pos"; static const ARGUMENT_TYPE_POS = "arg_type_pos";
static const ARGUMENT_VIDEO_DATA = "arg_video_data"; static const ARGUMENT_VIDEO_DATA = "arg_video_data";
static const sPlayerViewDisplayRatio = 720.0 / 1280.0; //当前界面播放器view展示的宽高比,用主流的16:9
List<SuperPlayerModel> videoModels = []; List<SuperPlayerModel> videoModels = [];
bool _isFullScreen = false; bool _isFullScreen = false;
...@@ -34,6 +36,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -34,6 +36,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
double? initStartTime; double? initStartTime;
TextStyle _textStyleSelected = new TextStyle(fontSize: 16, color: Colors.white); TextStyle _textStyleSelected = new TextStyle(fontSize: 16, color: Colors.white);
TextStyle _textStyleUnSelected = new TextStyle(fontSize: 16, color: Colors.grey); TextStyle _textStyleUnSelected = new TextStyle(fontSize: 16, color: Colors.grey);
double playerHeight = 220;
@override @override
void initState() { void initState() {
...@@ -59,8 +62,9 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -59,8 +62,9 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
if (null != widget.initParams) { if (null != widget.initParams) {
tabSelectPos = widget.initParams![ARGUMENT_TYPE_POS]; tabSelectPos = widget.initParams![ARGUMENT_TYPE_POS];
initVideoModel = widget.initParams![ARGUMENT_VIDEO_DATA]; initVideoModel = widget.initParams![ARGUMENT_VIDEO_DATA];
initStartTime = widget.initParams![TXPipController.ARGUMENT_PIP_START_TIME]; initStartTime = widget.initParams![TXPipController.ARGUMENT_PIP_START_TIME];
} }
_adjustSuperPlayerViewHeight();
if (tabSelectPos == 0) { if (tabSelectPos == 0) {
_getLiveListData(); _getLiveListData();
} else if (tabSelectPos == 1) { } else if (tabSelectPos == 1) {
...@@ -68,6 +72,11 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -68,6 +72,11 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
} }
} }
/// 竖屏下,播放器始终保持 16 :9的宽高比,优先保证宽度填充
void _adjustSuperPlayerViewHeight() {
playerHeight = (window.physicalSize.width / window.devicePixelRatio) * sPlayerViewDisplayRatio;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( return WillPopScope(
...@@ -136,7 +145,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -136,7 +145,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
Widget _getPlayArea() { Widget _getPlayArea() {
return Container( return Container(
decoration: BoxDecoration(color: Colors.black), decoration: BoxDecoration(color: Colors.black),
height: 220, height: playerHeight,
child: SuperPlayerView(_controller), child: SuperPlayerView(_controller),
); );
} }
...@@ -203,6 +212,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -203,6 +212,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
if (url.isNotEmpty) { if (url.isNotEmpty) {
model.videoURL = url; model.videoURL = url;
playCurrentModel(model, 0); playCurrentModel(model, 0);
_addVideoToCurrentList(model);
} else if (appId != 0 && fileId.isNotEmpty) { } else if (appId != 0 && fileId.isNotEmpty) {
model.videoId = new SuperPlayerVideoId(); model.videoId = new SuperPlayerVideoId();
model.videoId!.fileId = fileId; model.videoId!.fileId = fileId;
...@@ -210,9 +220,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -210,9 +220,7 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
model.videoId!.psign = pSign; model.videoId!.psign = pSign;
} }
loader.getVideoData(model, (resultModel) { loader.getVideoData(model, (resultModel) {
setState(() { _addVideoToCurrentList(resultModel);
videoModels.add(resultModel);
});
playCurrentModel(resultModel, 0); playCurrentModel(resultModel, 0);
}); });
} else { } else {
...@@ -225,6 +233,12 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto ...@@ -225,6 +233,12 @@ class _DemoSuperPlayerState extends State<DemoSuperPlayer> with TXPipPlayerResto
}); });
} }
void _addVideoToCurrentList(SuperPlayerModel model) {
setState(() {
videoModels.add(model);
});
}
void playCurrentModel(SuperPlayerModel model, double startTime) { void playCurrentModel(SuperPlayerModel model, double startTime) {
currentVideoModel = model; currentVideoModel = model;
_controller.setStartTime(startTime); _controller.setStartTime(startTime);
......
...@@ -20,8 +20,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -20,8 +20,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
double _progress = 0.0; double _progress = 0.0;
int _volume = 100; int _volume = 100;
bool _isMute = false; bool _isMute = false;
String _url = String _url = "http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
"http://liteavapp.qcloud.com/live/liteavdemoplayerstreamid_demo1080p.flv";
bool _isStop = true; bool _isStop = true;
bool _isPlaying = false; bool _isPlaying = false;
double _maxLiveProgressTime = 0; double _maxLiveProgressTime = 0;
...@@ -42,12 +41,12 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -42,12 +41,12 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
_progress = event["EVT_PLAY_PROGRESS"].toDouble(); _progress = event["EVT_PLAY_PROGRESS"].toDouble();
_maxLiveProgressTime = _progress >= _maxLiveProgressTime ? _progress : _maxLiveProgressTime; _maxLiveProgressTime = _progress >= _maxLiveProgressTime ? _progress : _maxLiveProgressTime;
progressSliderKey.currentState?.updateProgress(1, _maxLiveProgressTime); progressSliderKey.currentState?.updateProgress(1, _maxLiveProgressTime);
} else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN || } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
//首帧出现 //首帧出现
_isStop = false; _isStop = false;
_isPlaying = true; _isPlaying = true;
EasyLoading.dismiss(); EasyLoading.dismiss();
_resizeVideo(event);
} else if (event["event"] == TXVodPlayEvent.PLAY_EVT_STREAM_SWITCH_SUCC) { } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_STREAM_SWITCH_SUCC) {
//切换流成功 //切换流成功
EasyLoading.dismiss(); EasyLoading.dismiss();
...@@ -60,24 +59,18 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -60,24 +59,18 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
EasyLoading.dismiss(); EasyLoading.dismiss();
EasyLoading.showError("切流失败"); EasyLoading.showError("切流失败");
switchUrl(); switchUrl();
}else if(event["event"] == TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION) { } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION) {
LogUtils.w("PLAY_EVT_CHANGE_RESOLUTION", event); LogUtils.w("PLAY_EVT_CHANGE_RESOLUTION", event);
_resizeVideo(event);
} }
}); });
playNetEventSubscription = _controller.onPlayerNetStatusBroadcast.listen((event) { playNetEventSubscription = _controller.onPlayerNetStatusBroadcast.listen((event) {
double w = (event[TXVodNetEvent.NET_STATUS_VIDEO_WIDTH]).toDouble(); // 订阅状态变化
double h = (event[TXVodNetEvent.NET_STATUS_VIDEO_HEIGHT]).toDouble();
if (w > 0 && h > 0) {
setState(() {
_aspectRatio = 1.0 * w / h;
});
}
}); });
playerStateEventSubscription = _controller.onPlayerState.listen((event) { playerStateEventSubscription = _controller.onPlayerState.listen((event) {
//订阅状态变化 // 订阅状态变化
debugPrint("播放状态 ${event!.name}"); debugPrint("播放状态 ${event!.name}");
}); });
...@@ -88,6 +81,16 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -88,6 +81,16 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
await _controller.startLivePlay(_url, playType: TXPlayType.LIVE_FLV); await _controller.startLivePlay(_url, playType: TXPlayType.LIVE_FLV);
} }
void _resizeVideo(Map<dynamic, dynamic> event) {
int? videoWidth = event[TXVodPlayEvent.EVT_VIDEO_WIDTH];
int? videoHeight = event[TXVodPlayEvent.EVT_VIDEO_HEIGHT];
if ((videoWidth != null && videoWidth != 0) && (videoHeight != null && videoHeight != 0)) {
setState(() {
_aspectRatio = 1.0 * videoWidth / videoHeight;
});
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -104,7 +107,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -104,7 +107,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
case AppLifecycleState.inactive: case AppLifecycleState.inactive:
break; break;
case AppLifecycleState.resumed: case AppLifecycleState.resumed:
if(_isPlaying) { if (_isPlaying) {
_controller.resume(); _controller.resume();
} }
break; break;
...@@ -304,7 +307,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO ...@@ -304,7 +307,7 @@ class _DemoTXLivelayerState extends State<DemoTXLivePlayer> with WidgetsBindingO
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return DemoInputDialog("", 0, "", (String url, int appId, String fileId,String pSign) { return DemoInputDialog("", 0, "", (String url, int appId, String fileId, String pSign) {
_url = url; _url = url;
_controller.stop(); _controller.stop();
if (url.isNotEmpty) { if (url.isNotEmpty) {
......
...@@ -44,16 +44,13 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> ...@@ -44,16 +44,13 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer>
}); });
LogUtils.logOpen = true; LogUtils.logOpen = true;
SuperPlayerPlugin.setGlobalMaxCacheSize(200);
SuperPlayerPlugin.setGlobalCacheFolderPath("postfixPath");
playEventSubscription = _controller.onPlayerEventBroadcast.listen((event) async { playEventSubscription = _controller.onPlayerEventBroadcast.listen((event) async {
//订阅状态变化 //订阅状态变化
if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_BEGIN || if (event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
event["event"] == TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME) {
EasyLoading.dismiss(); EasyLoading.dismiss();
_supportedBitrates = (await _controller.getSupportedBitrates())!; _supportedBitrates = (await _controller.getSupportedBitrates())!;
_isPlaying = true; _isPlaying = true;
_resizeVideo(event);
} else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) { } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_PLAY_PROGRESS) {
_currentProgress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS].toDouble(); _currentProgress = event[TXVodPlayEvent.EVT_PLAY_PROGRESS].toDouble();
double videoDuration = event[TXVodPlayEvent.EVT_PLAY_DURATION].toDouble(); // 总播放时长,转换后的单位 秒 double videoDuration = event[TXVodPlayEvent.EVT_PLAY_DURATION].toDouble(); // 总播放时长,转换后的单位 秒
...@@ -64,6 +61,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> ...@@ -64,6 +61,8 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer>
} }
} else if (event["event"] == TXVodPlayEvent.PLAY_EVT_GET_PLAYINFO_SUCC) { } else if (event["event"] == TXVodPlayEvent.PLAY_EVT_GET_PLAYINFO_SUCC) {
String? playUrl = event[TXVodPlayEvent.EVT_PLAY_URL]?.toString(); String? playUrl = event[TXVodPlayEvent.EVT_PLAY_URL]?.toString();
} else if(event["event"] == TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION) {
_resizeVideo(event);
} }
}); });
...@@ -89,6 +88,16 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> ...@@ -89,6 +88,16 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer>
await _controller.startVodPlay(_url); await _controller.startVodPlay(_url);
} }
void _resizeVideo(Map<dynamic, dynamic> event) {
int? videoWidth = event[TXVodPlayEvent.EVT_VIDEO_WIDTH];
int? videoHeight = event[TXVodPlayEvent.EVT_VIDEO_HEIGHT];
if ((videoWidth != null && videoWidth != 0) && (videoHeight != null && videoHeight != 0)) {
setState(() {
_aspectRatio = 1.0 * videoWidth / videoHeight;
});
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -202,26 +211,6 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer> ...@@ -202,26 +211,6 @@ class _DemoTXVodPlayerState extends State<DemoTXVodPlayer>
), ),
), ),
), ),
new GestureDetector(
onTap: () => {_controller.seek(_currentProgress + 10)},
child: Container(
alignment: Alignment.center,
child: Text(
"前进",
style: TextStyle(fontSize: 18, color: Colors.blue),
),
),
),
new GestureDetector(
onTap: () => {_controller.seek(_currentProgress - 10)},
child: Container(
alignment: Alignment.center,
child: Text(
"后退",
style: TextStyle(fontSize: 18, color: Colors.blue),
),
),
),
new GestureDetector( new GestureDetector(
onTap: () => {onClickSetRate()}, onTap: () => {onClickSetRate()},
child: Container( child: Container(
......
...@@ -64,6 +64,9 @@ class _MyAppState extends State<MyApp> { ...@@ -64,6 +64,9 @@ class _MyAppState extends State<MyApp> {
TXPipController.instance.setNavigatorHandle((params) { TXPipController.instance.setNavigatorHandle((params) {
navigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => DemoSuperPlayer(initParams: params))); navigatorKey.currentState?.push(MaterialPageRoute(builder: (_) => DemoSuperPlayer(initParams: params)));
}); });
SuperPlayerPlugin.setGlobalMaxCacheSize(200);
SuperPlayerPlugin.setGlobalCacheFolderPath("postfixPath");
} }
Future<void> _getflutterSdkVersion() async { Future<void> _getflutterSdkVersion() async {
......
...@@ -41,11 +41,13 @@ static const int CODE_ON_RECEIVE_FIRST_FRAME = 2003; ...@@ -41,11 +41,13 @@ static const int CODE_ON_RECEIVE_FIRST_FRAME = 2003;
id<FlutterTextureRegistry> _textureRegistry; id<FlutterTextureRegistry> _textureRegistry;
float currentPlayTime; float currentPlayTime;
BOOL volatile isVideoFirstFrameReceived;
NSNumber *videoWidth;
NSNumber *videoHeight;
// 主线程队列,用于保证视频播放部分事件按顺序进行
dispatch_queue_t playerMainqueue;
} }
BOOL volatile isStop = false;
- (instancetype)initWithRegistrar:(id<FlutterPluginRegistrar>)registrar - (instancetype)initWithRegistrar:(id<FlutterPluginRegistrar>)registrar
{ {
if (self = [self init]) { if (self = [self init]) {
...@@ -53,6 +55,10 @@ BOOL volatile isStop = false; ...@@ -53,6 +55,10 @@ BOOL volatile isStop = false;
_lastBuffer = nil; _lastBuffer = nil;
_latestPixelBuffer = nil; _latestPixelBuffer = nil;
_textureId = -1; _textureId = -1;
isVideoFirstFrameReceived = false;
videoWidth = 0;
videoHeight = 0;
playerMainqueue = dispatch_get_main_queue();
self.hasEnteredPipMode = NO; self.hasEnteredPipMode = NO;
self.restoreUI = NO; self.restoreUI = NO;
_eventSink = [FTXPlayerEventSinkQueue new]; _eventSink = [FTXPlayerEventSinkQueue new];
...@@ -190,7 +196,6 @@ BOOL volatile isStop = false; ...@@ -190,7 +196,6 @@ BOOL volatile isStop = false;
- (BOOL)stopPlay - (BOOL)stopPlay
{ {
if (_txVodPlayer != nil) { if (_txVodPlayer != nil) {
isStop = true;
return [_txVodPlayer stopPlay]; return [_txVodPlayer stopPlay];
} }
return NO; return NO;
...@@ -517,11 +522,13 @@ BOOL volatile isStop = false; ...@@ -517,11 +522,13 @@ BOOL volatile isStop = false;
(void **)&_latestPixelBuffer)) { (void **)&_latestPixelBuffer)) {
pixelBuffer = _latestPixelBuffer; pixelBuffer = _latestPixelBuffer;
} }
if(isStop && nil != pixelBuffer) { dispatch_async(playerMainqueue, ^{
isStop = false; if(!self->isVideoFirstFrameReceived && nil != pixelBuffer) {
[_eventSink success:[FTXVodPlayer getParamsWithEvent:CODE_ON_RECEIVE_FIRST_FRAME withParams:@{}]]; [self->_eventSink success:[FTXVodPlayer getParamsWithEvent:CODE_ON_RECEIVE_FIRST_FRAME withParams:@{@"EVT_WIDTH":@(self->videoWidth.intValue), @"EVT_HEIGHT":@(self->videoHeight.intValue)}]];
} self->isVideoFirstFrameReceived = true;
return isStop ? nil : pixelBuffer; }
});
return pixelBuffer;
} }
#pragma mark - TXVodPlayListener #pragma mark - TXVodPlayListener
...@@ -531,11 +538,24 @@ BOOL volatile isStop = false; ...@@ -531,11 +538,24 @@ BOOL volatile isStop = false;
// 交给flutter共享纹理处理首帧事件返回时机 // 交给flutter共享纹理处理首帧事件返回时机
if (EvtID == CODE_ON_RECEIVE_FIRST_FRAME) { if (EvtID == CODE_ON_RECEIVE_FIRST_FRAME) {
currentPlayTime = 0; currentPlayTime = 0;
dispatch_async(playerMainqueue, ^{
self->videoWidth = param[@"EVT_WIDTH"];
self->videoHeight = param[@"EVT_HEIGHT"];
});
return; return;
} else if(EvtID == PLAY_EVT_CHANGE_RESOLUTION) {
dispatch_async(playerMainqueue, ^{
self->videoWidth = param[@"EVT_WIDTH"];
self->videoHeight = param[@"EVT_HEIGHT"];
});
} else if(EvtID == PLAY_EVT_PLAY_PROGRESS) { } else if(EvtID == PLAY_EVT_PLAY_PROGRESS) {
currentPlayTime = [param[EVT_PLAY_PROGRESS] floatValue]; currentPlayTime = [param[EVT_PLAY_PROGRESS] floatValue];
} else if(EvtID == PLAY_EVT_PLAY_BEGIN) { } else if(EvtID == PLAY_EVT_PLAY_BEGIN) {
currentPlayTime = 0; currentPlayTime = 0;
} else if(EvtID == PLAY_EVT_START_VIDEO_DECODER) {
dispatch_async(playerMainqueue, ^{
self->isVideoFirstFrameReceived = false;
});
} }
[_eventSink success:[FTXVodPlayer getParamsWithEvent:EvtID withParams:param]]; [_eventSink success:[FTXVodPlayer getParamsWithEvent:EvtID withParams:param]];
......
...@@ -83,6 +83,8 @@ abstract class TXVodPlayEvent { ...@@ -83,6 +83,8 @@ abstract class TXVodPlayEvent {
static const EVT_DESCRIPTION = "EVT_MSG"; // 事件说明 static const EVT_DESCRIPTION = "EVT_MSG"; // 事件说明
static const EVT_PARAM1 = "EVT_PARAM1"; // 事件参数1 static const EVT_PARAM1 = "EVT_PARAM1"; // 事件参数1
static const EVT_PARAM2 = "EVT_PARAM2"; // 事件参数2 static const EVT_PARAM2 = "EVT_PARAM2"; // 事件参数2
static const EVT_VIDEO_WIDTH = "EVT_WIDTH"; // 分辨率之width
static const EVT_VIDEO_HEIGHT = "EVT_HEIGHT"; // 分辨率之height
static const EVT_GET_MSG = "EVT_GET_MSG"; // 消息内容,收到PLAY_EVT_GET_MESSAGE事件时,通过该字段获取消息内容 static const EVT_GET_MSG = "EVT_GET_MSG"; // 消息内容,收到PLAY_EVT_GET_MESSAGE事件时,通过该字段获取消息内容
static const EVT_PLAY_COVER_URL = "EVT_PLAY_COVER_URL"; // 视频封面 static const EVT_PLAY_COVER_URL = "EVT_PLAY_COVER_URL"; // 视频封面
static const EVT_PLAY_URL = "EVT_PLAY_URL"; // 视频地址 static const EVT_PLAY_URL = "EVT_PLAY_URL"; // 视频地址
......
...@@ -57,6 +57,7 @@ class SuperPlayerController { ...@@ -57,6 +57,7 @@ class SuperPlayerController {
double _seekPos = 0; // 记录切换硬解时的播放时间 double _seekPos = 0; // 记录切换硬解时的播放时间
/// 该值会改变新播放视频的播放开始时间点 /// 该值会改变新播放视频的播放开始时间点
double startPos = 0; double startPos = 0;
/// 播放器内核解析出来的视频宽高
double videoWidth = 0; double videoWidth = 0;
double videoHeight = 0; double videoHeight = 0;
double currentPlayRate = 1.0; double currentPlayRate = 1.0;
...@@ -148,6 +149,7 @@ class SuperPlayerController { ...@@ -148,6 +149,7 @@ class SuperPlayerController {
_updatePlayerState(SuperPlayerState.PLAYING); _updatePlayerState(SuperPlayerState.PLAYING);
break; break;
case TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME: // PLAY_EVT_RCV_FIRST_I_FRAME case TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME: // PLAY_EVT_RCV_FIRST_I_FRAME
_configVideoSize(event);
if (_needToPause) { if (_needToPause) {
return; return;
} }
...@@ -175,23 +177,12 @@ class SuperPlayerController { ...@@ -175,23 +177,12 @@ class SuperPlayerController {
_observer?.onPlayProgress(currentDuration, videoDuration, await getPlayableDuration()); _observer?.onPlayProgress(currentDuration, videoDuration, await getPlayableDuration());
} }
break; break;
case TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION:
_configVideoSize(event);
break;
} }
}); });
_vodNetEventListener = _vodPlayerController.onPlayerNetStatusBroadcast.listen((event) { _vodNetEventListener = _vodPlayerController.onPlayerNetStatusBroadcast.listen((event) {
dynamic wd = (event["VIDEO_WIDTH"]);
dynamic hd = (event["VIDEO_HEIGHT"]);
if (null != wd && null != hd) {
double w = wd.toDouble();
double h = hd.toDouble();
if (w > 0 && h > 0) {
if (w != videoWidth) {
videoWidth = w;
}
if (h != videoHeight) {
videoHeight = h;
}
}
}
_playerNetStatusStreamController.add(event); _playerNetStatusStreamController.add(event);
}); });
} }
...@@ -225,6 +216,7 @@ class SuperPlayerController { ...@@ -225,6 +216,7 @@ class SuperPlayerController {
_updatePlayerState(SuperPlayerState.LOADING); _updatePlayerState(SuperPlayerState.LOADING);
break; break;
case TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME: case TXVodPlayEvent.PLAY_EVT_RCV_FIRST_I_FRAME:
_configVideoSize(event);
_updatePlayerState(SuperPlayerState.PLAYING); _updatePlayerState(SuperPlayerState.PLAYING);
_observer?.onRcvFirstIframe(); _observer?.onRcvFirstIframe();
break; break;
...@@ -239,27 +231,27 @@ class SuperPlayerController { ...@@ -239,27 +231,27 @@ class SuperPlayerController {
_maxLiveProgressTime = progress > _maxLiveProgressTime ? progress : _maxLiveProgressTime; _maxLiveProgressTime = progress > _maxLiveProgressTime ? progress : _maxLiveProgressTime;
_observer?.onPlayProgress(progress / 1000, _maxLiveProgressTime / 1000, await getPlayableDuration()); _observer?.onPlayProgress(progress / 1000, _maxLiveProgressTime / 1000, await getPlayableDuration());
break; break;
case TXVodPlayEvent.PLAY_EVT_CHANGE_RESOLUTION:
_configVideoSize(event);
break;
} }
}); });
_liveNetEventListener = _livePlayerController.onPlayerNetStatusBroadcast.listen((event) { _liveNetEventListener = _livePlayerController.onPlayerNetStatusBroadcast.listen((event) {
dynamic wd = (event["VIDEO_WIDTH"]);
dynamic hd = (event["VIDEO_HEIGHT"]);
if (null != wd && null != hd) {
double w = wd.toDouble();
double h = hd.toDouble();
if (w > 0 && h > 0) {
if (w != videoWidth) {
videoWidth = w;
}
if (h != videoHeight) {
videoHeight = h;
}
}
}
_playerNetStatusStreamController.add(event); _playerNetStatusStreamController.add(event);
}); });
} }
void _configVideoSize(Map<dynamic, dynamic> event) {
int? eventVideoWidth = event[TXVodPlayEvent.EVT_VIDEO_WIDTH];
int? eventVideoHeight = event[TXVodPlayEvent.EVT_VIDEO_HEIGHT];
if (eventVideoWidth != null && eventVideoWidth != 0) {
videoWidth = eventVideoWidth.toDouble();
}
if (eventVideoHeight != null && eventVideoHeight != 0) {
videoHeight = eventVideoHeight.toDouble();
}
}
/// 播放视频. /// 播放视频.
/// 10.7版本开始,playWithModel变更为playWithModelNeedLicence,需要通过 {@link SuperPlayerPlugin#setGlobalLicense} 设置 Licence 后方可成功播放, /// 10.7版本开始,playWithModel变更为playWithModelNeedLicence,需要通过 {@link SuperPlayerPlugin#setGlobalLicense} 设置 Licence 后方可成功播放,
/// 否则将播放失败(黑屏),全局仅设置一次即可。直播 Licence、短视频 Licence 和视频播放 Licence 均可使用,若您暂未获取上述 Licence , /// 否则将播放失败(黑屏),全局仅设置一次即可。直播 Licence、短视频 Licence 和视频播放 Licence 均可使用,若您暂未获取上述 Licence ,
...@@ -643,7 +635,7 @@ class SuperPlayerController { ...@@ -643,7 +635,7 @@ class SuperPlayerController {
_observer?.onDispose(); _observer?.onDispose();
playerStreamController.close(); playerStreamController.close();
// 如果处于画中画模式,播放器暂时不释放 // 如果处于画中画模式,播放器暂时不释放
if(!TXPipController.instance.isPlayerInPip(getCurrentController())) { if (!TXPipController.instance.isPlayerInPip(getCurrentController())) {
resetPlayer(); resetPlayer();
_vodPlayerController.dispose(); _vodPlayerController.dispose();
_livePlayerController.dispose(); _livePlayerController.dispose();
......
...@@ -86,6 +86,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs ...@@ -86,6 +86,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
(value) => _playController.enableHardwareDecode(value), (value) => _playController.enableHardwareDecode(value),
(playRate) => _playController.setPlayRate(playRate), (playRate) => _playController.setPlayRate(playRate),
() => _playController.playerType == SuperPlayerType.VOD); () => _playController.playerType == SuperPlayerType.VOD);
_playController.onPlayerNetStatusBroadcast.listen((event) { _playController.onPlayerNetStatusBroadcast.listen((event) {
dynamic wd = (event["VIDEO_WIDTH"]); dynamic wd = (event["VIDEO_WIDTH"]);
dynamic hd = (event["VIDEO_HEIGHT"]); dynamic hd = (event["VIDEO_HEIGHT"]);
...@@ -163,6 +164,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs ...@@ -163,6 +164,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
}, () { }, () {
// onRcvFirstIframe // onRcvFirstIframe
_coverViewKey.currentState?.hideCover(); _coverViewKey.currentState?.hideCover();
// 收到首帧事件后,先用播放器内核解析出来的分辨率对播放器大小进行调整
_calculateSize(_playController.videoWidth, _playController.videoHeight);
}, () { }, () {
// onPlayLoading // onPlayLoading
setState(() { setState(() {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论