buffer_waiter.dart 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. logger.i("VidPlayer - buffer end since buffered enough");
  84. logger.i("VidPlayer - BufferedSize: $bufferedSize.");
  85. logger.i("VidPlayer - NeedBufferedSize: $needBufferSize.");
  86. return finishFn();
  87. }
  88. if (channel.isBufferedDone) {
  89. // 全部缓冲完成
  90. var fileTotalSize = channel.getFileSize();
  91. var fileDownloadedSize = channel.getBufferSize();
  92. logger.i("VidPlayer - buffer end since all files are downloaded");
  93. logger.i("VidPlayer - fileTotalSize: $fileTotalSize.");
  94. logger.i("VidPlayer - filedownloaded: $fileDownloadedSize.");
  95. return finishFn();
  96. }
  97. if (waitCount >= waitCountLimit) {
  98. //记录上方管理提前终止的逻辑未执行时的内存现场
  99. var fileTotalSize = channel.getFileSize();
  100. var fileDownloadedSize = channel.getBufferSize();
  101. logger.i(
  102. "VidPlayer - channel.isBufferedDone: ${channel.isBufferedDone}.");
  103. logger.i("VidPlayer - BufferedSize: $bufferedSize.");
  104. logger.i("VidPlayer - NeedBufferedSize: $needBufferSize.");
  105. logger.i("VidPlayer - fileTotalSize: $fileTotalSize.");
  106. logger.i("VidPlayer - filedownloaded: $fileDownloadedSize.");
  107. // 等待超时
  108. final bufferredSizeNow = channel.getBufferSize();
  109. if (bufferredSizeNow - bufferredSize < 1024) {
  110. timer.cancel();
  111. // 缓冲小于1k,报超时
  112. completer.completeError(Exception("Wait buffer timeout"));
  113. logger.i("VidPlayer - Wait buffer timeout.");
  114. } else {
  115. // 放行
  116. finishFn();
  117. }
  118. }
  119. },
  120. );
  121. return completer.future;
  122. }
  123. /// 记录单帧耗时
  124. void recordFrameSpendTime(int millseconds) {
  125. _maxDuration = math.max(_maxDuration, millseconds);
  126. }
  127. /// 取消等待
  128. void cancel() {
  129. _timer?.cancel();
  130. }
  131. int _calcNeedWaitSize(int frameIndex) {
  132. int needWaitSize = 0;
  133. final int bufferedSize = channel.getBufferSize();
  134. final int totalSize = channel.getFileSize();
  135. // 已缓冲帧数
  136. final int bufferredFrameCount = bufferedSize ~/ _framePerSize;
  137. // 未缓冲帧数
  138. final int unbufferredFrameCount = _frameCount - bufferredFrameCount;
  139. // 未缓冲数据字节数
  140. final int unbufferredSize = totalSize - bufferedSize;
  141. // 未缓冲数据字节数 所需耗时
  142. final int needBufferTime = unbufferredFrameCount * _maxDuration;
  143. // 未缓冲播放时长
  144. final int unbufferredDuration =
  145. ((1000 / _frameRate) * unbufferredFrameCount).toInt();
  146. // 每秒需要字节数
  147. final int perSecondNeedSize = (_framePerSize * _frameRate).toInt();
  148. // 缓存和播放同时结束所需耗时
  149. int needWaitTime = needBufferTime - unbufferredDuration;
  150. if (needWaitTime < 0) {
  151. // 预计缓冲比播放快(可能是网络波动大导致出现加载)
  152. // 缓存1秒
  153. needWaitSize = perSecondNeedSize;
  154. } else {
  155. needWaitTime += 1; //多缓存一秒
  156. needWaitSize = needWaitTime * perSecondNeedSize;
  157. if (frameIndex > bufferredFrameCount) {
  158. // 手动定位到了后面指定帧,需要额外缓存相差的帧数
  159. final needWaitExtraCount = frameIndex - bufferredFrameCount;
  160. final needWaitExtraSize = _framePerSize * needWaitExtraCount;
  161. needWaitSize += needWaitExtraSize;
  162. }
  163. }
  164. return math.max(unbufferredSize, needWaitSize);
  165. }
  166. int _calcFramePerSize() {
  167. final size = _calcFramesBytesSize();
  168. final perSize = size ~/ channel.imageCount;
  169. return perSize;
  170. }
  171. int _calcFramesBytesSize() {
  172. int size = channel.getFileSize();
  173. size -= _vidHeadSize;
  174. return size;
  175. }
  176. int _calcHeaderSize() {
  177. int size = 0;
  178. size += channel.probe.toBytes().length;
  179. size += channel.extendedData.length;
  180. size += channel.imageCount * 8;
  181. size += 16; // Header Size
  182. size += 4; // Version Size
  183. size += 4; // ImageFormat
  184. return size;
  185. }
  186. }