chudongvip / awesome_video_player

This is a flutter package of video player. it's a very simple and easy to use.
MIT License
195 stars 36 forks source link

视频可以在浏览器上播放,但是在flutter app 上不可以 #36

Closed markchao closed 4 years ago

markchao commented 4 years ago

视频可以在浏览器上播放,但是在flutter app 上不可以 报错如下 flutter: 日志拦截: http://192.168.100.8:8081/file?p=/video/2020/05/IMG_3761.mp4 [VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter/src/foundation/stack_frame.dart': Failed assertion: line 113 pos 12: 'match != null': Expected to match RegExp: pattern=^(.+) (\d+):(\d+)\s+(.+)$ flags=.

0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:42:39)

1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:38:5)

2 StackFrame._parseWebDebugFrame (package:flutter/src/foundation/stack_frame.dart:113:12)

3 StackFrame._parseWebFrame (package:flutter/src/foundation/stack_frame.dart:99:14)

4 StackFrame.fromStackTraceLine (package:flutter/src/foundation/stack_frame.dart:193:14)

5 MappedListIterable.elementAt (dart:_internal/iterable.dart:417:31)

6 ListIterator.moveNext (dart:_internal/iterable.dart:346:26)

7 SkipWhileIterator.moveNext (dart:_internal/iterable.dart:669:24)

8 new List.from (dart:core-patch/array_patch.dart:47:19)

9 Iterable.toList (dart:core/iterable.dart:400:12)

10 StackFrame.fromStackString (package:flutter/src/foundation/stack_frame.dart:94:10)

11 FlutterError.defaultStackFilter (package:flutter/src/foundation/assertions.dart:820:54)

12 new DiagnosticsStackTrace (package:flutter/src/foundation/assertions.dart:958:59)

13 FlutterErrorDetails.debugFillProperties (package:flutter/src/foundation/assertions.dart:575:22)

14 DiagnosticableNode.builder. (package:flutter/src/foundation/diagnostics.dart:2926:18)

15 DiagnosticableNode.builder (package:flutter/src/foundation/diagnostics.dart:2929:8)

16 _FlutterErrorDetailsNode.builder (package:flutter/src/foundation/assertions.dart:996:55)

17 DiagnosticableNode.getProperties (package:flutter/src/foundation/diagnostics.dart:2943:105)

18 TextTreeRenderer._debugRender (package:flutter/src/foundation/diagnostics.dart:1238:63)

19 TextTreeRenderer.render (package:flutter/src/foundation/diagnostics.dart:1116:14)

20 DiagnosticsNode.toStringDeep. (package:flutter/src/foundation/diagnostics.dart:1730:9)

21 DiagnosticsNode.toStringDeep (package:flutter/src/foundation/diagnostics.dart:1737:6)

22 FlutterErrorDetails.toString (package:flutter/src/foundation/assertions.dart:590:65)

23 _StringBase._interpolateSingle (dart:core-patch/string_patch.dart:823:17)

24 print (dart:core/print.dart:11:26)

25 AppInit.reportErrorAndLog (package:iCloud/init/app_init.dart:44:5)

26 AppInit.catchException. (package:iCloud/init/app_init.dart:32:9)

27 _rootRunBinary (dart:async/zone.dart:1208:13)

28 _CustomZone.runBinary (dart:async/zone.dart:1093:19)

29 runZonedGuarded. (dart:async/zone.dart:1591:19)

30 _CustomZone.handleUncaughtError (dart:async/zone.dart:1059:19)

31 Future._propagateToListeners (dart:async/future_impl.dart:598:16)

32 Future._completeError (dart:async/future_impl.dart:534:5)

33 Future._asyncCompleteError. (dart:async/future_impl.dart:582:7)

34 _rootRun (dart:async/zone.dart:1184:13)

35 _CustomZone.run (dart:async/zone.dart:1077:19)

36 _CustomZone.runGuarded (dart:async/zone.dart:979:7)

37 _CustomZone.bindCallbackGuarded. (dart:async/zone.dart:1019:23)

38 _microtaskLoop (dart:async/schedule_microtask.dart:43:21)

39 _startMicrotaskLoop (dart:async/schedule_microtask.dart:52:5)

代码如下:

import 'package:flutter/material.dart'; import 'package:awsome_video_player/awsome_video_player.dart'; import 'package:iCloud/page/fintness_app_theme.dart';

class VideoPlayPage extends StatefulWidget { const VideoPlayPage( {Key key, this.url,this.name,this.index}) : super(key: key); final String url; final String name; final int index;

@override _VideoPlayPageState createState() => new _VideoPlayPageState(this.url,this.name,this.index); }

