reader.dart 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'dart:typed_data';
  4. import 'package:fis_common/extensions/date.dart';
  5. import 'package:fis_common/index.dart';
  6. import 'package:fis_common/web/shell_api_hepler.dart';
  7. import 'package:vid/us/vid_us_data_http_reader.dart';
  8. import '../reader.dart';
  9. class AsyncShellVidDataReader extends AsyncVidDataReaderBase {
  10. final int minChunkSize;
  11. int _imageCount = 0;
  12. bool _isBreak = false;
  13. bool _isStop = false;
  14. int _skipFrameIndex = 0;
  15. Completer<void> _completer = Completer<void>();
  16. late final String id =
  17. DateTime.now().format('MMddHHmmssSSS') + hashCode.toString();
  18. AsyncShellVidDataReader(
  19. String url, {
  20. DownloadCallback? downloadCallback,
  21. this.minChunkSize = 65536,
  22. }) : super(url, downloadCallback: downloadCallback);
  23. @override
  24. void close() {
  25. _isStop = true;
  26. cancelFetchVid();
  27. }
  28. @override
  29. void startDownload() async {
  30. final size = await getFileSize();
  31. // 获取到size即开始下载
  32. if (size == null) {
  33. setError(true, 'Get file size fail.');
  34. } else if (isVrd) {
  35. _imageCount = size;
  36. fetchFrames(0, size, isNeedReload: true);
  37. }
  38. }
  39. @override
  40. Future<void> skipToFrame(int index) async {
  41. if (_skipFrameIndex == index || index == 0) {
  42. return;
  43. }
  44. //停用上个不断获取帧的请求
  45. if (!_completer.isCompleted) {
  46. _isStop = true;
  47. _completer.complete();
  48. }
  49. _skipFrameIndex = index;
  50. print(
  51. "_skipFrameIndex change:$_skipFrameIndex _completer:${_completer.isCompleted}");
  52. await Future.delayed(const Duration(milliseconds: 2000));
  53. _isStop = false;
  54. print("fetchFrames : $_skipFrameIndex $_imageCount");
  55. //从跳帧的位置开始不断获取数据
  56. fetchFrames(_skipFrameIndex, _imageCount, isNeedReload: true);
  57. }
  58. void cancelFetchVid() {
  59. ShellApiHelper.call('cancelFetchVid', id);
  60. }
  61. /// 接收分片数据
  62. void receiveChunk(Uint8List chunk) {
  63. appendChunk(chunk);
  64. final progress = downloadedSize / totalSize;
  65. print('updateProgress : $progress');
  66. updateProgress(progress);
  67. }
  68. //注意:此处VRD返回的是总帧数,非VRD返回的是数据大小
  69. Future<int?> getFileSize() async {
  70. final result = await ShellApiHelper.call(
  71. (isVrd) ? 'dynamicFetchVidAsync' : 'fetchVid',
  72. {
  73. 'Id': id,
  74. 'Url': url,
  75. 'MinChunkSize': minChunkSize,
  76. },
  77. );
  78. if (result != null) {
  79. if (isVrd) {
  80. _imageCount = result!;
  81. }
  82. initChunk(result);
  83. }
  84. await fetchFrames(0, 1, isNeedReload: true);
  85. print("getFileSize result:$result");
  86. return result;
  87. }
  88. @override
  89. Future<void> fetchFrames(int startIndex, int size,
  90. {bool isNeedReload = false}) async {
  91. _completer = Completer<void>();
  92. int batchSize = 5; // 每次获取的帧数
  93. try {
  94. for (int start = startIndex; start < size; start += batchSize) {
  95. if (_isStop) {
  96. break;
  97. }
  98. int end = start + batchSize;
  99. if (end > size) {
  100. end = size; // 确保最后一次获取不会超出范围
  101. }
  102. print("batchFetchFrames: start:$start end:$end");
  103. bool result = await batchFetchFrames(
  104. start,
  105. end,
  106. isNeedReload: isNeedReload,
  107. );
  108. if (_isStop) {
  109. break;
  110. }
  111. if (result == false) {
  112. continue;
  113. }
  114. }
  115. } finally {
  116. _completer.complete();
  117. }
  118. return _completer.future;
  119. }
  120. Future<bool> batchFetchFrames(
  121. int start,
  122. int end, {
  123. bool isNeedReload = false,
  124. }) async {
  125. print("batchFetchFrames : $start $end");
  126. final result = await ShellApiHelper.call(
  127. 'batchFetchFrames',
  128. {
  129. 'Id': id,
  130. 'Url': url,
  131. 'Start': start,
  132. 'End': end,
  133. },
  134. );
  135. if (_isStop) {
  136. return false;
  137. }
  138. if (result.toString().isEmpty) {
  139. print("batchFetchFrames result is empty");
  140. _isBreak = true;
  141. if (isNeedReload) {
  142. await Future.delayed(const Duration(milliseconds: 1000));
  143. return await batchFetchFrames(start, end, isNeedReload: isNeedReload);
  144. }
  145. return false;
  146. }
  147. List<String> base64Frames = result.toString().split("&");
  148. int index = start;
  149. for (var f in base64Frames) {
  150. var frame = base64Decode(f);
  151. appendFrame(frame, index);
  152. print("appendFrame ${frame.length} index: $index");
  153. //非空,且之前没有中断,则允许更新进度
  154. if (frame.isNotEmpty) {
  155. if (!_isBreak) {
  156. if (_isStop) {
  157. return false;
  158. }
  159. updateProgress(index / _imageCount);
  160. }
  161. } else {
  162. //如果遇到获取不到帧,则中断更新进度
  163. print('updateProgress isBreak true');
  164. _isBreak = true;
  165. }
  166. index++;
  167. }
  168. //base64Decode
  169. print("batchFetchFrames result:${base64Frames.length}");
  170. return true;
  171. }
  172. }