import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'package:fis_common/extensions/date.dart'; import 'package:fis_common/index.dart'; import 'package:fis_common/web/shell_api_hepler.dart'; import 'package:vid/us/vid_us_data_http_reader.dart'; import '../reader.dart'; class AsyncShellVidDataReader extends AsyncVidDataReaderBase { final int minChunkSize; int _imageCount = 0; bool _isBreak = false; bool _isStop = false; int _skipFrameIndex = 0; Completer _completer = Completer(); late final String id = DateTime.now().format('MMddHHmmssSSS') + hashCode.toString(); AsyncShellVidDataReader( String url, { DownloadCallback? downloadCallback, this.minChunkSize = 65536, }) : super(url, downloadCallback: downloadCallback); @override void close() { _isStop = true; cancelFetchVid(); } @override void startDownload() async { final size = await getFileSize(); // 获取到size即开始下载 if (size == null) { setError(true, 'Get file size fail.'); } else if (isVrd) { _imageCount = size; fetchFrames(0, size, isNeedReload: true); } } @override Future skipToFrame(int index) async { if (_skipFrameIndex == index || index == 0) { return; } //停用上个不断获取帧的请求 if (!_completer.isCompleted) { _isStop = true; _completer.complete(); } _skipFrameIndex = index; print( "_skipFrameIndex change:$_skipFrameIndex _completer:${_completer.isCompleted}"); await Future.delayed(const Duration(milliseconds: 2000)); _isStop = false; print("fetchFrames : $_skipFrameIndex $_imageCount"); //从跳帧的位置开始不断获取数据 fetchFrames(_skipFrameIndex, _imageCount, isNeedReload: true); } void cancelFetchVid() { ShellApiHelper.call('cancelFetchVid', id); } /// 接收分片数据 void receiveChunk(Uint8List chunk) { appendChunk(chunk); final progress = downloadedSize / totalSize; print('updateProgress : $progress'); updateProgress(progress); } //注意:此处VRD返回的是总帧数,非VRD返回的是数据大小 Future getFileSize() async { final result = await ShellApiHelper.call( (isVrd) ? 'dynamicFetchVidAsync' : 'fetchVid', { 'Id': id, 'Url': url, 'MinChunkSize': minChunkSize, }, ); if (result != null) { if (isVrd) { _imageCount = result!; } initChunk(result); } await fetchFrames(0, 1, isNeedReload: true); print("getFileSize result:$result"); return result; } @override Future fetchFrames(int startIndex, int size, {bool isNeedReload = false}) async { _completer = Completer(); int batchSize = 5; // 每次获取的帧数 try { for (int start = startIndex; start < size; start += batchSize) { if (_isStop) { break; } int end = start + batchSize; if (end > size) { end = size; // 确保最后一次获取不会超出范围 } print("batchFetchFrames: start:$start end:$end"); bool result = await batchFetchFrames( start, end, isNeedReload: isNeedReload, ); if (_isStop) { break; } if (result == false) { continue; } } } finally { _completer.complete(); } return _completer.future; } Future batchFetchFrames( int start, int end, { bool isNeedReload = false, }) async { print("batchFetchFrames : $start $end"); final result = await ShellApiHelper.call( 'batchFetchFrames', { 'Id': id, 'Url': url, 'Start': start, 'End': end, }, ); if (_isStop) { return false; } if (result.toString().isEmpty) { print("batchFetchFrames result is empty"); _isBreak = true; if (isNeedReload) { await Future.delayed(const Duration(milliseconds: 1000)); return await batchFetchFrames(start, end, isNeedReload: isNeedReload); } return false; } List base64Frames = result.toString().split("&"); int index = start; for (var f in base64Frames) { var frame = base64Decode(f); appendFrame(frame, index); print("appendFrame ${frame.length} index: $index"); //非空,且之前没有中断,则允许更新进度 if (frame.isNotEmpty) { if (!_isBreak) { if (_isStop) { return false; } updateProgress(index / _imageCount); } } else { //如果遇到获取不到帧,则中断更新进度 print('updateProgress isBreak true'); _isBreak = true; } index++; } //base64Decode print("batchFetchFrames result:${base64Frames.length}"); return true; } }