我想实时获取正在播放的视频的当前位置。我正在考虑使用监听器,但如果我这样做:
_controller.addListener(() => print(_controller.value.position.inMilliseconds))
它仅每 500 毫秒打印一次值。这太慢了,视频每 33 毫秒更新一次,甚至更频繁。任何人都知道为什么会发生这种情况以及实现我想要的目标的正确方法是什么?
附注我能够通过在视频开始时启动动画控制器来实现我想要的目标,但这看起来像是一个黑客。
延迟的原因是
VideoPlayerController
每 500 毫秒通知听众一次。您可以使用 Timer
定期获取视频播放器的位置。这是执行此操作的示例代码
class VideoPlayerScreen extends StatefulWidget {
@override
VideoPlayerState createState() => VideoPlayerState();
}
class VideoPlayerState extends State<VideoPlayerScreen> {
Timer _timer;
VideoPlayerController videoPlayerController;
void startTimer() {
_timer = Timer.periodic(const Duration(milliseconds: 100), (Timer timer) async {
print(await videoPlayerController.position);
});
}
@override
void dispose() {
_timer?.cancel();
videoPlayerController?.dispose();
super.dispose();
}
}
问题在于
VideoPlayerController
本身,当它在很长的时间间隔(约 500 毫秒)内更新其位置时。显然,VideoPlayerController
不支持设置监听回调间隔。如果您使用计时器比该间隔更频繁地检索位置,您将获得相同的位置值,直到间隔结束。
如果玩家正在玩,其时间位置是完全可以预测的。如果您的目的是在玩家玩游戏时获取位置(例如更新滑动条或搜索栏),则可以使用秒表和计时器来估计当前位置。这个想法是测量当前位置检索与先前调用之间的时间差,并将该差值添加到您的估计位置中。位置将由真实玩家回调修正(每 500 毫秒)。
以下是演示片段:
/// A wrapper for VideoPlayerController
class VideoPlayer {
final String _mediaPath;
final VideoPlayerController _controller;
bool _isPlaying = false;
// for triggering callback periodically
Timer? _positionUpdateTimer;
// the callback interval of position update
Duration _positionUpdateInterval = const Duration(milliseconds: 0);
Function(Duration)? _positionChangeCallback;
Duration _estimatedPosition = Duration.zero;
final Stopwatch _positionEstimationStopwatch = Stopwatch();
VideoPlayer(this._mediaPath)
: _controller = VideoPlayerController.file(File(_mediaPath));
Future<void> initialize() async {
await _controller.initialize();
}
void dispose() => _controller.dispose();
void play() {
_controller.play();
_isPlaying = true;
// start the position update timer
if (_positionUpdateInterval > Duration.zero) {
_positionEstimationStopwatch.start();
_positionUpdateTimer = Timer.periodic(_positionUpdateInterval, (timer) {
// update the estimated position
_estimatedPosition += _positionEstimationStopwatch.elapsed;
_positionEstimationStopwatch.reset();
_positionChangeCallback?.call(_estimatedPosition);
});
}
}
void pause() {
_controller.pause();
_isPlaying = false;
// stop the position update timer
_positionUpdateTimer?.cancel();
_positionEstimationStopwatch.stop();
}
void setPositionChangeCallback(Function(Duration) callback) {
_controller.addListener(() {
// trigger the callback if the internal position change callback is not
// triggered by the timer
if (!(_isPlaying && _positionUpdateInterval > Duration.zero)) {
callback(_controller.value.position);
} else {
// correct the estimated position with the actual player position
_estimatedPosition = _controller.value.position;
_positionEstimationStopwatch.reset();
}
});
_positionChangeCallback = callback;
}
/// Set the position update interval to trigger the timer position estimation
void setPositionUpdateInterval(Duration interval) {
_positionUpdateInterval = interval;
}
}
在此演示中,仅在玩家玩游戏时才会使用估计位置的位置变化回调。如果您希望计时器位置更新始终运行,您可以删除
_isPlaying
检查并让秒表始终运行。