reader.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. if (isVrd) {
  31. final imageCount = await getImageCount();
  32. if (imageCount == 0) {
  33. setError(true, 'Get image count is 0.');
  34. return;
  35. }
  36. await fetchFrames(0, 1, isNeedReload: false);
  37. if (imageCount == null) {
  38. setError(true, 'Get image count fail.');
  39. return;
  40. }
  41. _imageCount = imageCount;
  42. fetchFrames(0, _imageCount, isNeedReload: true);
  43. return;
  44. }
  45. final size = await getFileSize();
  46. // 获取到size即开始下载
  47. if (size == null) {
  48. setError(true, 'Get file size fail.');
  49. }
  50. }
  51. @override
  52. Future<void> skipToFrame(int index) async {
  53. if (_skipFrameIndex == index || index == 0) {
  54. return;
  55. }
  56. //停用上个不断获取帧的请求
  57. if (!_completer.isCompleted) {
  58. _isStop = true;
  59. _completer.complete();
  60. }
  61. _skipFrameIndex = index;
  62. print(
  63. "_skipFrameIndex change:$_skipFrameIndex _completer:${_completer.isCompleted}");
  64. await Future.delayed(const Duration(milliseconds: 2000));
  65. _isStop = false;
  66. print("fetchFrames : $_skipFrameIndex $_imageCount");
  67. //从跳帧的位置开始不断获取数据
  68. fetchFrames(_skipFrameIndex, _imageCount, isNeedReload: true);
  69. }
  70. void cancelFetchVid() {
  71. ShellApiHelper.call('cancelFetchVid', id);
  72. }
  73. /// 接收分片数据
  74. void receiveChunk(Uint8List chunk) {
  75. appendChunk(chunk);
  76. final progress = downloadedSize / totalSize;
  77. print('updateProgress : $progress');
  78. updateProgress(progress);
  79. }
  80. Future<int?> getFileSize() async {
  81. final result = await ShellApiHelper.call(
  82. 'fetchVid',
  83. {
  84. 'Id': id,
  85. 'Url': url,
  86. 'MinChunkSize': minChunkSize,
  87. },
  88. );
  89. if (result != null) {
  90. initChunk(result!);
  91. }
  92. return result;
  93. }
  94. // 此处返回 VRD 的总帧数
  95. Future<int?> getImageCount() async {
  96. final result = await ShellApiHelper.call(
  97. 'dynamicFetchVidAsync',
  98. {
  99. 'Id': id,
  100. 'Url': url,
  101. 'MinChunkSize': minChunkSize,
  102. },
  103. );
  104. if (result != null) {
  105. _imageCount = result!;
  106. initChunk(result);
  107. }
  108. print("getImageCount result:$result");
  109. return result;
  110. }
  111. @override
  112. Future<void> fetchFrames(int startIndex, int size,
  113. {bool isNeedReload = false}) async {
  114. _completer = Completer<void>();
  115. int batchSize = 5; // 每次获取的帧数
  116. try {
  117. for (int start = startIndex; start < size; start += batchSize) {
  118. if (_isStop) {
  119. break;
  120. }
  121. int end = start + batchSize;
  122. if (end > size) {
  123. end = size; // 确保最后一次获取不会超出范围
  124. }
  125. print("batchFetchFrames: start:$start end:$end");
  126. bool result = await batchFetchFrames(
  127. start,
  128. end,
  129. isNeedReload: isNeedReload,
  130. );
  131. if (_isStop) {
  132. break;
  133. }
  134. if (result == false) {
  135. continue;
  136. }
  137. }
  138. } finally {
  139. _completer.complete();
  140. }
  141. return _completer.future;
  142. }
  143. Future<bool> batchFetchFrames(
  144. int start,
  145. int end, {
  146. bool isNeedReload = false,
  147. }) async {
  148. print("batchFetchFrames : $start $end");
  149. final result = await ShellApiHelper.call(
  150. 'batchFetchFrames',
  151. {
  152. 'Id': id,
  153. 'Url': url,
  154. 'Start': start,
  155. 'End': end,
  156. },
  157. );
  158. if (_isStop) {
  159. return false;
  160. }
  161. if (result.toString().isEmpty) {
  162. print("batchFetchFrames result is empty");
  163. _isBreak = true;
  164. if (isNeedReload) {
  165. await Future.delayed(const Duration(milliseconds: 1000));
  166. return await batchFetchFrames(start, end, isNeedReload: isNeedReload);
  167. }
  168. return false;
  169. }
  170. List<String> base64Frames = result.toString().split("&");
  171. int index = start;
  172. for (var f in base64Frames) {
  173. var frame = base64Decode(f);
  174. appendFrame(frame, index);
  175. print("appendFrame ${frame.length} index: $index");
  176. //非空,且之前没有中断,则允许更新进度
  177. // if (frame.isNotEmpty) {
  178. // if (!_isBreak) {
  179. // if (_isStop) {
  180. // return false;
  181. // }
  182. // }
  183. // } else {
  184. // //如果遇到获取不到帧,则中断更新进度
  185. // print('updateProgress isBreak true');
  186. // _isBreak = true;
  187. // }
  188. updateProgress(index / _imageCount);
  189. index++;
  190. }
  191. //base64Decode
  192. print("batchFetchFrames result:${base64Frames.length}");
  193. return true;
  194. }
  195. }