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_ybqx511528_xingwen/components/commonFun.dart'; import 'package:hyzp_ybqx511528_xingwen/components/dioFun.dart'; import 'package:hyzp_ybqx511528_xingwen/provider/player_ratio.dart'; import 'package:hyzp_ybqx511528_xingwen/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; 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; //远程控制球机方向按钮外半径和内半径 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(347)), getRoundButton( //(bPlaying) ? '暂停' : '播放', text: playerRegionProvide.playerText, icon: playerRegionProvide.playerIcon, diameter: 130, onPress: playOrPause, ), SizedBox(width: ScreenUtil().setWidth(104)), getRoundButton( text: '刷新', icon: Icons.autorenew, diameter: 130, onPress: () { restartPlay(urlnew); }, ), ], ), 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 ? 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; 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))), ], ), ); } 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"); // }); } }