buffer_waiter.dart 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import 'dart:async';
  2. import 'dart:math' as math;
  3. import 'package:fis_common/logger/logger.dart';
  4. import 'package:fis_vid/data_channel/channel.dart';
  5. /// Vid缓冲等待
  6. class VidBufferWaiter {
  7. VidBufferWaiter(
  8. this.channel, {
  9. this.timeout = 10 * 1000,
  10. });
  11. // ignore: constant_identifier_names
  12. static const _FIRST_FRAME_LOAD_TIME_LIMIT = 60 * 1000; // 一分钟
  13. /// 数据通道
  14. final VidDataChannel channel;
  15. /// 等待超时时间,默认10秒
  16. final int timeout;
  17. double _frameRate = 0;
  18. int _frameCount = 0;
  19. int _framePerSize = 0;
  20. int _vidHeadSize = 0;
  21. int _maxDuration = 0;
  22. Timer? _timer;
  23. /// vid头信息尺寸(含扩展)
  24. int get vidHeaderSize => _vidHeadSize;
  25. /// 初始化
  26. void init() {
  27. _frameRate = channel.probe.frameRate;
  28. _frameCount = channel.imageCount;
  29. _vidHeadSize = _calcHeaderSize();
  30. _framePerSize = _calcFramePerSize();
  31. }
  32. /// 等待首帧
  33. Future<void> waitSingleVid() async {
  34. logger.i("VidPlayer - Wait single vid start.");
  35. final completer = Completer();
  36. const int waitInterval = 100;
  37. const int waitCountLimit = _FIRST_FRAME_LOAD_TIME_LIMIT ~/ waitInterval;
  38. int waitCount = 0;
  39. _timer = Timer.periodic(
  40. const Duration(milliseconds: waitInterval),
  41. (timer) {
  42. waitCount++;
  43. if (channel.isBufferedDone) {
  44. // 全部缓冲完成
  45. timer.cancel();
  46. completer.complete();
  47. logger.i("VidPlayer - Wait single vid end.");
  48. return;
  49. }
  50. if (waitCount >= waitCountLimit) {
  51. completer.completeError(Exception("First frame load timeout"));
  52. logger.i("VidPlayer - Wait single vid: timeout.");
  53. }
  54. },
  55. );
  56. return completer.future;
  57. }
  58. /// 等待缓冲
  59. Future<void> waitBuffer(int frameIndex) {
  60. logger.i("VidPlayer - Wait buffer start.");
  61. final completer = Completer();
  62. final bufferredSize = channel.getBufferSize();
  63. final needBufferSize = _calcNeedWaitSize(frameIndex);
  64. const int waitInterval = 100;
  65. final int waitCountLimit = timeout ~/ waitInterval;
  66. int waitCount = 0;
  67. final startTime = DateTime.now();
  68. _timer = Timer.periodic(
  69. const Duration(milliseconds: waitInterval),
  70. (timer) {
  71. // 函数 - 完成等待
  72. void finishFn() {
  73. timer.cancel();
  74. completer.complete();
  75. final endTime = DateTime.now();
  76. final spendTime = endTime.difference(startTime).inMilliseconds;
  77. logger.i("VidPlayer - Wait buffer end, spend time: $spendTime ms.");
  78. }
  79. waitCount++;
  80. final bufferedSize = channel.getBufferSize();
  81. if (bufferedSize >= needBufferSize) {
  82. // 缓存足够
  83. return finishFn();
  84. }
  85. if (waitCount >= waitCountLimit) {
  86. // 等待超时
  87. final bufferredSizeNow = channel.getBufferSize();
  88. if (bufferredSizeNow - bufferredSize < 1024) {
  89. // 缓冲小于1k,报超时
  90. completer.completeError(Exception("Wait buffer timeout"));
  91. logger.i("VidPlayer - Wait buffer timeout.");
  92. } else {
  93. // 放行
  94. finishFn();
  95. }
  96. }
  97. },
  98. );
  99. return completer.future;
  100. }
  101. /// 记录单帧耗时
  102. void recordFrameSpendTime(int millseconds) {
  103. _maxDuration = math.max(_maxDuration, millseconds);
  104. }
  105. /// 取消等待
  106. void cancel() {
  107. _timer?.cancel();
  108. }
  109. int _calcNeedWaitSize(int frameIndex) {
  110. int needWaitSize = 0;
  111. final int bufferedSize = channel.getBufferSize();
  112. final int totalSize = channel.getFileSize();
  113. // 已缓冲帧数
  114. final int bufferredFrameCount = bufferedSize ~/ _framePerSize;
  115. // 未缓冲帧数
  116. final int unbufferredFrameCount = _frameCount - bufferredFrameCount;
  117. // 未缓冲数据字节数
  118. final int unbufferredSize = totalSize - bufferedSize;
  119. // 未缓冲数据字节数 所需耗时
  120. final int needBufferTime = unbufferredFrameCount * _maxDuration;
  121. // 未缓冲播放时长
  122. final int unbufferredDuration =
  123. ((1000 / _frameRate) * unbufferredFrameCount).toInt();
  124. // 每秒需要字节数
  125. final int perSecondNeedSize = (_framePerSize * _frameRate).toInt();
  126. // 缓存和播放同时结束所需耗时
  127. int needWaitTime = needBufferTime - unbufferredDuration;
  128. if (needWaitTime < 0) {
  129. // 预计缓冲比播放快(可能是网络波动大导致出现加载)
  130. // 缓存1秒
  131. needWaitSize = perSecondNeedSize;
  132. } else {
  133. needWaitTime += 1; //多缓存一秒
  134. needWaitSize = needWaitTime * perSecondNeedSize;
  135. if (frameIndex > bufferredFrameCount) {
  136. // 手动定位到了后面指定帧,需要额外缓存相差的帧数
  137. final needWaitExtraCount = frameIndex - bufferredFrameCount;
  138. final needWaitExtraSize = _framePerSize * needWaitExtraCount;
  139. needWaitSize += needWaitExtraSize;
  140. }
  141. }
  142. return math.max(unbufferredSize, needWaitSize);
  143. }
  144. int _calcFramePerSize() {
  145. final size = _calcFramesBytesSize();
  146. final perSize = size ~/ channel.imageCount;
  147. return perSize;
  148. }
  149. int _calcFramesBytesSize() {
  150. int size = channel.getFileSize();
  151. size -= _vidHeadSize;
  152. return size;
  153. }
  154. int _calcHeaderSize() {
  155. int size = 0;
  156. size += channel.probe.toBytes().length;
  157. size += channel.extendedData.length;
  158. size += channel.imageCount * 8;
  159. size += 16; // Header Size
  160. size += 4; // Version Size
  161. size += 4; // ImageFormat
  162. return size;
  163. }
  164. }