Flutter Video_player:增强位置精度

发布于 2025-01-20 14:48:55 字数 4542 浏览 6 评论 0原文

我目前正在使用 video_player 来精确分析视频。 不幸的是,我似乎无法提高 VideoPlayer 实例的不同“位置”获取器的精度。顶部每次刷新之间的间隔为 500ms。它对应于进度指示器的更新。 500 毫秒来检索体育数据(例如短跑)太大了。

可以实时更新吗?越精确越好,比如流什么的。

下面是代码,从他们的示例来看非常简单,我使用内置 Stream,它仅在完成时发送事件,并且位置获取器与其他刷新器相同(500ms)

class AssistantHome extends StatefulWidget {
  final UserTest test;
  final Player player;
  const AssistantHome({Key key, @required this.test, @required this.player})
      : super(key: key);

  @override
  State<AssistantHome> createState() => _AssistantHomeState();
}

class _AssistantHomeState extends State<AssistantHome> {
  VideoPlayerController _controller;
  int _positionInMs;
  Stream<Duration> durationStream;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(widget.test.videoUrl);
    durationStream = _controller.position.asStream();
    _controller.addListener(() {
      setState(() {
        _positionInMs = _controller.value.position.inMilliseconds;
      });
    });
    _controller.setLooping(true);
    _controller.initialize().then((_) => setState(() {}));
    _controller.play();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverFillRemaining(
            hasScrollBody: false,
            child: Column(
              children: <Widget>[
                Text('${widget.test.uid}'),
                Container(
                  height: 600,
                  padding: const EdgeInsets.all(20),
                  child: AspectRatio(
                    aspectRatio: _controller.value.aspectRatio,
                    child: SizedBox(
                      height: 600,
                      child: Stack(
                        alignment: Alignment.bottomCenter,
                        children: <Widget>[
                          VideoPlayer(_controller),
                          _ControlsOverlay(controller: _controller),
                          VideoProgressIndicator(_controller,
                              allowScrubbing: true),
                        ],
                      ),
                    ),
                  ),
                ),
                StreamBuilder(builder: ((context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return CircularProgressIndicator();
                  } else if (snapshot.connectionState ==
                          ConnectionState.active ||
                      snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.hasError) {
                      return const Text('Error');
                    } else if (snapshot.hasData) {
                      return Text(snapshot.data.toString(),
                          style: const TextStyle(
                              color: Colors.teal, fontSize: 36));
                    } else {
                      return const Text('Empty data');
                    }
                  } else {
                    return Text(
                        'Duration: ${_controller.value.position.inMicroseconds} us');
                  }
                })),
                Text("Current position: $_positionInMs ms"),
                const Text('Footer'),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _ControlsOverlay extends StatelessWidget {
  const _ControlsOverlay({Key key, @required this.controller})
      : super(key: key);

  final VideoPlayerController controller;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 50),
          reverseDuration: const Duration(milliseconds: 200),
          child: controller.value.isPlaying
              ? const SizedBox.shrink()
              : Container(
                  color: Colors.black26,
                  child: const Center(
                    child: Icon(
                      Icons.play_arrow,
                      color: Colors.white,
                      size: 100.0,
                      semanticLabel: 'Play',
                    ),
                  ),
                ),
        ),
        GestureDetector(
          onTap: () {
            controller.value.isPlaying ? controller.pause() : controller.play();
          },
        ),
      ],
    );
  }
}

I'm currently using the video_player to analyse the videos with precision.
Unfortunately, I can't seem to be able to enhance the precision of the different "position" getter of the VideoPlayer instance. The top is 500ms interval between each refresh. It corresponds to the update of the progress indicator. 500ms to retrieve sports data such s a sprint is way too big.

Would it be possible to have a real time update ? The more precise the better, such as a stream or something.

Below is the code, super simple from their example, I'm using the builtin Stream which only sends an event when completed, and the position getter is the same refresh than the other (500ms)

class AssistantHome extends StatefulWidget {
  final UserTest test;
  final Player player;
  const AssistantHome({Key key, @required this.test, @required this.player})
      : super(key: key);

