Flutter 视频播放器 - 使用新的 VideoPlayerController 重建后无法设置播放速度

问题描述 投票:0回答:1

我的视频播放器有问题。无法设置播放速度。 步骤:

  • 使用 VideoPlayerController 创建播放器
  • 将播放速度更改为2.0。
  • 重新创建一个新的
    VideoPlayerController
    ,并将播放速度设置为旧的播放速度(2.0)。
  • 重新构建播放器 -> 播放速度重置为 1.0。 更多细节请参考我的代码示例。 谢谢!
代码示例
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

/// An example of using the plugin, controlling lifecycle and playback of the
/// video.

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

void main() {
  runApp(
    MaterialApp(
      home: _App(),
    ),
  );
}

class _App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: const ValueKey<String>('home_page'),
      appBar: AppBar(
        title: const Text('Video player example'),
      ),
      body: _BumbleBeeRemoteVideo(),
    );
  }
}

class _BumbleBeeRemoteVideo extends StatefulWidget {
  @override
  _BumbleBeeRemoteVideoState createState() => _BumbleBeeRemoteVideoState();
}

class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
  late VideoPlayerController _controller;
  M3u8 _currentM3u8 = _ControlsOverlay._exampleM3u8s.first;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
      'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8',
      formatHint: VideoFormat.hls,
    );

    _controller.addListener(() {
      setState(() {});
    });
    _controller.setLooping(true);
    _controller.initialize();
  }

  _resetControllerWithM3u8(M3u8 m3u8) {
    final speed = _controller.value.playbackSpeed;
    final position = _controller.value.position;
    _controller.pause();
    _controller = VideoPlayerController.network(
      m3u8.url,
      formatHint: VideoFormat.hls,
    );

    _controller.addListener(() {
      setState(() {});
    });

   // THE PLAYBACK SPEED IS NOT CHANGED.
    _controller.setPlaybackSpeed(speed);
    _controller.setLooping(true);
    _controller.initialize().then((_) {
      _controller.play();
      _controller.seekTo(position);
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          Container(padding: const EdgeInsets.only(top: 20.0)),
          const Text('With remote m3u8'),
          Container(
            padding: const EdgeInsets.all(20),
            child: AspectRatio(
              aspectRatio: _controller.value.aspectRatio,
              child: Stack(
                alignment: Alignment.bottomCenter,
                children: <Widget>[
                  VideoPlayer(_controller),
                  ClosedCaption(text: _controller.value.caption.text),
                  _ControlsOverlay(
                    controller: _controller,
                    onChangeQuality: (m3u8) {
                      _currentM3u8 = m3u8;
                      _resetControllerWithM3u8(m3u8);
                    },
                    currentM3u8: _currentM3u8,
                  ),
                  VideoProgressIndicator(_controller, allowScrubbing: true),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

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

  static const List<Duration> _exampleCaptionOffsets = <Duration>[
    Duration(seconds: -10),
    Duration(seconds: -3),
    Duration(seconds: -1, milliseconds: -500),
    Duration(milliseconds: -250),
    Duration(milliseconds: 0),
    Duration(milliseconds: 250),
    Duration(seconds: 1, milliseconds: 500),
    Duration(seconds: 3),
    Duration(seconds: 10),
  ];
  static const List<double> _examplePlaybackRates = <double>[
    0.25,
    0.5,
    1.0,
    1.5,
    2.0,
    3.0,
    5.0,
    10.0,
  ];

  static const List<M3u8> _exampleM3u8s = [
    M3u8('Auto',
        'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/master.m3u8'),
    M3u8('640x360',
        'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/index_0_av.m3u8'),
    M3u8('960x540',
        'https://multiplatform-f.akamaihd.net/i/multi/will/bunny/big_buck_bunny_,640x360_400,640x360_700,640x360_1000,950x540_1500,.f4v.csmil/index_3_av.m3u8'),
  ];

  final VideoPlayerController controller;
  final Function(M3u8) onChangeQuality;
  final M3u8 currentM3u8;
  @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();
          },
        ),
        Align(
          alignment: Alignment.topLeft,
          child: PopupMenuButton<Duration>(
            initialValue: controller.value.captionOffset,
            tooltip: 'Caption Offset',
            onSelected: (Duration delay) {
              controller.setCaptionOffset(delay);
            },
            itemBuilder: (BuildContext context) {
              return <PopupMenuItem<Duration>>[
                for (final Duration offsetDuration
                    in _ControlsOverlay._exampleCaptionOffsets)
                  PopupMenuItem<Duration>(
                    value: offsetDuration,
                    child: Text('${offsetDuration.inMilliseconds}ms'),
                  )
              ];
            },
            child: Padding(
              padding: const EdgeInsets.symmetric(
                vertical: 12,
                horizontal: 16,
              ),
              child: Text('${controller.value.captionOffset.inMilliseconds}ms'),
            ),
          ),
        ),
        Align(
          alignment: Alignment.topRight,
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.end,
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              PopupMenuButton<M3u8>(
                initialValue: currentM3u8,
                tooltip: 'Video Quality',
                onSelected: (m3u8) {
                  onChangeQuality(m3u8);
                },
                itemBuilder: (BuildContext context) {
                  return <PopupMenuItem<M3u8>>[
                    for (final m3u8 in _ControlsOverlay._exampleM3u8s)
                      PopupMenuItem<M3u8>(
                        value: m3u8,
                        child: Text(m3u8.quality),
                      )
                  ];
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    vertical: 12,
                    horizontal: 16,
                  ),
                  child: Text(currentM3u8.quality),
                ),
              ),
              PopupMenuButton<double>(
                initialValue: controller.value.playbackSpeed,
                tooltip: 'Playback speed',
                onSelected: (double speed) {
                  controller.setPlaybackSpeed(speed);
                },
                itemBuilder: (BuildContext context) {
                  return <PopupMenuItem<double>>[
                    for (final double speed
                        in _ControlsOverlay._examplePlaybackRates)
                      PopupMenuItem<double>(
                        value: speed,
                        child: Text('${speed}x'),
                      )
                  ];
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    vertical: 12,
                    horizontal: 16,
                  ),
                  child: Text('${controller.value.playbackSpeed}x'),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

class M3u8 {
  final String quality;
  final String url;

  const M3u8(this.quality, this.url);
}

flutter doctor:

[✓] Flutter (Channel stable, 2.10.3, on macOS 12.3 21E230 darwin-arm, locale en-VN)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.1)
[✓] VS Code (version 1.65.2)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

• No issues found!

我在模拟器 iPhone 13 iOS 15.2 上运行该应用程序。 要重现该问题,请运行代码示例 -> 将播放速度更改为 2.0 -> 更改视频质量 -> 将播放速度重置为 1.0。

flutter video-player
1个回答
0
投票

我遇到了同样的问题,我用

addListener
解决了这个问题。

请参阅此示例代码:

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

class MyVideoPlayer extends StatefulWidget {
  final VideoPlayerController controller;
  final double initVideoSpeed;

  const MyVideoPlayer({
    super.key,
    required this.controller,
    this.initVideoSpeed = 1.0,
  });

  @override
  State<MyVideoPlayer> createState() => _MyVideoPlayerState();
}

class _MyVideoPlayerState extends State<MyVideoPlayer> {

  _initializeSpeed() {
    Future.delayed(Duration.zero, () {
      widget.controller.removeListener(_initializeSpeed);
      widget.controller.setPlaybackSpeed(widget.initVideoSpeed);
    });
  }

  @override
  void initState() {
    widget.controller.addListener(_initializeSpeed);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return VideoPlayer(widget.controller);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.