From 078447dc583a8c5fb66264e268439f52f5f545a5 Mon Sep 17 00:00:00 2001 From: mlch911 Date: Sat, 30 Apr 2022 19:40:11 +0800 Subject: [PATCH] Fix Bug: SuperPlayer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SuperPlayer在 iOS 上无法播放 rtmp,换用 fijkplayer --- ios/Podfile.lock | 10 + ios/Runner/Info.plist | 3 + lib/components/dioFun.dart | 2 - .../example/ios/Podfile.lock | 4 +- .../ios/Runner.xcodeproj/project.pbxproj | 18 ++ lib/widget/my_superplayer.dart | 230 +++++------------- pubspec.lock | 7 + pubspec.yaml | 2 +- 8 files changed, 108 insertions(+), 168 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4940f77..05eb770 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -19,6 +19,7 @@ PODS: - audioplayers (0.0.1): - Flutter - BaiduMapKit (5.4.0) + - BIJKPlayer (0.7.16) - camera (0.0.1): - Flutter - city_pickers (0.0.1): @@ -27,6 +28,9 @@ PODS: - Flutter - disable_screenshots (0.0.1): - Flutter + - fijkplayer (0.8.8): + - BIJKPlayer (~> 0.7.10) + - Flutter - Flutter (1.0.0) - flutter_bmfbase (0.0.1): - BaiduMapKit (= 5.4.0) @@ -83,6 +87,7 @@ DEPENDENCIES: - city_pickers (from `.symlinks/plugins/city_pickers/ios`) - device_info (from `.symlinks/plugins/device_info/ios`) - disable_screenshots (from `.symlinks/plugins/disable_screenshots/ios`) + - fijkplayer (from `.symlinks/plugins/fijkplayer/ios`) - Flutter (from `Flutter`) - flutter_bmfbase (from `.symlinks/plugins/flutter_bmfbase/ios`) - flutter_bmfmap (from `.symlinks/plugins/flutter_bmfmap/ios`) @@ -105,6 +110,7 @@ SPEC REPOS: trunk: - AFNetworking - BaiduMapKit + - BIJKPlayer - FMDB - Masonry - TXLiteAVSDK_Professional @@ -122,6 +128,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/device_info/ios" disable_screenshots: :path: ".symlinks/plugins/disable_screenshots/ios" + fijkplayer: + :path: ".symlinks/plugins/fijkplayer/ios" Flutter: :path: Flutter flutter_bmfbase: @@ -162,10 +170,12 @@ SPEC CHECKSUMS: app_installer: 6c31be407728fb6d67cce038fd8547e563e6982c audioplayers: 53f0f30789b10ab2009771c6c79def00980945e4 BaiduMapKit: 40a4382633859bd569d40da9f9a2e98a277dd28b + BIJKPlayer: 4c5d66e5cb99ae5bade6f22a4fcc031722a81c64 camera: a0ca5080336f7af47b88436e5e26da3dee5568f0 city_pickers: b0370f4c35c201723b5b7fcce10ec29b59d5bc35 device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 disable_screenshots: 3f3a1881efa341fcdad395fb2b25e11a9a7bce0b + fijkplayer: 0d3793a2822d030ef5bba77f904bff1f7a91a115 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_bmfbase: 8ac2c94f3f110daec8e499dc13f8a983b0c8ee40 flutter_bmfmap: 57030919b16b5353649fbea77b6143129f7a4ff1 diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index d5cbfb4..609b071 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -35,6 +35,9 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown UISupportedInterfaceOrientations~ipad diff --git a/lib/components/dioFun.dart b/lib/components/dioFun.dart index fe2edb3..7334b46 100644 --- a/lib/components/dioFun.dart +++ b/lib/components/dioFun.dart @@ -2145,7 +2145,6 @@ Future getDwspUrlNew( print('判断_dwspUrl是否是视频地址?'); print('_dwspUrl : ${_dwspUrl}'); if (!isVideoUrl(_dwspUrl)) { - print('_dwspUrl非视频地址?'); Fluttertoast.showToast( msg: '获取 $getingDwmc 点位视频地址失败,请稍后重试。', toastLength: Toast.LENGTH_SHORT, @@ -2154,7 +2153,6 @@ Future getDwspUrlNew( //正在获取点位视频标志,禁止重入 getingDwVideo = false; } else { - print('_dwspUrl非视频地址?'); print('开始播放视频地址'); playUrl(index: indexRecord, url: _dwspUrl, context: context); } diff --git a/lib/my_flutter_superplayer/example/ios/Podfile.lock b/lib/my_flutter_superplayer/example/ios/Podfile.lock index 2547ae6..58702fb 100644 --- a/lib/my_flutter_superplayer/example/ios/Podfile.lock +++ b/lib/my_flutter_superplayer/example/ios/Podfile.lock @@ -44,11 +44,11 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce - Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_superplayer: 50d64a438d4e917295d7c8d8124bcc239f323dad Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 TXLiteAVSDK_Professional: 165018e2f0570d2608d7ea2b785fc273558f9920 PODFILE CHECKSUM: b1f7a399522c118a74b177b13c01eca692aa7e6d -COCOAPODS: 1.10.1 +COCOAPODS: 1.11.2 diff --git a/lib/my_flutter_superplayer/example/ios/Runner.xcodeproj/project.pbxproj b/lib/my_flutter_superplayer/example/ios/Runner.xcodeproj/project.pbxproj index 15601f4..8e0d79d 100644 --- a/lib/my_flutter_superplayer/example/ios/Runner.xcodeproj/project.pbxproj +++ b/lib/my_flutter_superplayer/example/ios/Runner.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, EFF62BD560582B20FF73FC03 /* [CP] Copy Pods Resources */, + BF68C3AC7529D977444CE650 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -258,6 +259,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + BF68C3AC7529D977444CE650 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; EFF62BD560582B20FF73FC03 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/lib/widget/my_superplayer.dart b/lib/widget/my_superplayer.dart index dcff875..f59b7e4 100644 --- a/lib/widget/my_superplayer.dart +++ b/lib/widget/my_superplayer.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:ui'; +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -12,12 +13,11 @@ 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'; -const _kControlViewTypes = [kControlViewTypeDefault, kControlViewTypeWithout]; - class SuperPlayerPage extends StatefulWidget { SuperPlayerPage( {@required this.url, @@ -38,31 +38,28 @@ class SuperPlayerPage extends StatefulWidget { } class _SuperPlayerPageState extends State with SuperPlayerListener { - SuperPlayerController _playerController = SuperPlayerController(); + final SuperPlayerController _playerController = SuperPlayerController(); + final FijkPlayer _ijkPlayer = FijkPlayer(); 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(); + _ijkPlayer.release(); + _playerController.resetPlayer(); + _playerController.release(); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); } @override void initState() { super.initState(); - //initPlatformState(); - // Future.delayed(const Duration(milliseconds: 1000), () { - // _playerController.playWithModel(SuperPlayerModel(url: widget.url)); - // setState(() { - // }); - // }); init(); } @@ -70,38 +67,26 @@ class _SuperPlayerPageState extends State with SuperPlayerListe 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); + + 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); } + } - 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"); + bool get _useIJKPlayer { + return Platform.isIOS && widget.url.startsWith("rtmp"); } SuperPlayerModel get testSuperPlayerModel { - // int appId = 1252463788; - // String fileId = "5285890781763144364"; - - SuperPlayerModel superPlayerModel = SuperPlayerModel( - url: widget.url, - // appId: appId, - // videoId: SuperPlayerVideoId(fileId: fileId), - ); - return superPlayerModel; + return SuperPlayerModel(url: widget.url); } // Platform messages are asynchronous, so we initialize in an async method. @@ -157,7 +142,6 @@ class _SuperPlayerPageState extends State with SuperPlayerListe double _outerRadius = 270; double _innerRadius = _outerRadius / 2; - //double barHeight = bFullScreen ? 0 : MediaQueryData.fromWindow(window).padding.top; return Scaffold( appBar: bFullScreen ? null @@ -168,13 +152,9 @@ class _SuperPlayerPageState extends State with SuperPlayerListe 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, @@ -185,12 +165,6 @@ class _SuperPlayerPageState extends State with SuperPlayerListe ], ), ), - // decoration: BoxDecoration( - // gradient: LinearGradient(colors: [ - // Color(0xFF0018EB), - // Color(0xFF01C1D9), - // ], begin: Alignment.bottomCenter, end: Alignment.topCenter), - // ), ), ), title: Padding( @@ -203,7 +177,7 @@ class _SuperPlayerPageState extends State with SuperPlayerListe iconData: Icons.chevron_left_outlined, onPress: () { getingDwVideo = false; - Navigator.pop(context); + pop(); }, ), Expanded( @@ -220,16 +194,12 @@ class _SuperPlayerPageState extends State with SuperPlayerListe ), 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), @@ -237,11 +207,7 @@ class _SuperPlayerPageState extends State with SuperPlayerListe 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), + _useIJKPlayer ? FijkView(player: _ijkPlayer) : SuperPlayerView(controller: _playerController) ], ), ), @@ -254,7 +220,6 @@ class _SuperPlayerPageState extends State with SuperPlayerListe children: [ SizedBox(width: ScreenUtil().setWidth(btn_left)), getRoundButton( - //(bPlaying) ? '暂停' : '播放', text: playerRegionProvide.playerText, icon: playerRegionProvide.playerIcon, diameter: 130, @@ -407,41 +372,27 @@ class _SuperPlayerPageState extends State with SuperPlayerListe } }, ), - // 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); //关闭弹框,播放输入视频地址 + pop(); }, ), ); } + pop() async { + Playing = false; + getingDwVideo = false; + _ijkPlayer.removeListener(() {}); + await _playerController.removeListener(this); + Navigator.pop(context); + } + @override void onClickFloatCloseBtn() { _addLog('onClickFloatCloseBtn', {}); @@ -450,7 +401,7 @@ class _SuperPlayerPageState extends State with SuperPlayerListe @override void onClickSmallReturnBtn() { _addLog('onClickSmallReturnBtn', {}); - Navigator.maybePop(context); + pop(); } @override @@ -496,6 +447,12 @@ class _SuperPlayerPageState extends State with SuperPlayerListe _addLog('onStartFloatWindowPlay', {}); } + void _fijkValueListener() { + FijkValue value = _ijkPlayer.value; + onPlayStateChange(value.state == FijkState.started ? 1 : 2); + onFullScreenChange(value.fullScreen); +} + //生成圆形按钮部件,基于图标 Widget getRoundButton( {double diameter = 144, @@ -554,13 +511,7 @@ class _SuperPlayerPageState extends State with SuperPlayerListe 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)), @@ -576,44 +527,37 @@ class _SuperPlayerPageState extends State with SuperPlayerListe bool bPlaying = true; - void playOrPause() { + Future playOrPause() async { //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(() {}); - }); + 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; - _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); + if (_useIJKPlayer) { + await _ijkPlayer.reset(); + _ijkPlayer.setDataSource(widget.url, autoPlay: true); + } else { + _playerController.resetPlayer(); + _playerController.resume(); + } } //生成播放控制区第2行按钮List @@ -624,24 +568,6 @@ class _SuperPlayerPageState extends State with SuperPlayerListe 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, @@ -650,8 +576,6 @@ class _SuperPlayerPageState extends State with SuperPlayerListe text: '放大', icon: Icons.zoom_in, onPress: () { - //print('Icons.videocam'); - //_inputDialog(context2); if (10 >= playerRatioProvide.scale) { playerRatioProvide.changeScale(playerRatioProvide.scale + 0.5); } @@ -665,27 +589,11 @@ class _SuperPlayerPageState extends State with SuperPlayerListe 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, @@ -694,9 +602,6 @@ class _SuperPlayerPageState extends State with SuperPlayerListe text: '截图', icon: Icons.camera_alt, onPress: () { - //通过上面定义的key,才能准确调用该类型的该对象的方法 - //_myFijkPanelWidgetBuilderStateKey.currentState.takeSnapshot(); - //_fijkPanelWidgetBuilder.currentState..takeSnapshot(); takeSnapshot(); }, ), @@ -708,8 +613,7 @@ class _SuperPlayerPageState extends State with SuperPlayerListe text: '全屏', icon: Icons.fullscreen, onPress: () { - //player.enterFullScreen(); - _playerController.toFullScreen(); + _useIJKPlayer ? _ijkPlayer.enterFullScreen() : _playerController.toFullScreen(); }, ), ]; diff --git a/pubspec.lock b/pubspec.lock index 81e725c..cdc996e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -211,6 +211,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 f58d7df..f87f2c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -79,7 +79,7 @@ dependencies: cupertino_icons: ^1.0.0 # hyzp_ybqx00_yibin Project Adds - # fijkplayer: ^0.8.7 + fijkplayer: ^0.8.7 path_provider: ^1.6.14 #permission_handler: ^3.3.0 permission_handler: ^5.0.1+1