diff --git a/lib/widget/my_superplayer-0.0.3.dart b/lib/widget/my_superplayer-0.0.3.dart new file mode 100644 index 0000000..9323294 --- /dev/null +++ b/lib/widget/my_superplayer-0.0.3.dart @@ -0,0 +1,739 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/screen_util.dart'; +import 'package:flutter_superplayer/flutter_superplayer.dart'; +import 'package:flutterptcontrol/flutterptcontrol.dart'; +import 'package:hyzp_ybqx/components/commonFun.dart'; +import 'package:hyzp_ybqx/components/dioFun.dart'; +import 'package:hyzp_ybqx/provider/player_ratio.dart'; +import 'package:hyzp_ybqx/provider/player_region.dart'; +import 'package:provider/provider.dart'; + +import '../components/commonFun.dart'; +import '../services/Storage.dart'; + +const _kControlViewTypes = [kControlViewTypeDefault, kControlViewTypeWithout]; + +class SuperPlayerPage extends StatefulWidget { + SuperPlayerPage( + {@required this.url, + this.id = -2, // 播放点位视频的点位编号,-2 表示播放违章视频 + this.dwip = '', // 点位IP,用于点位视频控制球机方向 + this.loop = 1, + this.title = 'Tencent Player', + Key key}) + : super(key: key); + String dwip; + String url; + String title; + int loop; //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。 + int id; + + @override + _SuperPlayerPageState createState() => _SuperPlayerPageState(); +} + +class _SuperPlayerPageState extends State with SuperPlayerListener { + SuperPlayerController _playerController = SuperPlayerController(); + + String _sdkVersion = 'Unknown'; + List _logs = []; + bool bFullScreen = false; + + String _controlViewType = _kControlViewTypes.first; + + @override + void dispose() { + Playing = false; + // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 + setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1); + super.dispose(); + } + + @override + void initState() { + super.initState(); + //initPlatformState(); + // Future.delayed(const Duration(milliseconds: 1000), () { + // _playerController.playWithModel(SuperPlayerModel(url: widget.url)); + // setState(() { + // }); + // }); + init(); + } + + Future init() async { + await _playerController.addListener(this); + await initPlatformState(); + if (!mounted) return; + print('mounted = ${mounted}'); + // 开启调试日志 + //await FTXPlayerController.setConsoleEnabled(true); + // 初始化播放器 + //await _controller.initialize(onlyAudio: true); + + await _playerController.uiHideDanmu(); // 隐藏弹幕 + //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。 + if (0 == widget.loop) { + await _playerController.setLoop(true); + } + + await _playerController.playWithModel(testSuperPlayerModel); + //_controller.play("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"); + // _controller + // .play('rtmp://125.64.218.67:9901/rtp/gb_play_34020000001320003016_34020000001320003016'); + // 设置循环播放 + //await _controller.setLoop(true); + // 开始播放 + //await _controller.play("http://125.64.218.67:9908/video/2_6063_20210409_140608_川Q31715.mp4"); + } + + SuperPlayerModel get testSuperPlayerModel { + // int appId = 1252463788; + // String fileId = "5285890781763144364"; + + SuperPlayerModel superPlayerModel = SuperPlayerModel( + url: widget.url, + // appId: appId, + // videoId: SuperPlayerVideoId(fileId: fileId), + ); + return superPlayerModel; + } + + // Platform messages are asynchronous, so we initialize in an async method. + Future initPlatformState() async { + String sdkVersion; + // Platform messages may fail, so we use a try/catch PlatformException. + try { + sdkVersion = await FlutterSuperPlayer.sdkVersion; + } on PlatformException { + sdkVersion = 'Failed to get platform version.'; + } + print('sdkVersion = ${sdkVersion}'); + print('mounted = ${mounted}'); + + // If the widget was removed from the tree while the asynchronous platform + // message was in flight, we want to discard the reply rather than calling + // setState to update our non-existent appearance. + if (!mounted) return; + + setState(() { + _sdkVersion = sdkVersion; + }); + } + + void _addLog(String method, dynamic data) { + _logs.add('>>>$method'); + if (data != null) { + _logs.add(data is Map ? json.encode(data) : data); + } + _logs.add(' '); + + setState(() {}); + } + + PlayerRatioProvide playerRatioProvide; + + @override + Widget build(BuildContext context) { + playerRegionProvide = Provider.of(context); + playerRatioProvide = Provider.of(context); + // List listData = getDataListControl2(); + double btnHeight1 = 70; //第一按钮行高度 + double btnHeight2 = 160; //第二按钮行高度 + int btnCount = 4; //每行按钮个数 + // int btnCount3 = listData.length; //每行按钮个数 + var mediaSize = MediaQuery.of(context).size; + + // widget.id:播放点位视频的点位编号,-2 表示播放违章视频 + double btn_left = -2 == widget.id ? 347 : 70; //第一按钮行高度 + double btn_gap = -2 == widget.id ? 104 : 70; //第一按钮行高度 + + //远程控制球机方向按钮外半径和内半径 + double _outerRadius = 270; + double _innerRadius = _outerRadius / 2; + + //double barHeight = bFullScreen ? 0 : MediaQueryData.fromWindow(window).padding.top; + return Scaffold( + appBar: bFullScreen + ? null + : PreferredSize( + preferredSize: Size.fromHeight(ScreenUtil().setHeight(173)), // 设置appBar高度 + // 设置appBar高度 + child: AppBar( + automaticallyImplyLeading: false, + centerTitle: true, + titleSpacing: 0.0, + //设置title的左边距 + flexibleSpace: Container( + //SizedBox(height: ScreenUtil().statusBarHeight), //显示顶部状态栏 + // SizedBox(height: ScreenUtil().setHeight(10)), //显示顶部状态栏 + padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight), //留出顶部状态栏高度 + child: Container( + //height: ScreenUtil().setHeight(173), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Color.fromRGBO(12, 186, 156, 1), + Color.fromRGBO(39, 127, 235, 1), + ], + ), + ), + // decoration: BoxDecoration( + // gradient: LinearGradient(colors: [ + // Color(0xFF0018EB), + // Color(0xFF01C1D9), + // ], begin: Alignment.bottomCenter, end: Alignment.topCenter), + // ), + ), + ), + title: Padding( + padding: EdgeInsets.only(left: 0, right: 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + getIconAndTextButton( + iconColor: Colors.white, + iconData: Icons.chevron_left_outlined, + onPress: () { + getingDwVideo = false; + Navigator.pop(context); + }, + ), + Expanded( + child: Text(widget.title, + style: TextStyle(color: Colors.white, fontSize: 18), + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis), + ), + SizedBox(width: 50), + ], + ), + ), + ), + ), + body: WillPopScope( + child: Container( + // height: ScreenUtil().screenHeight - + // ScreenUtil().statusBarHeight - + // ScreenUtil().bottomBarHeight, + color: Color.fromRGBO(224, 224, 224, 1), + child: Column( + children: [ + //第2行组件,视频播放区 + Center( + child: Container( + //padding: EdgeInsets.only(top: barHeight), + alignment: Alignment(0, -1), + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.width * (9 / 16), + color: Colors.black, + child: Stack( + children: [ + _playState <= 2 ? getMoreWidget(strokeWidth: 3.0) : SizedBox.shrink(), + SuperPlayerView( + controller: _playerController, + controlViewType: _kControlViewTypes[0], + ), + //_playState < 3 ? SizedBox.shrink() : getMoreWidget(strokeWidth: 3.0), + ], + ), + ), + ), + //第3.1行组件,控制按钮区 + bFullScreen ? SizedBox.shrink() : SizedBox(height: ScreenUtil().setHeight(69)), + bFullScreen + ? SizedBox.shrink() + : Row( + children: [ + SizedBox(width: ScreenUtil().setWidth(btn_left)), + getRoundButton( + //(bPlaying) ? '暂停' : '播放', + text: playerRegionProvide.playerText, + icon: playerRegionProvide.playerIcon, + diameter: 130, + onPress: playOrPause, + ), + SizedBox(width: ScreenUtil().setWidth(btn_gap)), + getRoundButton( + text: '刷新', + icon: Icons.autorenew, + diameter: 130, + onPress: () { + restartPlay(urlnew); + }, + ), + // widget.id:播放点位视频的点位编号,-2 表示播放违章视频 + -2 == widget.id + ? SizedBox.shrink() + : SizedBox(width: ScreenUtil().setWidth(btn_gap)), + -2 == widget.id + ? SizedBox.shrink() + : getRoundButton_image( + text: '雨刷', + image_path: 'assets/images/wiper.png', + diameter: 130, + onPress: () { + // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 3); + }, + ), + -2 == widget.id + ? SizedBox.shrink() + : SizedBox(width: ScreenUtil().setWidth(btn_gap)), + -2 == widget.id + ? SizedBox.shrink() + : getRoundButton_image( + text: '放大', + image_path: 'assets/images/zoom_in.png', + imageSize: 72, + diameter: 130, + onPress: () { + // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 11); + }, + ), + -2 == widget.id + ? SizedBox.shrink() + : SizedBox(width: ScreenUtil().setWidth(btn_gap)), + -2 == widget.id + ? SizedBox.shrink() + : getRoundButton_image( + text: '缩小', + image_path: 'assets/images/zoom_out.png', + imageSize: 72, + diameter: 130, + onPress: () { + // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 12); + }, + ), + ], + ), + bFullScreen ? SizedBox.shrink() : SizedBox(height: ScreenUtil().setHeight(79)), + bFullScreen + ? SizedBox.shrink() + : Container( + height: ScreenUtil().setHeight(2 * _outerRadius), + width: ScreenUtil().setWidth(2 * _outerRadius), + child: PtControlWidget( + // innerRadius: _innerRadius, + // outerRadius: _outerRadius, + // 进行像素单位转换,解决按钮响应错乱问题 + innerRadius: _innerRadius / ScreenUtil().pixelRatio, + outerRadius: _outerRadius / ScreenUtil().pixelRatio, + callback: -2 == widget.id // 播放点位视频的点位编号,-2 表示播放违章视频 + ? null + : (status) { + ///点击回调 + print('status = $status'); + switch (status) { + + /// status == -1 超出范围 + /// status == 0 右 + case 0: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 24); + break; + + /// status == 1 右上 + case 1: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 26); + break; + + ///三、球机位移接口方向代码说明: + // 上:8 下:4 左:2 右:1 左上:10 左下:6 右上:9 右下:5 + + // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 + // 21:上移 + // 22:下移 + // 23:左移 + // 24:右移 + // 25:左上移动 + // 26:右上移动 + // 27:左下移动 + // 28:右下移动 + /// status == 2 上 + case 2: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 21); + break; + + /// status == 3 左上 + case 3: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 25); + break; + + /// status == 4 左 + case 4: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 23); + break; + + /// status == 5 左下 + case 5: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 27); + break; + + /// status == 6 下 + case 6: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 22); + break; + + /// status == 7 右下 + case 7: + setSphericalCameraDio( + id: widget.id, dwip: widget.dwip, cmdCode: 28); + break; + + /// status == 8 还原 + case 8: + break; + default: + break; + } + }, + ), + // child: GridView.custom( + // // padding: EdgeInsets.only( + // // left: ScreenUtil().setWidth(35), right: ScreenUtil().setWidth(35)), + // gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + // crossAxisCount: btnCount3, + // mainAxisSpacing: 0, + // crossAxisSpacing: 1, + // childAspectRatio: ratio3, + // ), + // childrenDelegate: SliverChildBuilderDelegate((context, position) { + // return getItemContainer(listData[position]); + // }, childCount: btnCount3)), + ), + //SizedBox(height: ScreenUtil().setHeight(49)), + //Divider(color: Colors.blue), + //第4行组件,分隔栏 + // Container( + // //height: 11, + // height: ScreenUtil().setHeight(28), + // color: Color.fromRGBO(224, 224, 224, 1), + // ), + ], + ), + ), + onWillPop: () { + Playing = false; + getingDwVideo = false; + // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 + setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1); + Navigator.pop(context); //关闭弹框,播放输入视频地址 + }, + ), + ); + } + + @override + void onClickFloatCloseBtn() { + _addLog('onClickFloatCloseBtn', {}); + } + + @override + void onClickSmallReturnBtn() { + _addLog('onClickSmallReturnBtn', {}); + Navigator.maybePop(context); + } + + @override + void onFullScreenChange(bool isFullScreen) { + _addLog('onFullScreenChange', {'isFullScreen': isFullScreen}); + bFullScreen = !bFullScreen; + setState(() {}); + } + + @override + void onPlayProgressChange(int current, int duration) { + _addLog('onPlayProgressChange', {'current': current, 'duration': duration}); + } + + int _playState = 4; + int i = 0; + + @override + void onPlayStateChange(int playState) { + _playState = playState; + i++; + print('$i、playState = $playState'); + _addLog('onPlayStateChange', {'playState': playState}); + setPlayOrPauseIcon(playState); + } + + void setPlayOrPauseIcon(int state) { + //state : 1 播放状态,2 暂停状态 + print('state = $state'); + if (1 == state) { + bPlaying = true; + } else { + bPlaying = false; + } + playerRegionProvide.changePlayerState(bPlaying); + Storage.setString('bPlaying', bPlaying ? 'true' : 'false'); + setState(() {}); + } + + @override + void onStartFloatWindowPlay() { + _addLog('onStartFloatWindowPlay', {}); + } + + //生成圆形按钮部件,基于图标 + Widget getRoundButton( + {double diameter = 144, + double marginVer = 10, + String text, + IconData icon, + double fontSize = 16, + double iconSize = 90, + Color color = const Color.fromRGBO(52, 157, 237, 1), + var onPress}) { + return InkWell( + onTap: onPress, + child: Column( + children: [ + Container( + width: ScreenUtil().setWidth(diameter), + height: ScreenUtil().setHeight(diameter), + alignment: Alignment.center, + child: Icon( + icon, + size: ScreenUtil().setWidth(iconSize), + color: Color.fromRGBO(52, 157, 237, 1), + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(200)), + border: Border.all(width: 0, style: BorderStyle.none), + ), + ), + SizedBox(height: ScreenUtil().setHeight(marginVer)), + Text(text, style: TextStyle(fontSize: fontSize, color: Color.fromRGBO(139, 139, 139, 1))), + ], + ), + ); + } + + //生成圆形按钮部件,基于图片 + Widget getRoundButton_image( + {double diameter = 144, + double marginVer = 10, + String text, + String image_path, + double fontSize = 16, + double imageSize = 90, + Color color = const Color.fromRGBO(52, 157, 237, 1), + Color color_bkg = Colors.white, + var onPress}) { + return InkWell( + onTap: onPress, + child: Column( + children: [ + Container( + width: ScreenUtil().setWidth(diameter), + height: ScreenUtil().setHeight(diameter), + alignment: Alignment.center, + child: Image.asset(image_path, + fit: BoxFit.fitWidth, + width: ScreenUtil().setWidth(imageSize), + //height: ScreenUtil().setWidth(iconSize), + color: Color.fromRGBO(52, 157, 237, 1)), + // child: Icon( + // icon, + // size: ScreenUtil().setWidth(iconSize), + // color: Color.fromRGBO(52, 157, 237, 1), + // ), + decoration: BoxDecoration( + color: color_bkg, + borderRadius: BorderRadius.all(Radius.circular(200)), + border: Border.all(width: 0, style: BorderStyle.none), + ), + ), + SizedBox(height: ScreenUtil().setHeight(marginVer)), + Text(text, style: TextStyle(fontSize: fontSize, color: Color.fromRGBO(139, 139, 139, 1))), + ], + ), + ); + } + + bool bPlaying = true; + + void playOrPause() { + //state : 1 播放状态,2 暂停状态 + _playerController.getPlayState().then((state) { + print('state = $state'); + if (1 == state) { + bPlaying = false; + _playerController.pause(); + } else { + bPlaying = true; + _playerController.resume(); + } + playerRegionProvide.changePlayerState(bPlaying); + Storage.setString('bPlaying', bPlaying ? 'true' : 'false'); + setState(() {}); + }); + } + + void restartPlay(String url) async { + _playState = 4; + bPlaying = true; + _playerController.resetPlayer(); + _playerController.resume(); + // //writeCurrentPosFile(); + // await player.stop(); + // await player.reset(); + // await player.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1); + // await player.setOption(FijkOption.hostCategory, "enable-snapshot", 1); + // await player.setOption(FijkOption.hostCategory, "request-screen-on", 1); + // await player.setOption(FijkOption.hostCategory, "request-audio-focus", 1); + // await player.setOption(FijkOption.hostCategory, "enable-accurate-seek", 1); + // await player.setOption(FijkOption.hostCategory, "max-buffer-size", 500 * 1024); + // await player.setDataSource(url, autoPlay: true).catchError((e) { + // print("setDataSource error: $e"); + // }); + // await player.setLoop(widget.loop); //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。 + // bPlaying = true; + // setState(() {}); + // playerRegionProvide.changePlayerState(bPlaying); + } + + //生成播放控制区第2行按钮List +// List getDataListControl2() { +// double _diameter = 100; +// double _iconSize = 70; +// double _fontSize = 14; +// double _marginVer = 8; +// +// List list = [ +// // getRoundButton( +// // diameter: _diameter, +// // iconSize: _iconSize, +// // text: '快退', +// // icon: Icons.fast_rewind, +// // onPress: () { +// // fastSeek(false); +// // }, +// // ), +// // getRoundButton( +// // diameter: _diameter, +// // iconSize: _iconSize, +// // text: '快进', +// // icon: Icons.fast_forward, +// // onPress: () { +// // fastSeek(true); +// // }, +// // ), +// getRoundButton( +// diameter: _diameter, +// iconSize: _iconSize, +// fontSize: _fontSize, +// marginVer: _marginVer, +// text: '放大', +// icon: Icons.zoom_in, +// onPress: () { +// //print('Icons.videocam'); +// //_inputDialog(context2); +// if (10 >= playerRatioProvide.scale) { +// playerRatioProvide.changeScale(playerRatioProvide.scale + 0.5); +// } +// }, +// ), +// getRoundButton( +// diameter: _diameter, +// iconSize: _iconSize, +// fontSize: _fontSize, +// marginVer: _marginVer, +// text: '缩小', +// icon: Icons.zoom_out, +// onPress: () { +// //print('Icons.videocam'); +// //_getFileDialog(context2); +// if (1 < playerRatioProvide.scale) { +// playerRatioProvide.changeScale(playerRatioProvide.scale - 0.5); +// } +// }, +// ), +// // _getIconAndTextButton( +// // '还原', +// // Icons.reply, +// // Colors.orange, +// // () { +// // //print('Icons.videocam'); +// // //_getFileDialog(context2); +// // // 更新当前位置 +// // playerRatioProvide.changeScale(1.0); +// // playerRatioProvide.changeOffset(Offset(0, 0)); +// // playerRatioProvide.changeDeltaX(0.0); +// // playerRatioProvide.changeDeltaY(0.0); +// // }, +// // ), +// getRoundButton( +// diameter: _diameter, +// iconSize: _iconSize, +// fontSize: _fontSize, +// marginVer: _marginVer, +// text: '截图', +// icon: Icons.camera_alt, +// onPress: () { +// //通过上面定义的key,才能准确调用该类型的该对象的方法 +// //_myFijkPanelWidgetBuilderStateKey.currentState.takeSnapshot(); +// //_fijkPanelWidgetBuilder.currentState..takeSnapshot(); +// takeSnapshot(); +// }, +// ), +// getRoundButton( +// diameter: _diameter, +// iconSize: _iconSize, +// fontSize: _fontSize, +// marginVer: _marginVer, +// text: '全屏', +// icon: Icons.fullscreen, +// onPress: () { +// //player.enterFullScreen(); +// _playerController.toFullScreen(); +// }, +// ), +// ]; +// return list; +// } + + void takeSnapshot() { + // player.takeSnapShot().then((v) { + // var provider = MemoryImage(v); + // precacheImage(provider, context).then((_) { + // setState(() { + // myImageProvider = provider; + // }); + // }); + // FijkLog.d("get snapshot succeed"); + // + // //Uint8List fileData; + // String fileFath; + // ImageSaver.save('extended_image_cropped_image.jpg', v).then((value) { + // fileFath = value; + // // var fileFath = await ImagePickerSaver.saveFile(fileData: fileData); + // print('my save fileFath : $fileFath'); + // }); + // }).catchError((e) { + // FijkLog.d("get snapshot failed"); + // }); + } +} diff --git a/lib/widget/my_superplayer.dart b/lib/widget/my_superplayer.dart index 9323294..c04d545 100644 --- a/lib/widget/my_superplayer.dart +++ b/lib/widget/my_superplayer.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:ui'; +import 'package:fijkplayer/fijkplayer.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/screen_util.dart'; @@ -38,7 +39,8 @@ class SuperPlayerPage extends StatefulWidget { } class _SuperPlayerPageState extends State with SuperPlayerListener { - SuperPlayerController _playerController = SuperPlayerController(); + // SuperPlayerController _playerController = SuperPlayerController(); + final FijkPlayer _playerController = FijkPlayer(); String _sdkVersion = 'Unknown'; List _logs = []; @@ -63,35 +65,78 @@ class _SuperPlayerPageState extends State with SuperPlayerListe // setState(() { // }); // }); - init(); + // init(); + + _playerController.setOption(FijkOption.hostCategory, "enable-snapshot", 1); + _playerController.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1); + startPlay(); } - Future init() async { - await _playerController.addListener(this); - await initPlatformState(); + void startPlay() async { + // await _playerController.addListener(() {}); + if (!mounted) return; print('mounted = ${mounted}'); - // 开启调试日志 - //await FTXPlayerController.setConsoleEnabled(true); - // 初始化播放器 - //await _controller.initialize(onlyAudio: true); - - await _playerController.uiHideDanmu(); // 隐藏弹幕 - //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。 - if (0 == widget.loop) { - await _playerController.setLoop(true); + + await _playerController.setLoop(widget.loop); // 0无限循环,1循环一次,2循环两次,以此类推 + if (widget.loop == 0) { + await _playerController.setOption(FijkOption.playerCategory, "mediacodec-all-videos", 1); + await _playerController.setOption(FijkOption.hostCategory, "enable-snapshot", 1); + await _playerController.setOption(FijkOption.hostCategory, "request-screen-on", 1); + await _playerController.setOption(FijkOption.hostCategory, "request-audio-focus", 1); + await _playerController.setOption(FijkOption.hostCategory, "enable-accurate-seek", 1); + } else { + /// fijkplayer播放点位视频延迟比较大优化-OK,改完后约1秒钟就能打开 - Being + // 是否开启预缓冲,一般直播项目会开启,达到秒开的效果,不过带来了播放丢帧卡顿的体验 + await _playerController.setOption(FijkOption.playerCategory, "packet-buffering", 0); + // 播放前的探测Size,默认是1024K(1M), 改小一点会出画面更快 + // await player.setOption(FijkOption.formatCategory, "probesize", 200); // 1.3S打开 + await _playerController.setOption(FijkOption.formatCategory, "probesize", 200); // 1.3S打开 + await _playerController.setOption(FijkOption.formatCategory, 'http-detect-range-support', 0); + // 设置播放前的探测时间 1,达到首屏秒开效果 + await _playerController.setOption(FijkOption.formatCategory, "analyzeduration", 1); + // 缩短播放的rtmp视频延迟在1s内 + await _playerController.setOption(FijkOption.formatCategory, "fflags", "nobuffer"); + // 支持硬解: 1 开启, O 关闭 + await _playerController.setOption(FijkOption.playerCategory, "mediacodec-hevc", 1); + + /// fijkplayer播放点位视频延迟比较大优化-OK,改完后半秒钟就能打开 - End + + await _playerController.setOption(FijkOption.hostCategory, "request-screen-on", 1); + await _playerController.setOption(FijkOption.hostCategory, "request-audio-focus", 1); } - await _playerController.playWithModel(testSuperPlayerModel); - //_controller.play("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"); - // _controller - // .play('rtmp://125.64.218.67:9901/rtp/gb_play_34020000001320003016_34020000001320003016'); - // 设置循环播放 - //await _controller.setLoop(true); - // 开始播放 - //await _controller.play("http://125.64.218.67:9908/video/2_6063_20210409_140608_川Q31715.mp4"); + await _playerController.setDataSource(widget.url, autoPlay: true).catchError((e) { + print("setDataSource error: $e"); + }); } + // Future init() async { + // await _playerController.addListener(this); + // await initPlatformState(); + // if (!mounted) return; + // print('mounted = ${mounted}'); + // // 开启调试日志 + // //await FTXPlayerController.setConsoleEnabled(true); + // // 初始化播放器 + // //await _controller.initialize(onlyAudio: true); + // + // await _playerController.uiHideDanmu(); // 隐藏弹幕 + // //设置播放循环,默认播放器的循环次数是1, 即不循环播放。如果设置循环次数0,表示无限循环。 + // if (0 == widget.loop) { + // await _playerController.setLoop(true); + // } + // + // await _playerController.playWithModel(testSuperPlayerModel); + // //_controller.play("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"); + // // _controller + // // .play('rtmp://125.64.218.67:9901/rtp/gb_play_34020000001320003016_34020000001320003016'); + // // 设置循环播放 + // //await _controller.setLoop(true); + // // 开始播放 + // //await _controller.play("http://125.64.218.67:9908/video/2_6063_20210409_140608_川Q31715.mp4"); + // } + SuperPlayerModel get testSuperPlayerModel { // int appId = 1252463788; // String fileId = "5285890781763144364"; @@ -105,26 +150,26 @@ class _SuperPlayerPageState extends State with SuperPlayerListe } // Platform messages are asynchronous, so we initialize in an async method. - Future initPlatformState() async { - String sdkVersion; - // Platform messages may fail, so we use a try/catch PlatformException. - try { - sdkVersion = await FlutterSuperPlayer.sdkVersion; - } on PlatformException { - sdkVersion = 'Failed to get platform version.'; - } - print('sdkVersion = ${sdkVersion}'); - print('mounted = ${mounted}'); - - // If the widget was removed from the tree while the asynchronous platform - // message was in flight, we want to discard the reply rather than calling - // setState to update our non-existent appearance. - if (!mounted) return; - - setState(() { - _sdkVersion = sdkVersion; - }); - } + // Future initPlatformState() async { + // String sdkVersion; + // // Platform messages may fail, so we use a try/catch PlatformException. + // try { + // sdkVersion = await FlutterSuperPlayer.sdkVersion; + // } on PlatformException { + // sdkVersion = 'Failed to get platform version.'; + // } + // print('sdkVersion = ${sdkVersion}'); + // print('mounted = ${mounted}'); + // + // // If the widget was removed from the tree while the asynchronous platform + // // message was in flight, we want to discard the reply rather than calling + // // setState to update our non-existent appearance. + // if (!mounted) return; + // + // setState(() { + // _sdkVersion = sdkVersion; + // }); + // } void _addLog(String method, dynamic data) { _logs.add('>>>$method'); @@ -237,10 +282,28 @@ class _SuperPlayerPageState extends State with SuperPlayerListe child: Stack( children: [ _playState <= 2 ? getMoreWidget(strokeWidth: 3.0) : SizedBox.shrink(), - SuperPlayerView( - controller: _playerController, - controlViewType: _kControlViewTypes[0], + // SuperPlayerView( + // controller: _playerController, + // controlViewType: _kControlViewTypes[0], + // ), + + FijkView( + //设置视频区域背景颜色-OK + color: Colors.black, + player: _playerController, + panelBuilder: fijkPanel2Builder(snapShot: true), + fsFit: FijkFit.fill, + // panelBuilder: simplestUI, + // panelBuilder: (FijkPlayer player, BuildContext context, + // Size viewSize, Rect texturePos) { + // return CustomFijkPanel( + // player: player, + // buildContext: context, + // viewSize: viewSize, + // texturePos: texturePos); + // }, ), + //_playState < 3 ? SizedBox.shrink() : getMoreWidget(strokeWidth: 3.0), ], ), @@ -577,26 +640,27 @@ class _SuperPlayerPageState extends State with SuperPlayerListe void playOrPause() { //state : 1 播放状态,2 暂停状态 - _playerController.getPlayState().then((state) { - print('state = $state'); - if (1 == state) { - bPlaying = false; - _playerController.pause(); - } else { - bPlaying = true; - _playerController.resume(); - } - playerRegionProvide.changePlayerState(bPlaying); - Storage.setString('bPlaying', bPlaying ? 'true' : 'false'); - setState(() {}); - }); + // _playerController.getPlayState().then((state) { + // print('state = $state'); + // if (1 == state) { + // bPlaying = false; + // _playerController.pause(); + // } else { + // bPlaying = true; + // _playerController.resume(); + // } + // playerRegionProvide.changePlayerState(bPlaying); + // Storage.setString('bPlaying', bPlaying ? 'true' : 'false'); + // setState(() {}); + // }); } void restartPlay(String url) async { _playState = 4; bPlaying = true; - _playerController.resetPlayer(); - _playerController.resume(); + // _playerController.resetPlayer(); + // _playerController.resume(); + // //writeCurrentPosFile(); // await player.stop(); // await player.reset(); diff --git a/pubspec.lock b/pubspec.lock index 5c85757..c7dd44f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -232,6 +232,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.1.3" + fijkplayer: + dependency: "direct main" + description: + name: fijkplayer + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.8" file: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 9c9d872..7782d03 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -90,7 +90,7 @@ dependencies: cupertino_icons: ^1.0.0 # hyzp_ybqx00_yibin Project Adds - # fijkplayer: ^0.8.7 + fijkplayer: ^0.8.8 path_provider: ^1.6.14 #permission_handler: ^3.3.0 permission_handler: ^5.0.1+1