123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- import 'dart:async';
- import 'package:fis_common/event/event_type.dart';
- import 'package:fis_common/func/func_proxy.dart';
- import 'package:fis_measure/interfaces/process/player/play_controller.dart';
- import 'package:fis_ui/index.dart';
- import 'package:fis_vid/data_channel/channel.dart';
- import 'package:fis_vid/data_host/data_host.dart';
- import 'package:flutter/foundation.dart';
- import 'package:vid/us/vid_us_image.dart';
- import 'package:vid/us/vid_us_probe.dart';
- import 'enums.dart';
- import 'events.dart';
- /// Vid播放器控制器
- class VidPlayerControllerNoSharing extends ChangeNotifier
- implements IPlayerController {
- /// Vid播放器控制器
- ///
- /// [dataHost] Vid文件宿主
- VidPlayerControllerNoSharing({
- required VidDataHost dataHost,
- }) {
- _dataHost = dataHost;
- eventHandler = FEventHandler<VidPlayerEvent>();
- frameUpdated = FEventHandler<VidUsImage>();
- firstFrameLoaded = FEventHandler<VidUsImage>();
- frameLoadStateChanged = FEventHandler<bool>();
- errorOccured = FEventHandler<String?>();
- }
- // ignore: constant_identifier_names
- static const _CAN_PLAY_STATUS_ARR = [
- VidPlayStatus.ready,
- VidPlayStatus.pause
- ];
- // ignore: constant_identifier_names
- static const _HAS_VIEW_STATUS_ARR = [VidPlayStatus.play, VidPlayStatus.pause];
- @override
- var eventHandler = FEventHandler<VidPlayerEvent>();
- var currentFrameHandler = FEventHandler<VidUsImage>();
- @override
- late final FEventHandler<VidUsImage> frameUpdated;
- @override
- late final FEventHandler<VidUsImage> firstFrameLoaded;
- @override
- late final FEventHandler<bool> frameLoadStateChanged;
- @override
- late final FEventHandler<String?> errorOccured;
- late final VidDataHost _dataHost;
- _PlayAssistant? _playAssistant;
- double _speed = 1.0;
- VidPlayStatus _status = VidPlayStatus.init;
- int _frameIndex = -1;
- VidUsImage? _frame;
- bool _disposed = false;
- ///该图像是否需要获取测量项和注释项
- bool ifNeedInit = true;
- @override
- bool get disposed => _disposed;
- /// Current play speed
- double get currentSpeed => _speed;
- @override
- VidPlayStatus get status => _status;
- @override
- VidUsImage? get currentFrame => _frame;
- /// Whether the player is playing
- bool get playing => status == VidPlayStatus.play;
- /// Whether the player can play
- bool get canPlay => _CAN_PLAY_STATUS_ARR.contains(status);
- /// Whether the player should has view
- @override
- bool get hasView => _HAS_VIEW_STATUS_ARR.contains(status);
- /// Current viewed frame index
- int get currentFrameIndex => _frameIndex;
- /// Total frames count of current vid
- int get totalFramesCount => _dataHost.frameCount;
- double get frameRate => _dataHost.probe.frameRate;
- bool get isSingleFrame => totalFramesCount == 1;
- /// 是否播放结束
- bool get isEndOfPlay => currentFrameIndex == totalFramesCount - 1;
- /// 当前播放器亮度 初始值为 0
- double get brightness => _brightness;
- double _brightness = 0.0;
- /// 当前播放器对比度 初始值为 1
- double get contrast => _contrast;
- double _contrast = 1.0;
- /// Set play speed [0.5~2]
- ///
- /// [speed] speed value [0.5~2]
- void setSpeed(double speed) {
- if (speed < 0.5 || speed > 2) return;
- _speed = speed;
- eventHandler.emit(this, VidPlayerSpeedChangeEvent(currentSpeed));
- }
- @override
- Future<bool> load() async {
- ifNeedInit = true;
- final info = await _dataHost.load();
- final result = info != null;
- if (result) {
- _setStatus(VidPlayStatus.ready);
- } else {
- _setStatus(VidPlayStatus.loadFail);
- }
- return result;
- }
- @override
- void play() {
- if (playing) return;
- if (!canPlay) return;
- if (isEndOfPlay) {
- _frameIndex = -1;
- }
- if (isSingleFrame) {
- gotoFrame(0);
- _setStatus(VidPlayStatus.pause);
- } else {
- _playAssistant ??= _PlayAssistant(this);
- _playAssistant!.play();
- _setStatus(VidPlayStatus.play);
- }
- }
- @override
- void pause() {
- if (!playing) {
- if (_status != VidPlayStatus.pause) {
- _setStatus(VidPlayStatus.pause);
- }
- return;
- }
- _playAssistant?.pause();
- _setStatus(VidPlayStatus.pause);
- }
- /// 主动播放结束
- void playOver() {
- pause();
- eventHandler.emit(this, VidPlayerPlayOverEvent());
- }
- /// Pause and view next frame
- Future<bool> gotoNextFrame() {
- pause();
- return gotoFrame(currentFrameIndex + 1);
- }
- /// Pause and view prev frame
- Future<bool> gotoPrevFrame() {
- pause();
- return gotoFrame(currentFrameIndex - 1);
- }
- /// View target indexed frame
- ///
- /// [index] frame index
- Future<bool> gotoFrame(int index) async {
- if (index < 0 || index >= totalFramesCount) return false;
- if (index == currentFrameIndex) return true;
- _frameIndex = index;
- _updateFrame();
- return true;
- }
- /// Set frame brightness
- ///
- /// [value] brightness value
- void setBrightness(int value) {
- final brightnessCount = value / 100;
- if (brightnessCount < -1 || brightnessCount > 1) {
- return;
- }
- if (kIsMobile) {
- _brightness = brightnessCount * 255;
- } else {
- _brightness = brightnessCount;
- }
- final fliterMatrix = <double>[
- contrast, 0, 0, 0, brightness, // red
- 0, contrast, 0, 0, brightness, // green
- 0, 0, contrast, 0, brightness, // blue
- 0, 0, 0, 1, 0, // alpha // alpha
- ];
- eventHandler.emit(this, VidPlayerFilterChangeEvent(fliterMatrix));
- _updateFrame();
- }
- /// Set frame contrast
- ///
- /// [value] contrast value
- void setContrast(int value) {
- double contrastCount = 1;
- if (value < 0) {
- contrastCount = (value + 100) / 100;
- } else if (value >= 0) {
- contrastCount = value / 100 * 9 + 1;
- }
- if (contrastCount < 0 || contrastCount > 10) {
- return;
- }
- _contrast = contrastCount;
- final fliterMatrix = <double>[
- contrast, 0, 0, 0, brightness, // red
- 0, contrast, 0, 0, brightness, // green
- 0, 0, contrast, 0, brightness, // blue
- 0, 0, 0, 1, 0, // alpha
- ];
- eventHandler.emit(this, VidPlayerFilterChangeEvent(fliterMatrix));
- _updateFrame();
- }
- void setFilterMatrix(List<double> matrix) {
- eventHandler.emit(this, VidPlayerFilterChangeEvent(matrix));
- }
- /// 重置图像增益
- void resetTone() {
- setBrightness(0);
- setContrast(0);
- eventHandler.emit(this, VidPlayResetToneEvent());
- }
- void _updateFrame() {
- _handleUpdateFrame
- .throttle(
- timeout: _playAssistant?._playIntervalMillSeconds ?? 200,
- )
- .call();
- }
- /// [Carotid] ✅用于设置颈动脉单帧展示
- void set2DMeasureFrame(VidUsImage _frame) {
- eventHandler.emit(
- this,
- VidPlayerFrameIndexChangeEvent(
- currentFrameIndex,
- _frame.imageData,
- _frame.width,
- _frame.height,
- ),
- );
- }
- /// [Carotid] ✅用于重置播放器
- void resetCurrentFrame() {
- _frameIndex = -1;
- play();
- }
- Future<void> _handleUpdateFrame() async {
- if (_disposed) return;
- _frame = await _dataHost.getFrame(currentFrameIndex);
- emitFrameUpdate();
- }
- void emitFrameUpdate() {
- if (ifNeedInit) {
- currentFrameHandler.emit(this, _frame!);
- ifNeedInit = false;
- }
- eventHandler.emit(
- this,
- VidPlayerFrameIndexChangeEvent(
- currentFrameIndex,
- _frame!.imageData,
- _frame!.width,
- _frame!.height,
- ),
- );
- }
- void _setStatus(VidPlayStatus value) {
- _status = value;
- _notifyStatus();
- }
- void _notifyStatus() {
- eventHandler.emit(this, VidPlayerStatusChangeEvent(status));
- }
- void _stop({bool needNotify = true}) {
- _playAssistant?.pause();
- if (needNotify) {
- _setStatus(VidPlayStatus.stop);
- }
- }
- @override
- void dispose() {
- _dataHost.release();
- _disposed = true;
- _stop(needNotify: false);
- eventHandler.dispose();
- super.dispose();
- }
- /// 已禁用,请通过eventHandler监听事件
- @override
- void addListener(VoidCallback listener) {
- throw UnsupportedError(
- "method `addListener` has been limited.Pls use `eventHandler.addListener`.");
- }
- /// 已禁用,请通过eventHandler监听事件
- @override
- void removeListener(VoidCallback listener) {
- throw UnsupportedError(
- "method `removeListener` has been limited.Pls use `eventHandler.removeListener`.");
- }
- @override
- VidDataChannel get dataChannel => throw UnimplementedError();
- @override
- Future<bool> locateTo(int index) {
- pause();
- return gotoFrame(index);
- }
- @override
- String get url => _dataHost.url;
- VidUsProbe get probe => _dataHost.probe;
- }
- class _PlayAssistant {
- _PlayAssistant(this.owner);
- final VidPlayerControllerNoSharing owner;
- bool _ready = false;
- late double _frameRate;
- int get _playInterval => 1000 * 1000 ~/ _frameRate;
- int get _playIntervalMillSeconds => _playInterval ~/ 1000.0;
- Timer? _timer;
- void play() {
- if (!_ready) {
- _prepare();
- }
- if (_timer != null) {
- pause();
- }
- final duration = Duration(microseconds: _playInterval);
- // final duration = const Duration(milliseconds: 1000 ~/ 10);
- _timer = Timer.periodic(duration, (timer) {
- // print('play at ${DateTime.now()}');
- owner.gotoFrame(owner.currentFrameIndex + 1);
- if (owner.currentFrameIndex == owner.totalFramesCount - 1) {
- owner.playOver();
- }
- });
- }
- void pause() {
- _timer?.cancel();
- _timer = null;
- print('stop at ${DateTime.now()}');
- }
- void _prepare() {
- _frameRate = owner._dataHost.probe.frameRate;
- _ready = true;
- }
- }
|