  @override
  State<AssistantHome> createState() => _AssistantHomeState();
}

class _AssistantHomeState extends State<AssistantHome> {
  VideoPlayerController _controller;
  int _positionInMs;
  Stream<Duration> durationStream;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(widget.test.videoUrl);
    durationStream = _controller.position.asStream();
    _controller.addListener(() {
      setState(() {
        _positionInMs = _controller.value.position.inMilliseconds;
      });
    });
    _controller.setLooping(true);
    _controller.initialize().then((_) => setState(() {}));
    _controller.play();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverFillRemaining(
            hasScrollBody: false,
            child: Column(
              children: <Widget>[
                Text('${widget.test.uid}'),
                Container(
                  height: 600,
                  padding: const EdgeInsets.all(20),
                  child: AspectRatio(
                    aspectRatio: _controller.value.aspectRatio,
                    child: SizedBox(
                      height: 600,
                      child: Stack(
                        alignment: Alignment.bottomCenter,
                        children: <Widget>[
                          VideoPlayer(_controller),
                          _ControlsOverlay(controller: _controller),
                          VideoProgressIndicator(_controller,
                              allowScrubbing: true),
                        ],
                      ),
                    ),
                  ),
                ),
                StreamBuilder(builder: ((context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return CircularProgressIndicator();
                  } else if (snapshot.connectionState ==
                          ConnectionState.active ||
                      snapshot.connectionState == ConnectionState.done) {
                    if (snapshot.hasError) {
                      return const Text('Error');
                    } else if (snapshot.hasData) {
                      return Text(snapshot.data.toString(),
                          style: const TextStyle(
                              color: Colors.teal, fontSize: 36));
                    } else {
                      return const Text('Empty data');
                    }
                  } else {
                    return Text(
                        'Duration: ${_controller.value.position.inMicroseconds} us');
                  }
                })),
                Text("Current position: $_positionInMs ms"),
                const Text('Footer'),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _ControlsOverlay extends StatelessWidget {
  const _ControlsOverlay({Key key, @required this.controller})
      : super(key: key);

  final VideoPlayerController controller;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 50),
          reverseDuration: const Duration(milliseconds: 200),
          child: controller.value.isPlaying
              ? const SizedBox.shrink()
              : Container(
                  color: Colors.black26,
                  child: const Center(
                    child: Icon(
                      Icons.play_arrow,
                      color: Colors.white,
                      size: 100.0,
                      semanticLabel: 'Play',
                    ),
                  ),
                ),
        ),
        GestureDetector(
          onTap: () {
            controller.value.isPlaying ? controller.pause() : controller.play();
          },
        ),
      ],
    );
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷爱 2025-01-27 14:48:55

尝试使用 smooth_video_progress 包:https://pub.dev/packages/smooth_video_progress!

来自 https://pub.dev/packages/smooth_video_progress#usage

例如,以下是构建简单滑块的方法:

Widget build(BuildContext context) {
  SmoothVideoProgress(
    controller: controller,
    builder: (context, position, duration, child) => Slider(
      onChangeStart: (_) => controller.pause(),
      onChangeEnd: (_) => controller.play(),
      onChanged: (value) =>
          controller.seekTo(Duration(milliseconds: value.toInt())),
      value: position.inMilliseconds.toDouble(),
      min: 0,
      max: duration.inMilliseconds.toDouble(),
    ),
  );
}

Try using the smooth_video_progress package: https://pub.dev/packages/smooth_video_progress!

From https://pub.dev/packages/smooth_video_progress#usage:

Here is how you would build a simple slider for example:

Widget build(BuildContext context) {
  SmoothVideoProgress(
    controller: controller,
    builder: (context, position, duration, child) => Slider(
      onChangeStart: (_) => controller.pause(),
      onChangeEnd: (_) => controller.play(),
      onChanged: (value) =>
          controller.seekTo(Duration(milliseconds: value.toInt())),
      value: position.inMilliseconds.toDouble(),
      min: 0,
      max: duration.inMilliseconds.toDouble(),
    ),
  );
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文