controller.dart 10 KB

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