import 'dart:async'; import 'dart:convert'; import 'dart:ui'; import 'dart:io'; 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 'package:fijkplayer/fijkplayer.dart'; import '../components/commonFun.dart'; import '../services/Storage.dart'; 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 { final SuperPlayerController _playerController = SuperPlayerController(); final FijkPlayer _ijkPlayer = (){ var player = FijkPlayer(); player.setOption(FijkOption.playerCategory, "packet-buffering", 0); player.setOption(FijkOption.formatCategory, "probesize", 1024); return player; }(); String _sdkVersion = 'Unknown'; List _logs = []; bool bFullScreen = false; @override void dispose() { Playing = false; // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1); super.dispose(); _ijkPlayer.release(); _playerController.resetPlayer(); _playerController.release(); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); } @override void initState() { super.initState(); init(); } Future init() async { await _playerController.addListener(this); await initPlatformState(); if (!mounted) return; if (_useIJKPlayer) { await _playerController.removeListener(this); _ijkPlayer.addListener(_fijkValueListener); _ijkPlayer.setDataSource(widget.url, autoPlay: true); } else { await _playerController.uiHideDanmu(); if (0 == widget.loop) { await _playerController.setLoop(true); } await _playerController.playWithModel(testSuperPlayerModel); } } bool get _useIJKPlayer { return Platform.isIOS && widget.url.startsWith("rtmp"); } SuperPlayerModel get testSuperPlayerModel { return SuperPlayerModel(url: widget.url); } // 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; return Scaffold( appBar: bFullScreen ? null : PreferredSize( preferredSize: Size.fromHeight(ScreenUtil().setHeight(173)), // 设置appBar高度 // 设置appBar高度 child: AppBar( automaticallyImplyLeading: false, centerTitle: true, titleSpacing: 0.0, flexibleSpace: Container( padding: EdgeInsets.only(top: ScreenUtil().statusBarHeight), //留出顶部状态栏高度 child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ Color.fromRGBO(12, 186, 156, 1), Color.fromRGBO(39, 127, 235, 1), ], ), ), ), ), 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; pop(); }, ), 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( color: Color.fromRGBO(224, 224, 224, 1), child: Column( children: [ //第2行组件,视频播放区 Center( child: Container( 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(), _useIJKPlayer ? FijkView(player: _ijkPlayer, color: Colors.black) : SuperPlayerView(controller: _playerController) ], ), ), ), //第3.1行组件,控制按钮区 bFullScreen ? SizedBox.shrink() : SizedBox(height: ScreenUtil().setHeight(69)), bFullScreen ? SizedBox.shrink() : Row( children: [ SizedBox(width: ScreenUtil().setWidth(btn_left)), getRoundButton( 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; } }, ), ), ], ), ), onWillPop: () { // 云台控制代码:1:停止动作、3:启动雨刷、11:焦距变大、12:焦距变小 setSphericalCameraDio(id: widget.id, dwip: widget.dwip, cmdCode: 1); pop(); }, ), ); } pop() async { Playing = false; getingDwVideo = false; _ijkPlayer.removeListener(() {}); await _playerController.removeListener(this); Navigator.pop(context); } @override void onClickFloatCloseBtn() { _addLog('onClickFloatCloseBtn', {}); } @override void onClickSmallReturnBtn() { _addLog('onClickSmallReturnBtn', {}); pop(); } @override void onFullScreenChange(bool isFullScreen) { _addLog('onFullScreenChange', {'isFullScreen': isFullScreen}); if (bFullScreen == isFullScreen) return; bFullScreen = isFullScreen; 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', {}); } void _fijkValueListener() { FijkValue value = _ijkPlayer.value; onPlayStateChange(value.state == FijkState.started ? 1 : 2); onFullScreenChange(value.fullScreen); } //生成圆形按钮部件,基于图标 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), 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; Future playOrPause() async { //state : 1 播放状态,2 暂停状态 int state; if (_useIJKPlayer) { state = _ijkPlayer.state == FijkState.started ? 1 : 2; } else { state = await _playerController.getPlayState(); } if (1 == state) { bPlaying = false; _useIJKPlayer ? _ijkPlayer.pause() : _playerController.pause(); } else { bPlaying = true; _useIJKPlayer ? _ijkPlayer.start() : _playerController.resume(); } playerRegionProvide.changePlayerState(bPlaying); Storage.setString('bPlaying', bPlaying ? 'true' : 'false'); setState(() {}); } void restartPlay(String url) async { _playState = 4; bPlaying = true; if (_useIJKPlayer) { await _ijkPlayer.reset(); _ijkPlayer.setDataSource(widget.url, autoPlay: true); } else { _playerController.resetPlayer(); _playerController.resume(); } } //生成播放控制区第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"); // }); } }