class _VideoPlayPageState extends State { _VideoPlayPageState(this.url,this.name,this.index);

final String url; final String name; final int index;

String mainSubtitles = ""; //主字幕 String subSubtitles = ""; //辅字幕 bool _isPlaying = false; bool _isFullscreen = false;

bool showAdvertCover = false; //是否显示广告

bool get isPlaying => _isPlaying; set isPlaying(bool playing) { print("playing $playing"); _isPlaying = playing; }

@override void initState() { super.initState(); }

@override Widget build(BuildContext context) { print(url); return MaterialApp( home: Container( color: FintnessAppTheme.background, child: Scaffold( backgroundColor: Colors.transparent, appBar: !_isFullscreen ? AppBar( leading: IconButton(icon: new Icon(Icons.chevron_left)), backgroundColor: FintnessAppTheme.background, automaticallyImplyLeading: true, title: Text(name,style: TextStyle( color: Colors.black38 ),),

          ): null,
          body: Column(children: <Widget>[
            url != ""
                ? AwsomeVideoPlayer(
              "http://192.168.100.8:8081/file?p=/video/2020/05/IMG_3761.mp4",
              /// 视频播放配置
              playOptions: VideoPlayOptions(
                  seekSeconds: 30,
                  //左侧垂直手势调节视频亮度的单位(0~1之间,不能小于0,不能大于1)
                  brightnessGestureUnit: 0.05,
                  //右侧垂直手势调节视频音量的单位(0~1之间,不能小于0,不能大于1)
                  volumeGestureUnit: 0.05,
                  //横行手势调节视频进度的单位秒数
                  progressGestureUnit: 2000,
                  aspectRatio: 16 / 9,
                  loop: false,
                  autoplay: true,
                  allowScrubbing: true,
                  startPosition: Duration(seconds: 0)),

              /// 自定义视频样式
              videoStyle: VideoStyle(
                /// 自定义视频暂停时视频中部的播放按钮
                playIcon: Icon(
                  Icons.play_circle_outline,
                  size: 80,
                  color: Colors.white,
                ),

                /// 暂停时是否显示视频中部播放按钮
                showPlayIcon: true,

                videoLoadingStyle: VideoLoadingStyle(
                  /// 重写部分(二选一)
                  // 重写Loading的widget
                  // customLoadingIcon: CircularProgressIndicator(strokeWidth: 2.0),
                  // 重写Loading 下方的Text widget
                  // customLoadingText: Text("加载中..."),
                  /// 设置部分(二选一)
                  // 设置Loading icon 下方的文字
                  loadingText: "Loading...",
                  // 设置loading icon 下方的文字颜色
                  loadingTextFontColor: Colors.white,
                  // 设置loading icon 下方的文字大小
                  loadingTextFontSize: 20,
                ),

                /// 自定义顶部控制栏
                videoTopBarStyle: VideoTopBarStyle(
                  show: true, //是否显示
                  height: 40,
                  padding:
                  EdgeInsets.symmetric(vertical: 8, horizontal: 10),
                  barBackgroundColor: Color.fromRGBO(0, 0, 0, 0.5),
                  popIcon: Icon(
                    Icons.arrow_back,
                    size: 16,
                    color: Colors.white,
                  ),

// contents: [ // Center( // child: Container( // margin: EdgeInsets.symmetric(horizontal: 10), // child: Text( // '返回', // style: TextStyle( // color: Colors.white, fontSize: 14), // ), // ), // ) // ], //自定义顶部控制栏中间显示区域 // actions: [ // GestureDetector( // onTap: () { // ///1. 可配合自定义拓展元素使用,例如广告 // setState(() { // showAdvertCover = true; // }); // // /// // }, // child: Icon( // Icons.more_horiz, // size: 16, // color: Colors.white, // ), // ) // ], //自定义顶部控制栏右侧显示区域 /// 设置cusotmBar之后,以上属性均无效(除了show之外) // customBar: Positioned( // top: 0, // left: 0, // right: 0, // child: Container( // width: double.infinity, // height: 50, // color: Colors.yellow, // child: Text("12312312"), // ), // ), // customBar: Align( // alignment: Alignment.topLeft, // child: Container( // width: double.infinity, // height: 30, // color: Colors.yellow, // child: GestureDetector( // onTap: () { // print("yes"); // }, // child: Text("123123132") // ) // ), // ), ),

                /// 自定义底部控制栏
                videoControlBarStyle: VideoControlBarStyle(
                  /// 自定义颜色
                  // barBackgroundColor: Colors.blue,

                  ///添加边距
                  padding:
                  EdgeInsets.symmetric(vertical: 8, horizontal: 10),

                  ///设置控制拦的高度,默认为30,如果图标设置过大但是高度不够就会出现图标被裁剪的现象
                  height: 30,

                  /// 自定义进度条样式
                  // progressStyle: VideoProgressStyle(
                  //     // padding: EdgeInsets.all(0),
                  //     padding: EdgeInsets.symmetric(
                  //         vertical: 0,
                  //         horizontal: 10), //vertical不能设置太大,不然被把进度条压缩肉眼无法识别
                  //     playedColor: Colors.red,
                  //     bufferedColor: Colors.yellow,
                  //     backgroundColor: Colors.green,
                  //     dragBarColor: Colors
                  //         .white, //进度条为`progress`时有效,如果时`basic-progress`则无效
                  //     height: 4,
                  //     progressRadius:
                  //         2, //进度条为`progress`时有效,如果时`basic-progress`则无效
                  //     dragHeight:
                  //         5 //进度条为`progress`时有效,如果时`basic-progress`则无效
                  //     ),

                  /// 更改进度栏的播放按钮
                  playIcon: Icon(Icons.play_arrow,
                      color: Colors.white, size: 16),

                  /// 更改进度栏的暂停按钮
                  pauseIcon: Icon(
                    Icons.pause,
                    color: Colors.white,
                    size: 16,
                  ),

                  /// 更改进度栏的快退按钮
                  rewindIcon: Icon(
                    Icons.replay_30,
                    size: 16,
                    color: Colors.white,
                  ),

                  /// 更改进度栏的快进按钮
                  forwardIcon: Icon(
                    Icons.forward_30,
                    size: 16,
                    color: Colors.white,
                  ),

                  /// 更改进度栏的全屏按钮
                  fullscreenIcon: Icon(
                    Icons.fullscreen,
                    size: 20,
                    color: Colors.white,
                  ),

                  /// 更改进度栏的退出全屏按钮
                  fullscreenExitIcon: Icon(
                    Icons.fullscreen_exit,
                    size: 20,
                    color: Colors.red,
                  ),

                  /// 决定控制栏的元素以及排序,示例见上方图3
                  itemList: [
                    "rewind",
                    "play",
                    "forward",
                    "position-time", //当前播放时间
                    "progress", //线条形进度条(与‘basic-progress’二选一)
                    // "basic-progress",//矩形进度条(与‘progress’二选一)
                    "duration-time", //视频总时长
                    // "time",//格式:当前时间/视频总时长
                    "fullscreen"
                  ],
                ),

                /// 自定义字幕
                videoSubtitlesStyle: VideoSubtitles(
                  mianTitle: Align(
                    alignment: Alignment.bottomCenter,
                    child: Container(
                      padding: EdgeInsets.fromLTRB(10, 0, 10, 30),
                      child: Text(mainSubtitles,
                          maxLines: 2,
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.white, fontSize: 14)),
                    ),
                  ),
                  subTitle: Align(
                    alignment: Alignment.bottomCenter,
                    child: Container(
                      padding: EdgeInsets.all(10),
                      child: Text(subSubtitles,
                          maxLines: 2,
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.white, fontSize: 14)),
                    ),
                  ),
                ),
              ),

              /// 自定义拓展元素
              children: [
                /// DEMO1 自定义视频播放状态Toast
                /// 待完善

                /// DEMO2 这个将会覆盖的视频内容,因为这个层级是最高级,因此手势会失效(慎用)
                /// 这个可以用来做视频广告
                showAdvertCover
                    ? Align(
                  alignment: Alignment.center,
                  child: Container(
                    width: 200,
                    height: 100,
                    color: Colors.blue[500],
                    child: Stack(
                      fit: StackFit.expand,
                      children: <Widget>[
                        //关闭广告
                        Align(
                          alignment: Alignment.topRight,
                          child: GestureDetector(
                            onTap: () {
                              setState(() {
                                showAdvertCover = false;
                              });
                            },
                            child: Icon(
                              Icons.cancel,
                              size: 16,
                              color: Colors.white,
                            ),
                          ),
                        ),
                        Container(
                          alignment: Alignment.center,
                          child: Text(
                            "一个广告封面",
                            style: TextStyle(color: Colors.white),
                          ),
                        )
                      ],
                    ),
                  ),
                )
                    : Align(),
              ],

              /// 视频暂停回调
              onpause: (value) {
                print("video paused");
                setState(() {
                  isPlaying = false;
                });
              },

              /// 视频播放回调
              onplay: (value) {
                print("video played");
                setState(() {
                  isPlaying = true;
                });
              },

              /// 视频播放结束回调
              onended: (value) {
                print("video ended");
              },

              /// 视频播放进度回调
              /// 可以用来匹配字幕
              ontimeupdate: (value) {
                // print("timeupdate ${value}");
                // var position = value.position.inMilliseconds / 1000;
                //根据 position 来判断当前显示的字幕
              },

              onprogressdrag: (position, duration) {
                print("进度条拖拽的时间节点: ${position}");
                print("进度条总时长: ${duration}");
              },

              onvolume: (value) {
                print("onvolume ${value}");
              },

              onbrightness: (value) {
                print("onbrightness ${value}");
              },

              onfullscreen: (fullscreen) {
                print("is fullscreen $fullscreen");
                setState(() {
                  _isFullscreen = fullscreen;
                });
              },

              /// 顶部控制栏点击返回按钮
              onpop: (value) {
                print("返回上一页");
                Navigator.of(context).pop(0);
              },
            )
                : AspectRatio(
              aspectRatio: 16 / 9,
              child: Center(
                child: CircularProgressIndicator(strokeWidth: 2.0),
              ),
            ),
          ])),
    ));

} }

markchao commented 4 years ago

知道为什么了,是因为我服务器的输出有问题