vid_us_image_data.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. import 'dart:typed_data';
  2. import 'package:vid/us/vid_us_application.dart';
  3. import 'package:vid/us/vid_us_data_http_reader.dart';
  4. import 'package:vid/us/vid_us_data_reader.dart';
  5. import 'package:vid/us/vid_us_data_writer.dart';
  6. import 'package:vid/us/vid_us_image.dart';
  7. import 'package:vid/us/vid_us_probe.dart';
  8. enum VidUsImageFormat {
  9. Jpeg,
  10. Png,
  11. H264,
  12. Zip,
  13. Diff,
  14. }
  15. ///Not suport carotid3d for now.
  16. class VidUsImageData {
  17. late VidUsDataReader _reader;
  18. late List<int> _imagePositionList;
  19. late int _version;
  20. late int _imageCount;
  21. late VidUsProbe _probe;
  22. late VidUsImageFormat _imageFormat;
  23. late Uint8List _extendedData;
  24. late List<VidUsImage> _imagesList;
  25. final String header = "VINNO IMAGE DATA";
  26. /// Gets the version of this image data.
  27. int get version => _version;
  28. /// Gets the image count of this image data.
  29. int get imageCount => _imageCount;
  30. /// Gets the probe information.
  31. VidUsProbe get probe => _probe;
  32. /// Gets the image format of this image data.
  33. VidUsImageFormat get imageFormat => _imageFormat;
  34. /// Gets or sets the extended data.
  35. Uint8List get extendedData => _extendedData;
  36. /// Create a VINNO Image Data.
  37. VidUsImageData(Uint8List data) {
  38. _reader = VidUsDataReader(data);
  39. var header = _reader.readString();
  40. if (header != header) {
  41. throw Exception("The input data is not a VID data.");
  42. }
  43. _version = _reader.readInt();
  44. //Get probe info
  45. var probeData = _reader.readBytes();
  46. _probe = VidUsProbe.fromBytes(probeData);
  47. _imageFormat = VidUsImageFormat.values[_reader.readInt()];
  48. _extendedData = _reader.readBytes();
  49. _imagePositionList = [];
  50. var imagePositionListData = _reader.readBytes();
  51. _imageCount = imagePositionListData.length ~/ 8;
  52. var imagePositionReader = VidUsDataReader(imagePositionListData);
  53. for (var i = 0; i < _imageCount; i++) {
  54. _imagePositionList.add(imagePositionReader.readInt64V2());
  55. }
  56. _imagesList = [];
  57. }
  58. /// Create an empty third part VINNO Image Data
  59. VidUsImageData.empty(int fps, VidUsImageFormat imageFormat) {
  60. _imageCount = 0;
  61. _version = 1;
  62. _probe = VidUsProbe(
  63. "ThirdPart",
  64. VidUsProbeType.Linear,
  65. VidUsApplication(
  66. "ThirdPart",
  67. "ThirdPart",
  68. "ThirdPart",
  69. "ThirdPart",
  70. false,
  71. ),
  72. fps.toDouble(),
  73. );
  74. _imageFormat = imageFormat;
  75. _extendedData = Uint8List(10);
  76. _imagePositionList = [];
  77. _imagesList = [];
  78. }
  79. /// Add an image to the image data.
  80. void addJpegImage(Uint8List jpegBytes, int width, int height) {
  81. if (_imageFormat != VidUsImageFormat.Jpeg) {
  82. throw Exception("The image format is not Jpeg.");
  83. }
  84. if (_imagesList.length != _imageCount) {
  85. _fillImageList();
  86. }
  87. VidUsImage image = VidUsImage(_imageCount, width, height, jpegBytes);
  88. _imageCount++;
  89. _imagesList.add(image);
  90. }
  91. Uint8List flush() {
  92. if (_imageCount != _imagesList.length) {
  93. _fillImageList();
  94. }
  95. var imagePositionOffset = 0;
  96. var writer = VidUsDataWriter();
  97. writer.writeString(header);
  98. writer.writeInt(_version);
  99. writer.writeBytes(_probe.toBytes());
  100. writer.writeInt(_imageFormat.index);
  101. writer.writeBytes(_extendedData);
  102. imagePositionOffset = writer.data.length + _imageCount * 8 + 4;
  103. var imagePositionWriter = VidUsDataWriter();
  104. for (var i = 0; i < _imageCount; i++) {
  105. imagePositionWriter.writeInt64V2(imagePositionOffset);
  106. imagePositionOffset += _imagesList[i].toBytes().length + 4;
  107. }
  108. writer.writeBytes(imagePositionWriter.data);
  109. for (var i = 0; i < _imageCount; i++) {
  110. writer.writeBytes(_imagesList[i].toBytes());
  111. }
  112. return writer.data;
  113. }
  114. /// Get one image from the vid.
  115. VidUsImage getImage(int index) {
  116. if (index >= _imageCount || index < 0) {
  117. throw Exception("Can not find image Data");
  118. }
  119. //Jump to image.
  120. var imageData = _reader.readBytes(_imagePositionList[index]);
  121. return VidUsImage.fromBytes(imageData);
  122. }
  123. /// Fill all images to the image list.
  124. void _fillImageList() {
  125. _imagesList = [];
  126. for (var i = 0; i < _imageCount; i++) {
  127. _imagesList.add(getImage(i));
  128. }
  129. }
  130. void setThirdPartFPS(int newFps) {
  131. _probe = VidUsProbe(
  132. "ThirdPart",
  133. VidUsProbeType.Linear,
  134. VidUsApplication(
  135. "ThirdPart",
  136. "ThirdPart",
  137. "ThirdPart",
  138. "ThirdPart",
  139. false,
  140. ),
  141. newFps.toDouble(),
  142. );
  143. }
  144. }
  145. ///Raised when getting data from the downloaded data timeout. depends on the readHeaderTimeout and
  146. ///readImageTimeout parameters.
  147. class ReadTimeoutException implements Exception {}
  148. ///Raised when the Http operation already closed.
  149. class AlreadyClosedException implements Exception {}
  150. ///Only suport read for now.
  151. ///Not suport carotid3d for now.
  152. class HttpVidUsImageData {
  153. late VidUsDataHttpReader _reader;
  154. late List<int> _imagePositionList;
  155. late int _version;
  156. late int _imageCount;
  157. late VidUsProbe _probe;
  158. late VidUsImageFormat _imageFormat;
  159. late Uint8List _extendedData;
  160. late int _readHeaderTimeout;
  161. late int _readImageTimeout;
  162. late bool _initialized;
  163. late bool _closed;
  164. final Duration delayDuration = const Duration(milliseconds: 10);
  165. final String header = "VINNO IMAGE DATA";
  166. /// Gets the version of this image data.
  167. int get version => _version;
  168. /// Gets the image count of this image data.
  169. int get imageCount => _imageCount;
  170. /// Gets the probe information.
  171. VidUsProbe get probe => _probe;
  172. /// Gets the image format of this image data.
  173. VidUsImageFormat get imageFormat => _imageFormat;
  174. /// Gets the extended data.
  175. Uint8List get extendedData => _extendedData;
  176. /// Gets the initialized state.
  177. bool get initialized => _initialized;
  178. /// Create a VINNO Image Data.
  179. /// [readHeaderTimeout] is the timeout value of reading header and probe information etc..., we need give as much time as possible
  180. /// to let the reader read the header.
  181. /// [readImageTimeout] is the timeout value of reading one frame.
  182. /// [minChunkSize] The min download chunk size, set to a large value may speedup the download speed, but will cause the progress not smooth.
  183. HttpVidUsImageData(String url,
  184. {DownloadCallback? downloadCallback,
  185. int minChunkSize = 65536,
  186. int readHeaderTimeout = 3000,
  187. int readImageTimeout = 500}) {
  188. _initialized = false;
  189. _closed = false;
  190. _readHeaderTimeout = readHeaderTimeout;
  191. _readImageTimeout = readImageTimeout;
  192. _reader = VidUsDataHttpReader(url,
  193. downloadCallback: downloadCallback, minChunkSize: minChunkSize);
  194. }
  195. ///Get the downloaded data of this HttpVidUsImageData
  196. Uint8List getDownloadedData() {
  197. return _reader.toBytes();
  198. }
  199. ///Initialize the HttpVidUsImageData, must be called firstly.
  200. Future initialize() async {
  201. if (!_initialized) {
  202. var header = await _readHeader();
  203. if (header != header) {
  204. throw Exception("The input data is not a VID data.");
  205. }
  206. _version = await _readVersion();
  207. //Get probe info
  208. _probe = await _readProbe();
  209. _imageFormat = await _readImageFormat();
  210. _extendedData = await _readExtendedData();
  211. _imagePositionList = [];
  212. var imagePositionListData = await _readImagePositionListData();
  213. _imageCount = imagePositionListData.length ~/ 8;
  214. var imagePositionReader = VidUsDataReader(imagePositionListData);
  215. for (var i = 0; i < _imageCount; i++) {
  216. _imagePositionList.add(imagePositionReader.readInt64V2());
  217. }
  218. _initialized = true;
  219. }
  220. }
  221. ///Close the HttpVidUsImageData, it will force close the download operation and reading operation.
  222. void close() {
  223. _closed = true;
  224. _reader.close();
  225. }
  226. ///Read header from http data.
  227. Future<String> _readHeader() async {
  228. var timeout = 0;
  229. while (!_closed) {
  230. try {
  231. var header = _reader.readString();
  232. return header;
  233. } catch (ex) {
  234. if (ex is NotReadyException) {
  235. if (timeout >= _readHeaderTimeout) {
  236. throw ReadTimeoutException();
  237. }
  238. await Future.delayed(delayDuration);
  239. timeout += delayDuration.inMilliseconds;
  240. } else {
  241. rethrow;
  242. }
  243. }
  244. }
  245. throw AlreadyClosedException();
  246. }
  247. ///Read the version from http data.
  248. Future<int> _readVersion() async {
  249. var timeout = 0;
  250. while (!_closed) {
  251. try {
  252. var version = _reader.readInt();
  253. return version;
  254. } catch (ex) {
  255. if (ex is NotReadyException) {
  256. if (timeout >= _readHeaderTimeout) {
  257. throw ReadTimeoutException();
  258. }
  259. await Future.delayed(delayDuration);
  260. timeout += delayDuration.inMilliseconds;
  261. } else {
  262. rethrow;
  263. }
  264. }
  265. }
  266. throw AlreadyClosedException();
  267. }
  268. ///Read the probe info from http data.
  269. Future<VidUsProbe> _readProbe() async {
  270. var timeout = 0;
  271. while (!_closed) {
  272. try {
  273. var probeData = _reader.readBytes();
  274. return VidUsProbe.fromBytes(probeData);
  275. } catch (ex) {
  276. if (ex is NotReadyException) {
  277. if (timeout >= _readHeaderTimeout) {
  278. throw ReadTimeoutException();
  279. }
  280. await Future.delayed(delayDuration);
  281. timeout += delayDuration.inMilliseconds;
  282. } else {
  283. rethrow;
  284. }
  285. }
  286. }
  287. throw AlreadyClosedException();
  288. }
  289. ///Read the image format from http data.
  290. Future<VidUsImageFormat> _readImageFormat() async {
  291. var timeout = 0;
  292. while (!_closed) {
  293. try {
  294. return VidUsImageFormat.values[_reader.readInt()];
  295. } catch (ex) {
  296. if (ex is NotReadyException) {
  297. if (timeout >= _readHeaderTimeout) {
  298. throw ReadTimeoutException();
  299. }
  300. await Future.delayed(delayDuration);
  301. timeout += delayDuration.inMilliseconds;
  302. } else {
  303. rethrow;
  304. }
  305. }
  306. }
  307. throw AlreadyClosedException();
  308. }
  309. ///Read extended data from http data.
  310. Future<Uint8List> _readExtendedData() async {
  311. var timeout = 0;
  312. while (!_closed) {
  313. try {
  314. return _reader.readBytes();
  315. } catch (ex) {
  316. if (ex is NotReadyException) {
  317. if (timeout >= _readHeaderTimeout) {
  318. throw ReadTimeoutException();
  319. }
  320. await Future.delayed(delayDuration);
  321. timeout += delayDuration.inMilliseconds;
  322. } else {
  323. rethrow;
  324. }
  325. }
  326. }
  327. throw AlreadyClosedException();
  328. }
  329. ///Read the image positions data from http data.
  330. Future<Uint8List> _readImagePositionListData() async {
  331. var timeout = 0;
  332. while (!_closed) {
  333. try {
  334. return _reader.readBytes();
  335. } catch (ex) {
  336. if (ex is NotReadyException) {
  337. if (timeout >= _readHeaderTimeout) {
  338. throw ReadTimeoutException();
  339. }
  340. await Future.delayed(delayDuration);
  341. timeout += delayDuration.inMilliseconds;
  342. } else {
  343. rethrow;
  344. }
  345. }
  346. }
  347. throw AlreadyClosedException();
  348. }
  349. /// Get one image from the vid.
  350. Future<VidUsImage> getImage(int index) async {
  351. if (index >= _imageCount || index < 0) {
  352. throw Exception("Can not find image Data");
  353. }
  354. //Jump to image.
  355. var timeout = 0;
  356. while (!_closed) {
  357. try {
  358. var imageData = _reader.readBytes(_imagePositionList[index]);
  359. return VidUsImage.fromBytes(imageData);
  360. } catch (ex) {
  361. if (ex is NotReadyException) {
  362. if (timeout >= _readImageTimeout) {
  363. throw ReadTimeoutException();
  364. }
  365. await Future.delayed(delayDuration);
  366. timeout += delayDuration.inMilliseconds;
  367. } else {
  368. rethrow;
  369. }
  370. }
  371. }
  372. throw AlreadyClosedException();
  373. }
  374. }