123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- import 'dart:async';
- import 'dart:math' as math;
- import 'package:fis_common/logger/logger.dart';
- import 'package:fis_vid/data_channel/channel.dart';
- /// Vid缓冲等待
- class VidBufferWaiter {
- VidBufferWaiter(
- this.channel, {
- this.timeout = 10 * 1000,
- });
- // ignore: constant_identifier_names
- static const _FIRST_FRAME_LOAD_TIME_LIMIT = 60 * 1000; // 一分钟
- /// 数据通道
- final VidDataChannel channel;
- /// 等待超时时间,默认10秒
- final int timeout;
- double _frameRate = 0;
- int _frameCount = 0;
- int _framePerSize = 0;
- int _vidHeadSize = 0;
- int _maxDuration = 0;
- Timer? _timer;
- /// vid头信息尺寸(含扩展)
- int get vidHeaderSize => _vidHeadSize;
- /// 初始化
- void init() {
- _frameRate = channel.probe.frameRate;
- _frameCount = channel.imageCount;
- _vidHeadSize = _calcHeaderSize();
- _framePerSize = _calcFramePerSize();
- }
- /// 等待首帧
- Future<void> waitSingleVid() async {
- logger.i("VidPlayer - Wait single vid start.");
- final completer = Completer();
- const int waitInterval = 100;
- const int waitCountLimit = _FIRST_FRAME_LOAD_TIME_LIMIT ~/ waitInterval;
- int waitCount = 0;
- _timer = Timer.periodic(
- const Duration(milliseconds: waitInterval),
- (timer) {
- waitCount++;
- if (channel.isBufferedDone) {
- // 全部缓冲完成
- timer.cancel();
- completer.complete();
- logger.i("VidPlayer - Wait single vid end.");
- return;
- }
- if (waitCount >= waitCountLimit) {
- completer.completeError(Exception("First frame load timeout"));
- logger.i("VidPlayer - Wait single vid: timeout.");
- }
- },
- );
- return completer.future;
- }
- /// 等待缓冲
- Future<void> waitBuffer(int frameIndex) {
- logger.i("VidPlayer - Wait buffer start.");
- final completer = Completer();
- final bufferredSize = channel.getBufferSize();
- final needBufferSize = _calcNeedWaitSize(frameIndex);
- const int waitInterval = 100;
- final int waitCountLimit = timeout ~/ waitInterval;
- int waitCount = 0;
- final startTime = DateTime.now();
- _timer = Timer.periodic(
- const Duration(milliseconds: waitInterval),
- (timer) {
- // 函数 - 完成等待
- void finishFn() {
- timer.cancel();
- completer.complete();
- final endTime = DateTime.now();
- final spendTime = endTime.difference(startTime).inMilliseconds;
- logger.i("VidPlayer - Wait buffer end, spend time: $spendTime ms.");
- }
- waitCount++;
- final bufferedSize = channel.getBufferSize();
- if (bufferedSize >= needBufferSize) {
- // 缓存足够
- logger.i("VidPlayer - buffer end since buffered enough");
- logger.i("VidPlayer - BufferedSize: $bufferedSize.");
- logger.i("VidPlayer - NeedBufferedSize: $needBufferSize.");
- return finishFn();
- }
- if (channel.isBufferedDone) {
- // 全部缓冲完成
- var fileTotalSize = channel.getFileSize();
- var fileDownloadedSize = channel.getBufferSize();
- logger.i("VidPlayer - buffer end since all files are downloaded");
- logger.i("VidPlayer - fileTotalSize: $fileTotalSize.");
- logger.i("VidPlayer - filedownloaded: $fileDownloadedSize.");
- return finishFn();
- }
- if (waitCount >= waitCountLimit) {
- //记录上方管理提前终止的逻辑未执行时的内存现场
- var fileTotalSize = channel.getFileSize();
- var fileDownloadedSize = channel.getBufferSize();
- logger.i(
- "VidPlayer - channel.isBufferedDone: ${channel.isBufferedDone}.");
- logger.i("VidPlayer - BufferedSize: $bufferedSize.");
- logger.i("VidPlayer - NeedBufferedSize: $needBufferSize.");
- logger.i("VidPlayer - fileTotalSize: $fileTotalSize.");
- logger.i("VidPlayer - filedownloaded: $fileDownloadedSize.");
- // 等待超时
- final bufferredSizeNow = channel.getBufferSize();
- if (bufferredSizeNow - bufferredSize < 1024) {
- timer.cancel();
- // 缓冲小于1k,报超时
- completer.completeError(Exception("Wait buffer timeout"));
- logger.i("VidPlayer - Wait buffer timeout.");
- } else {
- // 放行
- finishFn();
- }
- }
- },
- );
- return completer.future;
- }
- /// 记录单帧耗时
- void recordFrameSpendTime(int millseconds) {
- _maxDuration = math.max(_maxDuration, millseconds);
- }
- /// 取消等待
- void cancel() {
- _timer?.cancel();
- }
- int _calcNeedWaitSize(int frameIndex) {
- int needWaitSize = 0;
- final int bufferedSize = channel.getBufferSize();
- final int totalSize = channel.getFileSize();
- // 已缓冲帧数
- final int bufferredFrameCount = bufferedSize ~/ _framePerSize;
- // 未缓冲帧数
- final int unbufferredFrameCount = _frameCount - bufferredFrameCount;
- // 未缓冲数据字节数
- final int unbufferredSize = totalSize - bufferedSize;
- // 未缓冲数据字节数 所需耗时
- final int needBufferTime = unbufferredFrameCount * _maxDuration;
- // 未缓冲播放时长
- final int unbufferredDuration =
- ((1000 / _frameRate) * unbufferredFrameCount).toInt();
- // 每秒需要字节数
- final int perSecondNeedSize = (_framePerSize * _frameRate).toInt();
- // 缓存和播放同时结束所需耗时
- int needWaitTime = needBufferTime - unbufferredDuration;
- if (needWaitTime < 0) {
- // 预计缓冲比播放快(可能是网络波动大导致出现加载)
- // 缓存1秒
- needWaitSize = perSecondNeedSize;
- } else {
- needWaitTime += 1; //多缓存一秒
- needWaitSize = needWaitTime * perSecondNeedSize;
- if (frameIndex > bufferredFrameCount) {
- // 手动定位到了后面指定帧,需要额外缓存相差的帧数
- final needWaitExtraCount = frameIndex - bufferredFrameCount;
- final needWaitExtraSize = _framePerSize * needWaitExtraCount;
- needWaitSize += needWaitExtraSize;
- }
- }
- return math.max(unbufferredSize, needWaitSize);
- }
- int _calcFramePerSize() {
- final size = _calcFramesBytesSize();
- final perSize = size ~/ channel.imageCount;
- return perSize;
- }
- int _calcFramesBytesSize() {
- int size = channel.getFileSize();
- size -= _vidHeadSize;
- return size;
- }
- int _calcHeaderSize() {
- int size = 0;
- size += channel.probe.toBytes().length;
- size += channel.extendedData.length;
- size += channel.imageCount * 8;
- size += 16; // Header Size
- size += 4; // Version Size
- size += 4; // ImageFormat
- return size;
- }
- }
|