import 'dart:typed_data'; import 'package:flutter/foundation.dart'; import 'package:vid/us/vid_us_data_http_reader.dart'; import 'package:vid/us/vid_us_data_reader.dart'; import 'package:vid/us/vid_us_image.dart'; import 'package:vid/us/vid_us_image_data.dart'; import 'package:vid/us/vid_us_probe.dart'; import 'reader.dart'; abstract class AsyncVidImageDataBase { late AsyncVidDataReaderBase _reader; late List _imagePositionList; late int _version; late int _imageCount; late VidUsProbe _probe; late VidUsImageFormat _imageFormat; late Uint8List _extendedData; late int _readHeaderTimeout; late int _readImageTimeout; late bool _initialized; late bool _closed; final Duration delayDuration = const Duration(milliseconds: 10); static final String vid_header = "VINNO IMAGE DATA"; /// Gets the version of this image data. int get version => _version; /// Gets the image count of this image data. int get imageCount => _imageCount; /// Gets the probe information. VidUsProbe get probe => _probe; /// Gets the image format of this image data. VidUsImageFormat get imageFormat => _imageFormat; /// Gets the extended data. Uint8List get extendedData => _extendedData; /// Gets the initialized state. bool get initialized => _initialized; /// Create a VINNO Image Data. /// [readHeaderTimeout] is the timeout value of reading header and probe information etc..., we need give as much time as possible /// to let the reader read the header. /// [readImageTimeout] is the timeout value of reading one frame. /// [minChunkSize] The min download chunk size, set to a large value may speedup the download speed, but will cause the progress not smooth. AsyncVidImageDataBase( String url, { DownloadCallback? downloadCallback, int readHeaderTimeout = 3000, int readImageTimeout = 500, }) { _initialized = false; _closed = false; _readHeaderTimeout = readHeaderTimeout; _readImageTimeout = readImageTimeout; _reader = createReader(url, downloadCallback: downloadCallback); } @protected AsyncVidDataReaderBase createReader(String url, {DownloadCallback? downloadCallback}); ///Get the downloaded data of this HttpVidUsImageData Uint8List getDownloadedData() { return _reader.toBytes(); } void setReadHeaderTimeout(int timeout) => _readHeaderTimeout = timeout; void setReadImageTimeout(int timeout) => _readImageTimeout = timeout; ///Initialize the HttpVidUsImageData, must be called firstly. Future initialize() async { if (!_initialized) { var header = await _readHeader(); if (header != vid_header) { // throw Exception("The input data is not a VID data."); } _version = await _readVersion(); //Get probe info _probe = await _readProbe(); _imageFormat = await _readImageFormat(); _extendedData = await _readExtendedData(); _imagePositionList = []; var imagePositionListData = await _readImagePositionListData(); _imageCount = imagePositionListData.length ~/ 8; var imagePositionReader = VidUsDataReader(imagePositionListData); for (var i = 0; i < _imageCount; i++) { _imagePositionList.add(imagePositionReader.readInt64V2()); } _initialized = true; } return _initialized; } ///Close the HttpVidUsImageData, it will force close the download operation and reading operation. void close() { if (_closed) return; _closed = true; _reader.close(); } T getReader() => _reader as T; ///Read header from http data. Future _readHeader() async { var timeout = 0; while (!_closed) { try { var header = _reader.readString(); return header; } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readHeaderTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } ///Read the version from http data. Future _readVersion() async { var timeout = 0; while (!_closed) { try { var version = _reader.readInt(); return version; } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readHeaderTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } ///Read the probe info from http data. Future _readProbe() async { var timeout = 0; while (!_closed) { try { var probeData = _reader.readBytes(); return VidUsProbe.fromBytes(probeData); } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readHeaderTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } ///Read the image format from http data. Future _readImageFormat() async { var timeout = 0; while (!_closed) { try { return VidUsImageFormat.values[_reader.readInt()]; } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readHeaderTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } ///Read extended data from http data. Future _readExtendedData() async { var timeout = 0; while (!_closed) { try { return _reader.readBytes(); } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readHeaderTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } ///Read the image positions data from http data. Future _readImagePositionListData() async { var timeout = 0; while (!_closed) { try { return _reader.readBytes(); } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readHeaderTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } /// Get one image from the vid. Future getImage(int index) async { if (index >= _imageCount || index < 0) { throw Exception("Can not find image Data"); } //Jump to image. var timeout = 0; while (!_closed) { try { var imageData = _reader.readBytes(_imagePositionList[index]); return VidUsImage.fromBytes(imageData); } catch (ex) { if (ex is NotReadyException) { if (timeout >= _readImageTimeout) { throw ReadTimeoutException(); } await Future.delayed(delayDuration); timeout += delayDuration.inMilliseconds; } else { rethrow; } } } throw AlreadyClosedException(); } }