controller.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. // ignore_for_file: constant_identifier_names
  2. import 'dart:async';
  3. import 'package:fis_common/event/event_type.dart';
  4. import 'package:fis_measure/interfaces/process/player/play_controller.dart';
  5. import 'package:fis_ui/index.dart';
  6. import 'package:fis_vid/data_channel/channel.dart';
  7. import 'package:flutter/foundation.dart';
  8. import 'package:vid/us/vid_us_image.dart';
  9. import 'package:vid/us/vid_us_image_data.dart';
  10. import 'enums.dart';
  11. import 'events.dart';
  12. /// Vid播放器控制器
  13. class VidPlayerController extends ChangeNotifier implements IPlayerController {
  14. /// Vid播放器控制器
  15. ///
  16. /// [url] Vid文件链接
  17. VidPlayerController(String url) {
  18. _url = url;
  19. _dataChannel = VidDataChannel.create(url);
  20. _isFirstFrame = true;
  21. eventHandler = FEventHandler<VidPlayerEvent>();
  22. frameUpdated = FEventHandler<VidUsImage>();
  23. firstFrameLoaded = FEventHandler<VidUsImage>();
  24. frameLoadStateChanged = FEventHandler<bool>();
  25. errorOccured = FEventHandler<String?>();
  26. }
  27. static const _CAN_PLAY_STATUS_ARR = [
  28. VidPlayStatus.ready,
  29. VidPlayStatus.pause
  30. ];
  31. static const _HAS_VIEW_STATUS_ARR = [VidPlayStatus.play, VidPlayStatus.pause];
  32. static const _FRAME_LOAD_RETRY_LIMIT = 120; // 500ms一次,等一分钟
  33. @override
  34. late final FEventHandler<VidPlayerEvent> eventHandler;
  35. @override
  36. late final FEventHandler<VidUsImage> frameUpdated;
  37. @override
  38. late final FEventHandler<VidUsImage> firstFrameLoaded;
  39. @override
  40. late final FEventHandler<bool> frameLoadStateChanged;
  41. @override
  42. late final FEventHandler<String?> errorOccured;
  43. late final String _url;
  44. late final VidDataChannel _dataChannel;
  45. _PlayAssistant? _playAssistant;
  46. double _speed = 1.0;
  47. VidPlayStatus _status = VidPlayStatus.init;
  48. int _frameIndex = -1;
  49. VidUsImage? _frame;
  50. bool _disposed = false;
  51. bool _isFirstFrame = false;
  52. bool _loading = false;
  53. int _frameLoadRetryCount = 0;
  54. Timer? _bufferWaitingTimer;
  55. @override
  56. String get url => _url;
  57. @override
  58. VidDataChannel get dataChannel => _dataChannel;
  59. @override
  60. bool get disposed => _disposed;
  61. /// Current play speed
  62. double get currentSpeed => _speed;
  63. @override
  64. VidPlayStatus get status => _status;
  65. @override
  66. VidUsImage? get currentFrame => _frame;
  67. /// Whether the player is playing
  68. bool get playing => status == VidPlayStatus.play;
  69. /// Whether the player can play
  70. bool get canPlay => _CAN_PLAY_STATUS_ARR.contains(status);
  71. /// Whether the player should has view
  72. bool get hasView => _HAS_VIEW_STATUS_ARR.contains(status);
  73. /// Current viewed frame index
  74. int get currentFrameIndex => _frameIndex;
  75. /// Total frames count of current vid
  76. int get totalFramesCount => _dataChannel.imageCount;
  77. bool get isSingleFrame => totalFramesCount == 1;
  78. /// 是否播放结束
  79. bool get isEndOfPlay => currentFrameIndex == totalFramesCount - 1;
  80. /// 当前播放器亮度 初始值为 0
  81. double get brightness => _brightness;
  82. double _brightness = 0.0;
  83. /// 当前播放器对比度 初始值为 1
  84. double get contrast => _contrast;
  85. double _contrast = 1.0;
  86. /// Set play speed [0.5~2]
  87. ///
  88. /// [speed] speed value [0.5~2]
  89. void setSpeed(double speed) {
  90. if (speed < 0.5 || speed > 2) return;
  91. _speed = speed;
  92. eventHandler.emit(this, VidPlayerSpeedChangeEvent(currentSpeed));
  93. }
  94. @override
  95. Future<bool> load() async {
  96. final loaded = await _dataChannel.load(10 * 1000);
  97. if (loaded) {
  98. _setStatus(VidPlayStatus.ready);
  99. } else {
  100. _setStatus(VidPlayStatus.loadFail);
  101. }
  102. return loaded;
  103. }
  104. @override
  105. void play() {
  106. if (playing) return;
  107. if (!canPlay) return;
  108. if (isEndOfPlay) {
  109. _frameIndex = -1;
  110. }
  111. if (isSingleFrame) {
  112. locateTo(0);
  113. _setStatus(VidPlayStatus.pause);
  114. } else {
  115. _playAssistant ??= _PlayAssistant(this);
  116. _playAssistant!.play();
  117. _setStatus(VidPlayStatus.play);
  118. }
  119. }
  120. @override
  121. void pause() {
  122. if (!playing) return;
  123. _playAssistant?.pause();
  124. _setStatus(VidPlayStatus.pause);
  125. }
  126. /// Pause and view next frame
  127. Future<bool> gotoNextFrame() {
  128. return locateTo(currentFrameIndex + 1);
  129. }
  130. /// Pause and view prev frame
  131. Future<bool> gotoPrevFrame() {
  132. return locateTo(currentFrameIndex - 1);
  133. }
  134. @override
  135. Future<bool> locateTo(int index) async {
  136. if (index < 0 || index >= totalFramesCount) return false;
  137. pause();
  138. _loading = false;
  139. gotoFrame(index);
  140. return true;
  141. }
  142. /// View target indexed frame
  143. ///
  144. /// [index] frame index
  145. Future<bool> gotoFrame(int index) async {
  146. if (index < 0 || index >= totalFramesCount) return false;
  147. if (_loading) return false;
  148. _frameIndex = index;
  149. _loading = true;
  150. _updateFrameLoadState(true);
  151. final result = await _waitUpdateFrame();
  152. if (result) {
  153. _updateFrameLoadState(false);
  154. }
  155. return result;
  156. }
  157. /// Set frame brightness
  158. ///
  159. /// [value] brightness value
  160. void setBrightness(int value) {
  161. final brightnessCount = value / 100;
  162. if (brightnessCount < -1 || brightnessCount > 1) {
  163. return;
  164. }
  165. if (kIsMobile) {
  166. _brightness = brightnessCount * 255;
  167. } else {
  168. _brightness = brightnessCount;
  169. }
  170. final fliterMatrix = <double>[
  171. contrast, 0, 0, 0, brightness, // red
  172. 0, contrast, 0, 0, brightness, // green
  173. 0, 0, contrast, 0, brightness, // blue
  174. 0, 0, 0, 1, 0, // alpha // alpha
  175. ];
  176. eventHandler.emit(this, VidPlayerFilterChangeEvent(fliterMatrix));
  177. _reloadFrame();
  178. }
  179. /// Set frame contrast
  180. ///
  181. /// [value] contrast value
  182. void setContrast(int value) {
  183. double contrastCount = 1;
  184. if (value < 0) {
  185. contrastCount = (value + 100) / 100;
  186. } else if (value >= 0) {
  187. contrastCount = value / 100 * 9 + 1;
  188. }
  189. if (contrastCount < 0 || contrastCount > 10) {
  190. return;
  191. }
  192. _contrast = contrastCount;
  193. final fliterMatrix = <double>[
  194. contrast, 0, 0, 0, brightness, // red
  195. 0, contrast, 0, 0, brightness, // green
  196. 0, 0, contrast, 0, brightness, // blue
  197. 0, 0, 0, 1, 0, // alpha
  198. ];
  199. eventHandler.emit(this, VidPlayerFilterChangeEvent(fliterMatrix));
  200. _reloadFrame();
  201. }
  202. void setFilterMatrix(List<double> matrix) {
  203. eventHandler.emit(this, VidPlayerFilterChangeEvent(matrix));
  204. }
  205. /// 重置图像增益
  206. void resetTone() {
  207. setBrightness(0);
  208. setContrast(0);
  209. eventHandler.emit(this, VidPlayResetToneEvent());
  210. }
  211. void _reloadFrame() {
  212. gotoFrame(currentFrameIndex);
  213. }
  214. void _updateFrameLoadState(bool val) {
  215. _loading = val;
  216. frameLoadStateChanged.emit(this, _loading);
  217. }
  218. void _emitErrorOccured([String? msg]) {
  219. errorOccured.emit(this, msg);
  220. }
  221. /// 等待更新帧
  222. Future<bool> _waitUpdateFrame([int? timeout]) async {
  223. if (_disposed) return false;
  224. try {
  225. final t = timeout ?? _playAssistant?._playIntervalMillSeconds ?? 500;
  226. _frame = await _dataChannel.getImage(currentFrameIndex, t);
  227. emitFrameUpdate();
  228. _frameLoadRetryCount = 0;
  229. return true;
  230. } catch (e) {
  231. if (e is ReadTimeoutException) {
  232. try {
  233. await _waitFrameBufferFluently();
  234. return await _waitUpdateFrame(500);
  235. } catch (e) {
  236. _emitErrorOccured("FrameLoadTimeout");
  237. }
  238. } else {
  239. _emitErrorOccured("FrameLoadError");
  240. }
  241. }
  242. return false;
  243. }
  244. Future<void> _waitFrameBufferFluently() async {
  245. const duration = Duration(milliseconds: 500);
  246. if (isSingleFrame) {
  247. await _waitSingleFrameBuffer(duration);
  248. } else {
  249. await _waitVideoBuffer(duration);
  250. }
  251. _frameLoadRetryCount = 0;
  252. }
  253. Future<void> _waitSingleFrameBuffer(Duration duration) async {
  254. final completer = Completer();
  255. Timer.periodic(
  256. duration,
  257. (timer) {
  258. if (_dataChannel.isBufferedDone) {
  259. timer.cancel();
  260. completer.complete();
  261. return;
  262. }
  263. _frameLoadRetryCount++;
  264. if (_frameLoadRetryCount >= _FRAME_LOAD_RETRY_LIMIT) {
  265. completer.completeError(Exception());
  266. }
  267. },
  268. );
  269. return completer.future;
  270. }
  271. Future<void> _waitVideoBuffer(Duration duration) async {
  272. final singleSize = currentFrame?.imageData.length ?? 2048;
  273. int fluntFrameCount = (_playAssistant!._frameRate * 1).toInt(); //1s缓冲
  274. final leftCount = totalFramesCount - (currentFrameIndex + 1);
  275. if (fluntFrameCount > leftCount) {
  276. fluntFrameCount = leftCount;
  277. }
  278. final bufferedSize = _dataChannel.getBufferSize();
  279. int fluentSize = bufferedSize + fluntFrameCount * singleSize;
  280. final totalSize = _dataChannel.getFileSize();
  281. if (fluentSize > totalSize) {
  282. fluentSize = totalSize;
  283. }
  284. final completer = Completer();
  285. Timer.periodic(
  286. duration,
  287. (timer) {
  288. final bufferedSize = _dataChannel.getBufferSize();
  289. if (bufferedSize >= fluentSize) {
  290. timer.cancel();
  291. completer.complete();
  292. return;
  293. }
  294. _frameLoadRetryCount++;
  295. if (_frameLoadRetryCount >= _FRAME_LOAD_RETRY_LIMIT) {
  296. completer.completeError(Exception());
  297. }
  298. },
  299. );
  300. return completer.future;
  301. }
  302. /// [Carotid] ✅用于设置颈动脉单帧展示
  303. void set2DMeasureFrame(VidUsImage frame) {
  304. _emitFrameUpdated(frame);
  305. }
  306. /// [Carotid] ✅用于重置播放器
  307. void resetCurrentFrame() {
  308. _frameIndex = -1;
  309. play();
  310. }
  311. void emitFrameUpdate() {
  312. if (_isFirstFrame) {
  313. firstFrameLoaded.emit(this, _frame!);
  314. _isFirstFrame = false;
  315. }
  316. _emitFrameUpdated();
  317. }
  318. void _emitFrameUpdated([VidUsImage? frame]) {
  319. // frameUpdated.emit(this, frame ?? _frame!);
  320. final f = frame ?? _frame!;
  321. eventHandler.emit(
  322. this,
  323. VidPlayerFrameIndexChangeEvent(f.index, f.imageData, f.width, f.height),
  324. );
  325. }
  326. void _setStatus(VidPlayStatus value) {
  327. _status = value;
  328. _notifyStatus();
  329. }
  330. void _notifyStatus() {
  331. eventHandler.emit(this, VidPlayerStatusChangeEvent(status));
  332. }
  333. void _stop({bool needNotify = true}) {
  334. _playAssistant?.pause();
  335. if (needNotify) {
  336. _setStatus(VidPlayStatus.stop);
  337. }
  338. }
  339. @override
  340. void dispose() {
  341. _disposed = true;
  342. _bufferWaitingTimer?.cancel();
  343. _stop(needNotify: false);
  344. eventHandler.dispose();
  345. _dataChannel.close();
  346. super.dispose();
  347. }
  348. /// 已禁用,请通过eventHandler监听事件
  349. @override
  350. void addListener(VoidCallback listener) {
  351. throw UnsupportedError(
  352. "method `addListener` has been limited.Pls use `eventHandler.addListener`.");
  353. }
  354. /// 已禁用,请通过eventHandler监听事件
  355. @override
  356. void removeListener(VoidCallback listener) {
  357. throw UnsupportedError(
  358. "method `removeListener` has been limited.Pls use `eventHandler.removeListener`.");
  359. }
  360. }
  361. class _PlayAssistant {
  362. _PlayAssistant(this.owner);
  363. final VidPlayerController owner;
  364. bool _ready = false;
  365. late double _frameRate;
  366. int get _playInterval => 1000 * 1000 ~/ _frameRate;
  367. int get _playIntervalMillSeconds => _playInterval ~/ 1000.0;
  368. Timer? _timer;
  369. void play() {
  370. if (!_ready) {
  371. _prepare();
  372. }
  373. if (_timer != null) {
  374. pause();
  375. }
  376. final duration = Duration(microseconds: _playInterval);
  377. // final duration = const Duration(milliseconds: 1000 ~/ 10);
  378. _timer = Timer.periodic(duration, (timer) async {
  379. // print('play at ${DateTime.now()}');
  380. final result = await owner.gotoFrame(owner.currentFrameIndex + 1);
  381. if (result) {
  382. if (owner.currentFrameIndex == owner.totalFramesCount - 1) {
  383. owner.pause();
  384. }
  385. }
  386. });
  387. }
  388. void pause() {
  389. _timer?.cancel();
  390. _timer = null;
  391. }
  392. void _prepare() {
  393. _frameRate = owner._dataChannel.probe.frameRate;
  394. _ready = true;
  395. }
  396. }