import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:vid/us/vid_us_data_http_reader.dart'; typedef AsyncVidDataReaderBytesProxy = Uint8List Function(); abstract class AsyncVidDataReaderBase { Uint8List _chunkedData = Uint8List(0); int _bufferSize = 0; int _index = 0; bool _error = false; String _errorMsg = ''; double _downloadProgress = 0; String url; //科研版内靠这个获取缓存 Map frames = {}; bool get isVrd => url.endsWith(".0"); DownloadCallback? downloadCallback; AsyncVidDataReaderBytesProxy? _bytesProxy; AsyncVidDataReaderBase(this.url, {this.downloadCallback}) { frames = {}; startDownload(); } Uint8List get _underlyingData { if (_bytesProxy != null) { return _bytesProxy!.call(); } return _chunkedData; } int get downloadedSize => _bufferSize; int get totalSize => _underlyingData.length; void startDownload(); //跳帧 void skipToFrame(int index); ///批量获取帧数 Future fetchFrames(int startIndex, int size, {bool isNeedReload = false}); void initChunk(int size) { _chunkedData = Uint8List(size); } void appendChunk(Uint8List chunk) { print('appendChunk: $_bufferSize ${chunk.length}'); if (isVrd && _chunkedData.length < _bufferSize + chunk.length) { _chunkedData = extendUint8List( _chunkedData, _bufferSize + chunk.length - _chunkedData.length); } _chunkedData.setAll(_bufferSize, chunk); setBufferSize(_bufferSize + chunk.length); } void appendFrame(Uint8List frame, int index) { if (frames.containsKey(index) && frames[index]! == frame) { return; } frames[index] = frame; } Uint8List extendUint8List(Uint8List originalData, int additionalSize) { // 创建新的 Uint8List,其长度等于原始长度 + 额外需要的长度 Uint8List newData = Uint8List(originalData.length + additionalSize); // 将原始数据复制到新的 Uint8List 中 newData.setRange(0, originalData.length, originalData); return newData; // 返回扩展后的新数据 } @protected void setBufferSize(int size) { print('setBufferSize size:$size'); _bufferSize = size; } void setError(bool hasErr, [String msg = '']) { _error = hasErr; _errorMsg = hasErr ? msg : ''; if (_error) { downloadCallback?.call(_downloadProgress, DownloadErrorException(msg)); } } void updateProgress(double progress, [DownloadErrorException? err]) { _downloadProgress = progress; print('updateProgress : $progress'); downloadCallback?.call(_downloadProgress, err); } /// 通过代理从其他渠道读取字节数组 /// /// 仅用于接入[VidUsDataHttpReader] @protected void setBytesProxy(AsyncVidDataReaderBytesProxy proxy) { _bytesProxy = proxy; } Uint8List toBytes() { return _underlyingData; } //Close the reader and its overhead. void close(); ///Read int value from binary data(little endian), int readInt([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 4) { throw NotReadyException(); } var intData = _underlyingData.buffer.asByteData(_index, 4); _index += 4; return intData.getInt32(0, Endian.little); } else { if ((_bufferSize - index) < 4) { throw NotReadyException(); } var intData = _underlyingData.buffer.asByteData(index, 4); _index = index + 4; return intData.getInt32(0, Endian.little); } } ///Read string from the binary data, the string format is utf-16, which is unicode in C# String readString([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } int dataLength; if (index == -1) { dataLength = readInt(); if ((_bufferSize - _index) < dataLength) { throw NotReadyException(); } } else { dataLength = readInt(index); if ((_bufferSize - index) < dataLength) { throw NotReadyException(); } } var stringData = _underlyingData.buffer.asUint8List(_index, dataLength); _index += dataLength; var unicodeStringData = Uint8List.fromList(stringData.toList()).buffer.asUint16List(); return String.fromCharCodes(unicodeStringData); } ///Read int16 value from binary data(little endian) int readInt16([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 2) { throw NotReadyException(); } var intData = _underlyingData.buffer.asByteData(_index, 2); _index += 2; return intData.getInt16(0, Endian.little); } else { if ((_bufferSize - index) < 2) { throw NotReadyException(); } var intData = _underlyingData.buffer.asByteData(index, 2); _index = index + 2; return intData.getInt16(0, Endian.little); } } ///Read int64 value from binary data(little endian) ///this method is not support in web platform use readInt64V2 instead. int readInt64([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 8) { throw NotReadyException(); } var intData = _underlyingData.buffer.asByteData(_index, 8); _index += 8; return intData.getInt64(0, Endian.little); } else { if ((_bufferSize - index) < 8) { throw NotReadyException(); } var intData = _underlyingData.buffer.asByteData(index, 8); _index = index + 8; return intData.getInt64(0, Endian.little); } } ///Read int64 value from binary data(little endian) ///this method use two int32 to support read int64 on web platform int readInt64V2([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 8) { throw NotReadyException(); } int low = readInt(); int high = readInt(); int value = high >> 32; value |= low; return value; } else { if ((_bufferSize - index) < 8) { throw NotReadyException(); } int low = readInt(index); //Read the next int. int high = readInt(); int value = high >> 32; value |= low; return value; } } ///Read float value from binary data(little endian) double readFloat([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 4) { throw NotReadyException(); } var floatData = _underlyingData.buffer.asByteData(_index, 4); _index += 4; return floatData.getFloat32(0, Endian.little); } else { if ((_bufferSize - index) < 4) { throw NotReadyException(); } var floatData = _underlyingData.buffer.asByteData(index, 4); _index = index + 4; return floatData.getFloat32(0, Endian.little); } } ///Read double value from binary data(little endian) double readDouble([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 8) { throw NotReadyException(); } var floatData = _underlyingData.buffer.asByteData(_index, 8); _index += 8; return floatData.getFloat64(0, Endian.little); } else { if ((_bufferSize - index) < 8) { throw NotReadyException(); } var floatData = _underlyingData.buffer.asByteData(index, 8); _index = index + 8; return floatData.getFloat64(0, Endian.little); } } ///Read bool value from binary data bool readBool([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 1) { throw NotReadyException(); } var boolData = _underlyingData.buffer.asByteData(_index, 1); _index++; return boolData.getInt8(0) == 1; } else { if ((_bufferSize - index) < 1) { throw NotReadyException(); } var boolData = _underlyingData.buffer.asByteData(index, 1); _index = index + 1; return boolData.getInt8(0) == 1; } } ///Read byte value from binary data int readByte([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } if (index == -1) { if ((_bufferSize - _index) < 1) { throw NotReadyException(); } var byteData = _underlyingData.buffer.asByteData(_index, 1); _index++; return byteData.getInt8(0); } else { if ((_bufferSize - index) < 1) { throw NotReadyException(); } var byteData = _underlyingData.buffer.asByteData(index, 1); _index = index + 1; return byteData.getInt8(0); } } ///Read bytes from the binary data. Uint8List readBytes([int index = -1]) { if (_error) { throw DownloadErrorException(_errorMsg); } var dataLength = readInt(index); if ((_bufferSize - _index) < dataLength) { throw NotReadyException(); } var bytes = _underlyingData.buffer.asUint8List(_index, dataLength); _index += dataLength; return bytes; } Uint8List getImageBytes(int index) { print("getImageBytes by index: $index,frames count:${frames.length}"); Uint8List result; if (frames.containsKey(index)) { result = frames[index] ?? Uint8List(0); } else { result = Uint8List(0); } return result; } }