Browse Source

fix web http channel read bug

melon.yin 2 years ago
parent
commit
d13048d65a

+ 1 - 1
.flutter-plugins-dependencies

@@ -1 +1 @@
-{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_ios","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_ios-2.0.9\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_android-2.0.14\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_macos-2.0.6\\\\","native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.1.7\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.0.7\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2022-10-16 18:22:36.285311","version":"3.3.4"}
+{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"path_provider_ios","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_ios-2.0.9\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"path_provider_android","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_android-2.0.14\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_macos-2.0.6\\\\","native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_linux-2.1.7\\\\","native_build":false,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Melon\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.flutter-io.cn\\\\path_provider_windows-2.0.7\\\\","native_build":false,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"path_provider","dependencies":["path_provider_android","path_provider_ios","path_provider_linux","path_provider_macos","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_ios","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]}],"date_created":"2022-10-17 17:39:58.872197","version":"3.3.4"}

+ 6 - 1
lib/async_vid/cached/reader.dart

@@ -10,7 +10,12 @@ class AsyncCachedVidDataReader extends AsyncVidDataReaderBase {
       : super('') {
     initChunk(buffer.length);
     appendChunk(buffer);
-    updateProgress(1.0);
+    Future.delayed(
+      const Duration(milliseconds: 200),
+      () {
+        updateProgress(1.0);
+      },
+    );
   }
 
   @override

+ 3 - 0
lib/async_vid/http/reader.dart

@@ -29,6 +29,9 @@ class AsyncHttpVidDataReader extends AsyncVidDataReaderBase {
     return _inner.toBytes();
   }
 
+  @override
+  int getBufferedSize() => _inner.toBytes().length;
+
   @override
   void close() {
     _inner.close();

+ 9 - 4
lib/async_vid/reader.dart

@@ -7,7 +7,7 @@ typedef AsyncVidDataReaderBytesProxy = Uint8List Function();
 
 abstract class AsyncVidDataReaderBase {
   Uint8List _chunkedData = Uint8List(0);
-  int _bufferSize = 0;
+  int _bufferdSize = 0;
   int _index = 0;
   bool _error = false;
   String _errorMsg = '';
@@ -23,7 +23,8 @@ abstract class AsyncVidDataReaderBase {
 
   Uint8List get _underlyingData {
     if (_bytesProxy != null) {
-      return _bytesProxy!.call();
+      final d = _bytesProxy!.call();
+      return d;
     }
     return _chunkedData;
   }
@@ -31,6 +32,10 @@ abstract class AsyncVidDataReaderBase {
   int get downloadedSize => _bufferSize;
   int get totalSize => _underlyingData.length;
 
+  int get _bufferSize => getBufferedSize();
+
+  int getBufferedSize() => _bufferdSize;
+
   void startDownload();
 
   void initChunk(int size) {
@@ -38,8 +43,8 @@ abstract class AsyncVidDataReaderBase {
   }
 
   void appendChunk(Uint8List chunk) {
-    _chunkedData.setAll(_bufferSize, chunk);
-    _bufferSize += chunk.length;
+    _chunkedData.setAll(_bufferdSize, chunk);
+    _bufferdSize += chunk.length;
   }
 
   void setError(bool hasErr, [String msg = '']) {

+ 16 - 8
lib/async_vid/vid_data.dart

@@ -23,7 +23,7 @@ abstract class AsyncVidImageDataBase {
   late bool _closed;
 
   final Duration delayDuration = const Duration(milliseconds: 10);
-  final String header = "VINNO IMAGE DATA";
+  static final String vid_header = "VINNO IMAGE DATA";
 
   /// Gets the version of this image data.
   int get version => _version;
@@ -48,10 +48,17 @@ abstract class AsyncVidImageDataBase {
   /// 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}) {
+  AsyncVidImageDataBase(
+    String url, {
+    DownloadCallback? downloadCallback,
+    int readHeaderTimeout = 3000,
+    int readImageTimeout = 500,
+  }) {
     _initialized = false;
     _closed = false;
-    createReader(url, downloadCallback: downloadCallback);
+    _readHeaderTimeout = readHeaderTimeout;
+    _readImageTimeout = readImageTimeout;
+    _reader = createReader(url, downloadCallback: downloadCallback);
   }
 
   @protected
@@ -64,11 +71,11 @@ abstract class AsyncVidImageDataBase {
   }
 
   ///Initialize the HttpVidUsImageData, must be called firstly.
-  Future initialize() async {
+  Future<bool> initialize() async {
     if (!_initialized) {
       var header = await _readHeader();
-      if (header != header) {
-        throw Exception("The input data is not a VID data.");
+      if (header != vid_header) {
+        // throw Exception("The input data is not a VID data.");
       }
       _version = await _readVersion();
       //Get probe info
@@ -84,12 +91,13 @@ abstract class AsyncVidImageDataBase {
       }
       _initialized = true;
     }
+    return _initialized;
   }
 
   ///Close the HttpVidUsImageData, it will force close the download operation and reading operation.
   void close() {
-    _closed = true;
-    _reader.close();
+    // _closed = true;
+    // _reader.close();
   }
 
   @protected

+ 77 - 5
lib/data_channel/channel.dart

@@ -1,26 +1,98 @@
+import 'dart:async';
+
+import 'package:fis_common/event/event_type.dart';
 import 'package:fis_vid/async_vid/vid_data.dart';
 import 'package:flutter/foundation.dart';
+import 'package:vid/us/vid_us_data_http_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 'channel_stub.dart'
+    if (dart.library.html) 'channel_web.dart'
+    if (dart.library.io) 'channel_io.dart';
+
+import 'progress_info.dart';
 
 abstract class VidDataChannel {
-  late final AsyncVidImageDataBase _source;
+  @protected
+  late final AsyncVidImageDataBase? source;
+
+  final String url;
+
+  VidDataChannel(this.url);
+
+  factory VidDataChannel.create(String url) {
+    return VidDataChannelImpl(url);
+  }
+
+  /// 下载进度变更事件
+  final downloadProgressChanged = FEventHandler<VidDownloadProgressInfo>();
+
+  bool _initialized = false;
+
+  /// 是否初始化完成
+  bool get initialized => _initialized;
 
   /// 开始加载数据
-  Future<bool> load() async {
+  ///
+  /// [timeoute] 超时时间,单位ms, 默认10s
+  Future<bool> load([int timeoute = 10 * 1000]) async {
+    if (_initialized) return true;
+
     try {
-      _source = await buildSource();
-      await _source.initialize();
+      final completer = Completer<bool>();
+      final timer = Timer(
+        Duration(milliseconds: timeoute),
+        () {
+          if (!completer.isCompleted) {
+            completer.complete(_initialized);
+          }
+          if (!_initialized) {
+            source?.close();
+          }
+        },
+      );
+      _innerLoad().then((value) {
+        _initialized = true;
+        if (timer.isActive) {
+          timer.cancel();
+        }
+        completer.complete(true);
+      });
+      return completer.future;
+    } catch (e) {
+      return false;
+    }
+  }
+
+  /// 分发下载进度回调
+  @protected
+  void onDownloadCallback(double progress, DownloadErrorException? error) {
+    final info = VidDownloadProgressInfo(progress, error: error);
+    downloadProgressChanged.emit(this, info);
+  }
+
+  Future<bool> _innerLoad() async {
+    try {
+      source = await buildSource();
+      await source!.initialize();
       return true;
     } catch (e) {
       return false;
     }
   }
 
+  VidUsProbe get probe => source!.probe;
+  int get imageCount => source!.imageCount;
+  VidUsImageFormat get imageFormat => source!.imageFormat;
+  Uint8List get extendedData => source!.extendedData;
+
   /// 获取指定帧
   ///
   /// [index] 帧索引
   Future<VidUsImage> getImage(int index) async {
-    return _source.getImage(index);
+    return source!.getImage(index);
   }
 
   @protected

+ 27 - 4
lib/data_channel/channel_io.dart

@@ -1,11 +1,34 @@
+import 'package:fis_vid/async_vid/cached/vid_data.dart';
+import 'package:fis_vid/async_vid/http/vid_data.dart';
 import 'package:fis_vid/async_vid/vid_data.dart';
+import 'package:fis_vid/cache/io.dart';
+import 'package:vid/us/vid_us_data_http_reader.dart';
 
 import 'channel.dart';
 
-class VidDataChannelIO extends VidDataChannel {
+class VidDataChannelImpl extends VidDataChannel {
+  VidDataChannelImpl(String url) : super(url);
+
   @override
-  Future<AsyncVidImageDataBase> buildSource() {
-    // TODO: implement buildSource
-    throw UnimplementedError();
+  Future<AsyncVidImageDataBase> buildSource() async {
+    final cacheBuffer = await VidNativeCache.ins.getCache(url);
+    if (cacheBuffer != null) {
+      return AsyncCachedVidImageData(
+        cacheBuffer,
+        downloadCallback: onDownloadCallback,
+      );
+    }
+    return AsyncHttpVidImageData(
+      url,
+      downloadCallback: _onHttpDownloadCallback,
+    );
+  }
+
+  void _onHttpDownloadCallback(double progress, DownloadErrorException? error) {
+    if (progress >= 1) {
+      final bytes = source!.getDownloadedData();
+      VidNativeCache.ins.saveCache(url, bytes);
+    }
+    onDownloadCallback(progress, error);
   }
 }

+ 3 - 1
lib/data_channel/channel_stub.dart

@@ -2,7 +2,9 @@ import 'package:fis_vid/async_vid/vid_data.dart';
 
 import 'channel.dart';
 
-class VidDataChannelStub extends VidDataChannel {
+class VidDataChannelImpl extends VidDataChannel {
+  VidDataChannelImpl(String url) : super(url);
+
   @override
   Future<AsyncVidImageDataBase> buildSource() {
     // TODO: implement buildSource

+ 12 - 4
lib/data_channel/channel_web.dart

@@ -1,11 +1,19 @@
+import 'package:fis_common/env/env.dart';
+import 'package:fis_vid/async_vid/http/vid_data.dart';
+import 'package:fis_vid/async_vid/shell/vid_data.dart';
 import 'package:fis_vid/async_vid/vid_data.dart';
 
 import 'channel.dart';
 
-class VidDataChannelWeb extends VidDataChannel {
+class VidDataChannelImpl extends VidDataChannel {
+  VidDataChannelImpl(String url) : super(url);
+
   @override
-  Future<AsyncVidImageDataBase> buildSource() {
-    // TODO: implement buildSource
-    throw UnimplementedError();
+  Future<AsyncVidImageDataBase> buildSource() async {
+    if (FPlatform.isPureWeb) {
+      return AsyncHttpVidImageData(url, downloadCallback: onDownloadCallback);
+    } else {
+      return AsyncShellVidImageData(url, downloadCallback: onDownloadCallback);
+    }
   }
 }

+ 8 - 0
lib/data_channel/progress_info.dart

@@ -0,0 +1,8 @@
+import 'package:vid/us/vid_us_data_http_reader.dart';
+
+class VidDownloadProgressInfo {
+  final double progress;
+  final DownloadErrorException? error;
+
+  VidDownloadProgressInfo(this.progress, {this.error});
+}

+ 21 - 0
lib/data_channel/test.dart

@@ -0,0 +1,21 @@
+import 'channel.dart';
+
+class VidChannelTest {
+  void run() async {
+    final channel = VidDataChannel.create(
+        "http://cdn-bj.fis.plus/0B344F48BA574ECD82B7FEDB8848421A.vid");
+    channel.downloadProgressChanged.addListener((sender, e) {
+      if (e.progress == 1) {
+        print('downloadProgressChanged: ${e.progress}');
+      }
+      if (e.error != null) {
+        print('occur error');
+      }
+    });
+    final loaded = await channel.load();
+    if (loaded) {
+      final frame = await channel.getImage(0);
+      print('Frame-${frame.index}');
+    }
+  }
+}

+ 1 - 0
test/fis_lib_vid_test.dart

@@ -1,3 +1,4 @@
+import 'package:fis_vid/data_channel/test.dart';
 import 'package:flutter_test/flutter_test.dart';
 
 void main() {