You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

721 lines
27 KiB
Dart

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<SuperPlayerPage> with SuperPlayerListener {
SuperPlayerController _playerController = SuperPlayerController();
String _sdkVersion = 'Unknown';
List<String> _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<void> 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<void> 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<PlayerRegionProvide>(context);
playerRatioProvide = Provider.of<PlayerRatioProvide>(context);
List<Widget> listData = getDataListControl2();
double btnHeight1 = 70; //第一按钮行高度
double btnHeight2 = 160; //第二按钮行高度
int btnCount = 4; //每行按钮个数
int btnCount3 = listData.length; //每行按钮个数
var mediaSize = MediaQuery.of(context).size;
double btn_left = 70; //第一按钮行高度
double btn_gap = 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: <Widget>[
//第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);
},
),
SizedBox(width: ScreenUtil().setWidth(btn_gap)),
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);
},
),
SizedBox(width: ScreenUtil().setWidth(btn_gap)),
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);
},
),
SizedBox(width: ScreenUtil().setWidth(btn_gap)),
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
? 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<Widget> getDataListControl2() {
double _diameter = 100;
double _iconSize = 70;
double _fontSize = 14;
double _marginVer = 8;
List<Widget> 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");
// });
}
}