#678 video: media_kit player POC
This commit is contained in:
parent
ad74eef150
commit
46c58207e7
47 changed files with 1138 additions and 423 deletions
|
@ -1,7 +1,7 @@
|
|||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.8.21'
|
||||
agp_version = '8.0.2'
|
||||
agp_version = '7.4.2'
|
||||
glide_version = '4.15.1'
|
||||
// AppGallery Connect plugin versions: https://developer.huawei.com/consumer/en/doc/development/AppGallery-connect-Guides/agc-sdk-changenotes-0000001058732550
|
||||
// TODO TLAD AppGallery Connect plugin v1.9.0.300 does not support Gradle 8+
|
||||
|
|
|
@ -200,6 +200,7 @@ class AvesEntry with AvesEntryBase {
|
|||
_bestTitle = null;
|
||||
}
|
||||
|
||||
@override
|
||||
String? get path => _path;
|
||||
|
||||
// directory path, without the trailing separator
|
||||
|
|
|
@ -71,7 +71,7 @@ extension ExtraAvesEntryInfo on AvesEntry {
|
|||
|
||||
Future<List<MetadataDirectory>> _getStreamDirectories(BuildContext context) async {
|
||||
final directories = <MetadataDirectory>[];
|
||||
final mediaInfo = await VideoMetadataFormatter.getVideoMetadata(this);
|
||||
final mediaInfo = await videoMetadataFetcher.getMetadata(this);
|
||||
|
||||
final formattedMediaTags = VideoMetadataFormatter.formatInfo(mediaInfo);
|
||||
if (formattedMediaTags.isNotEmpty) {
|
||||
|
|
|
@ -16,13 +16,10 @@ import 'package:aves/utils/math_utils.dart';
|
|||
import 'package:aves/utils/string_utils.dart';
|
||||
import 'package:aves/utils/time_utils.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_video_ijk/aves_video_ijk.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:fijkplayer/fijkplayer.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class VideoMetadataFormatter {
|
||||
static bool _initializedFijkLog = false;
|
||||
static final _dateY4M2D2H2m2s2Pattern = RegExp(r'(\d{4})[-./:](\d{1,2})[-./:](\d{1,2})([ T](\d{1,2}):(\d{1,2}):(\d{1,2})( ([ap]\.? ?m\.?))?)?');
|
||||
static final _ambiguousDatePatterns = {
|
||||
RegExp(r'^\d{2}[-/]\d{2}[-/]\d{4}$'),
|
||||
|
@ -45,24 +42,8 @@ class VideoMetadataFormatter {
|
|||
Codecs.webm: 'WebM',
|
||||
};
|
||||
|
||||
static Future<Map> getVideoMetadata(AvesEntry entry) async {
|
||||
if (!_initializedFijkLog) {
|
||||
_initializedFijkLog = true;
|
||||
FijkLog.setLevel(FijkLogLevel.Warn);
|
||||
}
|
||||
final player = FijkPlayer();
|
||||
final info = await player.setDataSourceUntilPrepared(entry.uri).then((v) {
|
||||
return player.getInfo();
|
||||
}).catchError((error) {
|
||||
debugPrint('failed to get video metadata for entry=$entry, error=$error');
|
||||
return {};
|
||||
});
|
||||
await player.release();
|
||||
return info;
|
||||
}
|
||||
|
||||
static Future<Map<String, int>> getLoadingMetadata(AvesEntry entry) async {
|
||||
final mediaInfo = await getVideoMetadata(entry);
|
||||
final mediaInfo = await videoMetadataFetcher.getMetadata(entry);
|
||||
final fields = <String, int>{};
|
||||
|
||||
final streams = mediaInfo[Keys.streams];
|
||||
|
@ -87,7 +68,7 @@ class VideoMetadataFormatter {
|
|||
}
|
||||
|
||||
static Future<CatalogMetadata?> getCatalogMetadata(AvesEntry entry) async {
|
||||
final mediaInfo = await getVideoMetadata(entry);
|
||||
final mediaInfo = await videoMetadataFetcher.getMetadata(entry);
|
||||
|
||||
// only consider values with at least 8 characters (yyyymmdd),
|
||||
// ignoring unset values like `0`, as well as year values like `2021`
|
||||
|
|
|
@ -19,6 +19,8 @@ import 'package:aves_report/aves_report.dart';
|
|||
import 'package:aves_report_platform/aves_report_platform.dart';
|
||||
import 'package:aves_services/aves_services.dart';
|
||||
import 'package:aves_services_platform/aves_services_platform.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:aves_video_ijk/aves_video_ijk.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
|
@ -30,6 +32,8 @@ final SettingsStore settingsStore = SharedPrefSettingsStore();
|
|||
final p.Context pContext = getIt<p.Context>();
|
||||
final AvesAvailability availability = getIt<AvesAvailability>();
|
||||
final MetadataDb metadataDb = getIt<MetadataDb>();
|
||||
final AvesVideoControllerFactory videoControllerFactory = getIt<AvesVideoControllerFactory>();
|
||||
final AvesVideoMetadataFetcher videoMetadataFetcher = getIt<AvesVideoMetadataFetcher>();
|
||||
|
||||
final AppService appService = getIt<AppService>();
|
||||
final DeviceService deviceService = getIt<DeviceService>();
|
||||
|
@ -50,6 +54,8 @@ void initPlatformServices() {
|
|||
getIt.registerLazySingleton<p.Context>(p.Context.new);
|
||||
getIt.registerLazySingleton<AvesAvailability>(LiveAvesAvailability.new);
|
||||
getIt.registerLazySingleton<MetadataDb>(SqfliteMetadataDb.new);
|
||||
getIt.registerLazySingleton<AvesVideoControllerFactory>(IjkVideoControllerFactory.new);
|
||||
getIt.registerLazySingleton<AvesVideoMetadataFetcher>(IjkVideoMetadataFetcher.new);
|
||||
|
||||
getIt.registerLazySingleton<AppService>(PlatformAppService.new);
|
||||
getIt.registerLazySingleton<DeviceService>(PlatformDeviceService.new);
|
||||
|
|
|
@ -455,6 +455,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
settings.areAnimationsRemoved = await AccessibilityService.areAnimationsRemoved();
|
||||
await _onTvLayoutChanged();
|
||||
_monitorSettings();
|
||||
videoControllerFactory.init();
|
||||
|
||||
unawaited(_setupErrorReporting());
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/entry/entry.dart';
|
||||
import 'package:aves/model/entry/extensions/location.dart';
|
||||
|
@ -56,7 +57,7 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
case EntryAction.videoTogglePlay:
|
||||
await _togglePlayPause(context, controller);
|
||||
case EntryAction.videoReplay10:
|
||||
await controller.seekTo(controller.currentPosition - 10000);
|
||||
await controller.seekTo(max(controller.currentPosition - 10000, 0));
|
||||
case EntryAction.videoSkip10:
|
||||
await controller.seekTo(controller.currentPosition + 10000);
|
||||
case EntryAction.openVideo:
|
||||
|
@ -189,6 +190,8 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
}
|
||||
|
||||
Future<void> _togglePlayPause(BuildContext context, AvesVideoController controller) async {
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (controller.isPlaying) {
|
||||
await controller.pause();
|
||||
} else {
|
||||
|
|
|
@ -579,11 +579,12 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
|
|||
required AvesVideoController controller,
|
||||
required EntryAction action,
|
||||
}) async {
|
||||
await _videoActionDelegate.onActionSelected(context, entry, controller, action);
|
||||
if (action == EntryAction.videoToggleMute) {
|
||||
final override = controller.isMuted;
|
||||
final override = !controller.isMuted;
|
||||
videoMutedOverride = override;
|
||||
await context.read<VideoConductor>().muteAll(override);
|
||||
} else {
|
||||
await _videoActionDelegate.onActionSelected(context, entry, controller, action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:aves/services/common/services.dart';
|
|||
import 'package:aves/widgets/viewer/video/db_playback_state_handler.dart';
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:aves_video_ijk/aves_video_ijk.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class VideoConductor {
|
||||
|
@ -37,7 +36,7 @@ class VideoConductor {
|
|||
if (controller != null) {
|
||||
_controllers.remove(controller);
|
||||
} else {
|
||||
controller = IjkPlayerAvesVideoController(
|
||||
controller = videoControllerFactory.buildController(
|
||||
entry,
|
||||
playbackStateHandler: playbackStateHandler,
|
||||
settings: settings,
|
||||
|
|
|
@ -1,107 +0,0 @@
|
|||
// import 'dart:async';
|
||||
// import 'dart:io';
|
||||
//
|
||||
// import 'package:aves/model/entry.dart';
|
||||
// import 'package:aves_utils/aves_utils.dart';
|
||||
// import 'package:aves_video/aves_video.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/src/foundation/change_notifier.dart';
|
||||
// import 'package:flutter/src/widgets/framework.dart';
|
||||
// import 'package:flutter_vlc_player/flutter_vlc_player.dart';
|
||||
// import 'package:provider/provider.dart';
|
||||
//
|
||||
// class VlcAvesVideoController extends AvesVideoController {
|
||||
// VlcPlayerController _instance;
|
||||
// final List<StreamSubscription> _subscriptions = [];
|
||||
// final StreamController<VlcPlayerValue> _valueStreamController = StreamController.broadcast();
|
||||
// final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||
//
|
||||
// Stream<VlcPlayerValue> get _valueStream => _valueStreamController.stream;
|
||||
//
|
||||
// VlcAvesVideoController();
|
||||
//
|
||||
// @override
|
||||
// Future<void> setDataSource(String uri, {int startMillis = 0}) async {
|
||||
// _instance = VlcPlayerController.file(
|
||||
// File(uri),
|
||||
// );
|
||||
// _instance.addListener(_onValueChanged);
|
||||
// _subscriptions.add(_valueStream.where((value) => value.isEnded).listen((_) => _playFinishNotifier.notifyListeners()));
|
||||
//
|
||||
// // update value stream to:
|
||||
// // 1) trigger playability check
|
||||
// // 2) show the `VlcPlayer` widget
|
||||
// // 3) initialize its `PlatformView`
|
||||
// // 4) complete `VlcPlayerController` initialization
|
||||
// _valueStreamController.add(_instance.value);
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _instance?.removeListener(_onValueChanged);
|
||||
// _valueStreamController.close();
|
||||
// _subscriptions
|
||||
// ..forEach((sub) => sub.cancel())
|
||||
// ..clear();
|
||||
// _instance?.dispose();
|
||||
// }
|
||||
//
|
||||
// void _onValueChanged() => _valueStreamController.add(_instance.value);
|
||||
//
|
||||
// @override
|
||||
// Future<void> play() => _instance.play();
|
||||
//
|
||||
// @override
|
||||
// Future<void> pause() => _instance?.pause();
|
||||
//
|
||||
// @override
|
||||
// Future<void> seekTo(int targetMillis) => _instance.seekTo(Duration(milliseconds: targetMillis));
|
||||
//
|
||||
// @override
|
||||
// Listenable get playCompletedListenable => _playFinishNotifier;
|
||||
//
|
||||
// @override
|
||||
// VideoStatus get status => _instance?.value?.toAves ?? VideoStatus.idle;
|
||||
//
|
||||
// @override
|
||||
// Stream<VideoStatus> get statusStream => _valueStream.map((value) => value.toAves);
|
||||
//
|
||||
// @override
|
||||
// bool get isPlayable => _instance != null;
|
||||
//
|
||||
// @override
|
||||
// int get duration => _instance?.value?.duration?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// int get currentPosition => _instance?.value?.position?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// Stream<int> get positionStream => _valueStream.map((value) => value.position.inMilliseconds);
|
||||
//
|
||||
// @override
|
||||
// Widget buildPlayerWidget(BuildContext context, AvesEntry entry) {
|
||||
// // do not use `Magnifier` with `applyScale` enabled when using this widget,
|
||||
// // as the original video size will be used to create the `PlatformView`
|
||||
// // and a virtual display larger than the device screen may crash the app
|
||||
// final mqWidth = MediaQuery.sizeOf(context).width;
|
||||
// final displaySize = entry.displaySize;
|
||||
// final ratio = mqWidth / displaySize.width;
|
||||
// return SizedBox.fromSize(
|
||||
// size: displaySize * ratio,
|
||||
// child: VlcPlayer(
|
||||
// controller: _instance,
|
||||
// aspectRatio: entry.displayAspectRatio,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// extension ExtraVlcPlayerValue on VlcPlayerValue {
|
||||
// VideoStatus get toAves {
|
||||
// if (hasError) return VideoStatus.error;
|
||||
// if (!isInitialized) return VideoStatus.idle;
|
||||
// if (isEnded) return VideoStatus.completed;
|
||||
// if (isPlaying) return VideoStatus.playing;
|
||||
// return VideoStatus.paused;
|
||||
// }
|
||||
// }
|
|
@ -1,83 +0,0 @@
|
|||
// import 'dart:async';
|
||||
//
|
||||
// import 'package:aves/model/entry.dart';
|
||||
// import 'package:aves_utils/aves_utils.dart';
|
||||
// import 'package:aves_video/aves_video.dart';
|
||||
// import 'package:flutter/src/foundation/change_notifier.dart';
|
||||
// import 'package:flutter/src/widgets/framework.dart';
|
||||
// import 'package:video_player/video_player.dart';
|
||||
//
|
||||
// class VideoPlayerAvesVideoController extends AvesVideoController {
|
||||
// VideoPlayerController _instance;
|
||||
// final List<StreamSubscription> _subscriptions = [];
|
||||
// final StreamController<VideoPlayerValue> _valueStreamController = StreamController.broadcast();
|
||||
// final AChangeNotifier _playFinishNotifier = AChangeNotifier();
|
||||
//
|
||||
// Stream<VideoPlayerValue> get _valueStream => _valueStreamController.stream;
|
||||
//
|
||||
// VideoPlayerAvesVideoController();
|
||||
//
|
||||
// @override
|
||||
// Future<void> setDataSource(String uri, {int startMillis = 0}) async {
|
||||
// _instance = VideoPlayerController.network(uri);
|
||||
// _instance.addListener(_onValueChanged);
|
||||
// _subscriptions.add(_valueStream.where((value) => value.position > value.duration).listen((_) => _playFinishNotifier.notifyListeners()));
|
||||
//
|
||||
// await _instance.initialize();
|
||||
// await play();
|
||||
// }
|
||||
//
|
||||
// @override
|
||||
// void dispose() {
|
||||
// _instance?.removeListener(_onValueChanged);
|
||||
// _valueStreamController.close();
|
||||
// _subscriptions
|
||||
// ..forEach((sub) => sub.cancel())
|
||||
// ..clear();
|
||||
// _instance?.dispose();
|
||||
// }
|
||||
//
|
||||
// void _onValueChanged() => _valueStreamController.add(_instance.value);
|
||||
//
|
||||
// @override
|
||||
// Future<void> play() => _instance.play();
|
||||
//
|
||||
// @override
|
||||
// Future<void> pause() => _instance?.pause();
|
||||
//
|
||||
// @override
|
||||
// Future<void> seekTo(int targetMillis) => _instance.seekTo(Duration(milliseconds: targetMillis));
|
||||
//
|
||||
// @override
|
||||
// Listenable get playCompletedListenable => _playFinishNotifier;
|
||||
//
|
||||
// @override
|
||||
// VideoStatus get status => _instance?.value?.toAves ?? VideoStatus.idle;
|
||||
//
|
||||
// @override
|
||||
// Stream<VideoStatus> get statusStream => _valueStream.map((value) => value.toAves);
|
||||
//
|
||||
// @override
|
||||
// bool get isPlayable => _instance != null && _instance.value.isInitialized && !_instance.value.hasError;
|
||||
//
|
||||
// @override
|
||||
// int get duration => _instance?.value?.duration?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// int get currentPosition => _instance?.value?.position?.inMilliseconds;
|
||||
//
|
||||
// @override
|
||||
// Stream<int> get positionStream => _valueStream.map((value) => value.position.inMilliseconds);
|
||||
//
|
||||
// @override
|
||||
// Widget buildPlayerWidget(BuildContext context, AvesEntry entry) => VideoPlayer(_instance);
|
||||
// }
|
||||
//
|
||||
// extension ExtraVideoPlayerValue on VideoPlayerValue {
|
||||
// VideoStatus get toAves {
|
||||
// if (hasError) return VideoStatus.error;
|
||||
// if (!isInitialized) return VideoStatus.idle;
|
||||
// if (isPlaying) return VideoStatus.playing;
|
||||
// return VideoStatus.paused;
|
||||
// }
|
||||
// }
|
|
@ -128,7 +128,7 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
|
|||
|
||||
if (videoAutoPlayEnabled) {
|
||||
final resumeTimeMillis = await controller.getResumeTime(context);
|
||||
await _playVideo(controller, () => entry == entryNotifier.value, resumeTimeMillis: resumeTimeMillis);
|
||||
await _autoPlayVideo(controller, () => entry == entryNotifier.value, resumeTimeMillis: resumeTimeMillis);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
|
|||
final pageVideoController = videoConductor.getController(pageEntry);
|
||||
assert(pageVideoController != null);
|
||||
if (pageVideoController != null) {
|
||||
await _playVideo(pageVideoController, () => entry == entryNotifier.value && page == multiPageController.page);
|
||||
await _autoPlayVideo(pageVideoController, () => entry == entryNotifier.value && page == multiPageController.page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _playVideo(AvesVideoController videoController, bool Function() isCurrent, {int? resumeTimeMillis}) async {
|
||||
Future<void> _autoPlayVideo(AvesVideoController videoController, bool Function() isCurrent, {int? resumeTimeMillis}) async {
|
||||
// video decoding may fail or have initial artifacts when the player initializes
|
||||
// during this widget initialization (because of the page transition and hero animation?)
|
||||
// so we play after a delay for increased stability
|
||||
|
@ -204,9 +204,8 @@ mixin EntryViewControllerMixin<T extends StatefulWidget> on State<T> {
|
|||
|
||||
if (resumeTimeMillis != null) {
|
||||
await videoController.seekTo(resumeTimeMillis);
|
||||
} else {
|
||||
await videoController.play();
|
||||
}
|
||||
await videoController.play();
|
||||
|
||||
// playing controllers are paused when the entry changes,
|
||||
// but the controller may still be preparing (not yet playing) when this happens
|
||||
|
|
|
@ -41,10 +41,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -73,10 +73,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_map:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -89,10 +89,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -9,6 +9,8 @@ mixin AvesEntryBase {
|
|||
|
||||
int? get pageId;
|
||||
|
||||
String? get path;
|
||||
|
||||
int? get sizeBytes;
|
||||
|
||||
int? get durationMillis;
|
||||
|
|
|
@ -34,10 +34,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -26,10 +26,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -26,10 +26,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -33,10 +33,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -113,10 +113,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_test:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
|
|
@ -26,10 +26,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -80,10 +80,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_map:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -96,10 +96,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -127,10 +127,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_map:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -220,10 +220,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: google_maps_flutter_web
|
||||
sha256: "5f58d7c491240b0074f455e70ce8d9b038f92472559e49e3b611d9f39b8d51a7"
|
||||
sha256: "280170a2dcac3364317b5786f0d2e3c4128fdb795bc0d87ffe56226b0cf1f57d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0+1"
|
||||
version: "0.5.1"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -236,10 +236,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -441,10 +441,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "1414f27dd781737e51afa9711f2ac2ace6ab4498ee98e20863fa5505aa00c58c"
|
||||
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.4"
|
||||
version: "5.0.5"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -94,10 +94,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_map:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -110,10 +110,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -87,10 +87,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_map:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -103,10 +103,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -26,10 +26,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -26,10 +26,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
library aves_video;
|
||||
|
||||
export 'src/controller.dart';
|
||||
export 'src/metadata.dart';
|
||||
export 'src/settings/subtitles.dart';
|
||||
export 'src/settings/video.dart';
|
||||
export 'src/stream.dart';
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_video/src/settings/video.dart';
|
||||
import 'package:aves_video/src/stream.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
abstract class AvesVideoControllerFactory {
|
||||
void init();
|
||||
|
||||
AvesVideoController buildController(
|
||||
AvesEntryBase entry, {
|
||||
required PlaybackStateHandler playbackStateHandler,
|
||||
required VideoSettings settings,
|
||||
});
|
||||
}
|
||||
|
||||
abstract class AvesVideoController {
|
||||
final AvesEntryBase _entry;
|
||||
final PlaybackStateHandler playbackStateHandler;
|
||||
|
@ -44,7 +53,7 @@ abstract class AvesVideoController {
|
|||
|
||||
Future<void> seekTo(int targetMillis);
|
||||
|
||||
Future<void> seekToProgress(double progress) => seekTo((duration * progress).toInt());
|
||||
Future<void> seekToProgress(double progress) => seekTo((duration * progress.clamp(0, 1)).toInt());
|
||||
|
||||
Listenable get playCompletedListenable;
|
||||
|
||||
|
@ -58,6 +67,18 @@ abstract class AvesVideoController {
|
|||
|
||||
bool get isReady;
|
||||
|
||||
Future<void> get untilReady {
|
||||
if (isReady) return Future.value();
|
||||
|
||||
final completer = Completer();
|
||||
late StreamSubscription<VideoStatus> sub;
|
||||
sub = statusStream.where((_) => isReady).listen((_) {
|
||||
sub.cancel();
|
||||
completer.complete();
|
||||
});
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
bool get isPlaying => status == VideoStatus.playing;
|
||||
|
||||
int get duration;
|
||||
|
|
9
plugins/aves_video/lib/src/metadata.dart
Normal file
9
plugins/aves_video/lib/src/metadata.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
|
||||
abstract class AvesVideoMetadataFetcher {
|
||||
void init();
|
||||
|
||||
Future<Map> getMetadata(AvesEntryBase entry);
|
||||
}
|
|
@ -18,5 +18,5 @@ class MediaStreamSummary {
|
|||
});
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType#${shortHash(this)}{type: type, index: $index, codecName: $codecName, language: $language, title: $title, width: $width, height: $height}';
|
||||
String toString() => '$runtimeType#${shortHash(this)}{type: $type, index: $index, codecName: $codecName, language: $language, title: $title, width: $width, height: $height}';
|
||||
}
|
||||
|
|
|
@ -48,10 +48,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
library aves_video_ijk;
|
||||
|
||||
export 'src/controller.dart';
|
||||
export 'src/factory.dart';
|
||||
export 'src/metadata.dart';
|
||||
|
|
|
@ -8,9 +8,7 @@ import 'package:fijkplayer/fijkplayer.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class IjkPlayerAvesVideoController extends AvesVideoController {
|
||||
static bool _initializedFijkLog = false;
|
||||
|
||||
class IjkVideoController extends AvesVideoController {
|
||||
final EventChannel _eventChannel = const OptionalEventChannel('befovy.com/fijk/event');
|
||||
|
||||
late FijkPlayer _instance;
|
||||
|
@ -21,7 +19,6 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
final StreamController<double> _speedStreamController = StreamController.broadcast();
|
||||
final AChangeNotifier _completedNotifier = AChangeNotifier();
|
||||
Offset _macroBlockCrop = Offset.zero;
|
||||
final List<MediaStreamSummary> _streams = [];
|
||||
Timer? _initialPlayTimer;
|
||||
double _speed = 1;
|
||||
double _volume = 1;
|
||||
|
@ -58,15 +55,11 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
static const gifLikeBitRateThreshold = 2 << 18; // 512kB/s (4Mb/s)
|
||||
static const captureFrameEnabled = true;
|
||||
|
||||
IjkPlayerAvesVideoController(
|
||||
IjkVideoController(
|
||||
super.entry, {
|
||||
required super.playbackStateHandler,
|
||||
required super.settings,
|
||||
}) {
|
||||
if (!_initializedFijkLog) {
|
||||
_initializedFijkLog = true;
|
||||
FijkLog.setLevel(FijkLogLevel.Warn);
|
||||
}
|
||||
_instance = FijkPlayer();
|
||||
_valueStream.map((value) => value.videoRenderStart).firstWhere((v) => v, orElse: () => false).then(
|
||||
(started) {
|
||||
|
@ -123,7 +116,7 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
}
|
||||
|
||||
sarNotifier.value = 1;
|
||||
_streams.clear();
|
||||
streams.clear();
|
||||
_applyOptions(startMillis);
|
||||
|
||||
// calling `setDataSource()` with `autoPlay` starts as soon as possible, but often yields initial artifacts
|
||||
|
@ -247,56 +240,6 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
return true;
|
||||
}
|
||||
|
||||
void _fetchStreams() async {
|
||||
final mediaInfo = await _instance.getInfo();
|
||||
if (!mediaInfo.containsKey(Keys.streams)) return;
|
||||
|
||||
var videoStreamCount = 0, audioStreamCount = 0, textStreamCount = 0;
|
||||
|
||||
_streams.clear();
|
||||
final allStreams = (mediaInfo[Keys.streams] as List).cast<Map>();
|
||||
allStreams.forEach((stream) {
|
||||
final type = ExtraStreamType.fromTypeString(stream[Keys.streamType]);
|
||||
if (type != null) {
|
||||
final width = stream[Keys.width] as int?;
|
||||
final height = stream[Keys.height] as int?;
|
||||
_streams.add(MediaStreamSummary(
|
||||
type: type,
|
||||
index: stream[Keys.index],
|
||||
codecName: stream[Keys.codecName],
|
||||
language: stream[Keys.language],
|
||||
title: stream[Keys.title],
|
||||
width: width,
|
||||
height: height,
|
||||
));
|
||||
switch (type) {
|
||||
case MediaStreamType.video:
|
||||
// check width/height to exclude image streams (that are included among video streams)
|
||||
if (width != null && height != null) {
|
||||
videoStreamCount++;
|
||||
}
|
||||
case MediaStreamType.audio:
|
||||
audioStreamCount++;
|
||||
case MediaStreamType.text:
|
||||
textStreamCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
canSelectStreamNotifier.value = videoStreamCount > 1 || audioStreamCount > 1 || textStreamCount > 0;
|
||||
|
||||
final selectedVideo = await getSelectedStream(MediaStreamType.video);
|
||||
if (selectedVideo != null) {
|
||||
final streamIndex = selectedVideo.index;
|
||||
final streamInfo = allStreams.firstWhereOrNull((stream) => stream[Keys.index] == streamIndex);
|
||||
if (streamInfo != null) {
|
||||
final num = streamInfo[Keys.sarNum] ?? 0;
|
||||
final den = streamInfo[Keys.sarDen] ?? 0;
|
||||
sarNotifier.value = (num != 0 ? num : 1) / (den != 0 ? den : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cf https://developer.android.com/reference/android/media/AudioManager
|
||||
static const int _audioFocusLoss = -1;
|
||||
static const int _audioFocusRequestFailed = 0;
|
||||
|
@ -321,7 +264,7 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
}
|
||||
|
||||
void _onValueChanged() {
|
||||
if (_instance.state == FijkState.prepared && _streams.isEmpty) {
|
||||
if (_instance.state == FijkState.prepared && streams.isEmpty) {
|
||||
_fetchStreams();
|
||||
}
|
||||
_valueStreamController.add(_instance.value);
|
||||
|
@ -427,39 +370,6 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
// TODO TLAD [video] bug: setting speed fails when there is no audio stream or audio is disabled
|
||||
Future<void> _applySpeed() => _instance.setSpeed(speed);
|
||||
|
||||
// When a stream is selected, the video accelerates to catch up with it.
|
||||
// The duration of this acceleration phase depends on the player `min-frames` parameter.
|
||||
// Calling `seekTo` after stream de/selection is a workaround to:
|
||||
// 1) prevent video stream acceleration to catch up with audio
|
||||
// 2) apply timed text stream
|
||||
@override
|
||||
Future<void> selectStream(MediaStreamType type, MediaStreamSummary? selected) async {
|
||||
final current = await getSelectedStream(type);
|
||||
if (current != selected) {
|
||||
if (selected != null) {
|
||||
final newIndex = selected.index;
|
||||
if (newIndex != null) {
|
||||
await _instance.selectTrack(newIndex);
|
||||
}
|
||||
} else if (current != null) {
|
||||
await _instance.deselectTrack(current.index!);
|
||||
}
|
||||
if (type == MediaStreamType.text) {
|
||||
_timedTextStreamController.add(null);
|
||||
}
|
||||
await seekTo(currentPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MediaStreamSummary?> getSelectedStream(MediaStreamType type) async {
|
||||
final currentIndex = await _instance.getSelectedTrack(type.code);
|
||||
return currentIndex != -1 ? _streams.firstWhereOrNull((v) => v.index == currentIndex) : null;
|
||||
}
|
||||
|
||||
@override
|
||||
List<MediaStreamSummary> get streams => _streams;
|
||||
|
||||
@override
|
||||
Future<Uint8List> captureFrame() {
|
||||
if (!_instance.value.videoRenderStart) {
|
||||
|
@ -503,6 +413,93 @@ class IjkPlayerAvesVideoController extends AvesVideoController {
|
|||
return Alignment.topLeft;
|
||||
}
|
||||
}
|
||||
|
||||
// streams (aka tracks)
|
||||
|
||||
final List<MediaStreamSummary> _streams = [];
|
||||
|
||||
@override
|
||||
List<MediaStreamSummary> get streams => _streams;
|
||||
|
||||
void _fetchStreams() async {
|
||||
final mediaInfo = await _instance.getInfo();
|
||||
if (!mediaInfo.containsKey(Keys.streams)) return;
|
||||
|
||||
var videoStreamCount = 0, audioStreamCount = 0, textStreamCount = 0;
|
||||
|
||||
_streams.clear();
|
||||
final allStreams = (mediaInfo[Keys.streams] as List).cast<Map>();
|
||||
allStreams.forEach((stream) {
|
||||
final type = ExtraStreamType.fromTypeString(stream[Keys.streamType]);
|
||||
if (type != null) {
|
||||
final width = stream[Keys.width] as int?;
|
||||
final height = stream[Keys.height] as int?;
|
||||
_streams.add(MediaStreamSummary(
|
||||
type: type,
|
||||
index: stream[Keys.index],
|
||||
codecName: stream[Keys.codecName],
|
||||
language: stream[Keys.language],
|
||||
title: stream[Keys.title],
|
||||
width: width,
|
||||
height: height,
|
||||
));
|
||||
switch (type) {
|
||||
case MediaStreamType.video:
|
||||
// check width/height to exclude image streams (that are included among video streams)
|
||||
if (width != null && height != null) {
|
||||
videoStreamCount++;
|
||||
}
|
||||
case MediaStreamType.audio:
|
||||
audioStreamCount++;
|
||||
case MediaStreamType.text:
|
||||
textStreamCount++;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
canSelectStreamNotifier.value = videoStreamCount > 1 || audioStreamCount > 1 || textStreamCount > 0;
|
||||
|
||||
final selectedVideo = await getSelectedStream(MediaStreamType.video);
|
||||
if (selectedVideo != null) {
|
||||
final streamIndex = selectedVideo.index;
|
||||
final streamInfo = allStreams.firstWhereOrNull((stream) => stream[Keys.index] == streamIndex);
|
||||
if (streamInfo != null) {
|
||||
final num = streamInfo[Keys.sarNum] ?? 0;
|
||||
final den = streamInfo[Keys.sarDen] ?? 0;
|
||||
sarNotifier.value = (num != 0 ? num : 1) / (den != 0 ? den : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MediaStreamSummary?> getSelectedStream(MediaStreamType type) async {
|
||||
final currentIndex = await _instance.getSelectedTrack(type.code);
|
||||
return currentIndex != -1 ? _streams.firstWhereOrNull((v) => v.index == currentIndex) : null;
|
||||
}
|
||||
|
||||
// When a stream is selected, the video accelerates to catch up with it.
|
||||
// The duration of this acceleration phase depends on the player `min-frames` parameter.
|
||||
// Calling `seekTo` after stream de/selection is a workaround to:
|
||||
// 1) prevent video stream acceleration to catch up with audio
|
||||
// 2) apply timed text stream
|
||||
@override
|
||||
Future<void> selectStream(MediaStreamType type, MediaStreamSummary? selected) async {
|
||||
final current = await getSelectedStream(type);
|
||||
if (current == selected) return;
|
||||
|
||||
if (selected != null) {
|
||||
final newIndex = selected.index;
|
||||
if (newIndex != null) {
|
||||
await _instance.selectTrack(newIndex);
|
||||
}
|
||||
} else if (current != null) {
|
||||
await _instance.deselectTrack(current.index!);
|
||||
}
|
||||
if (type == MediaStreamType.text) {
|
||||
_timedTextStreamController.add(null);
|
||||
}
|
||||
await seekTo(currentPosition);
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtraIjkStatus on FijkState {
|
||||
|
|
21
plugins/aves_video_ijk/lib/src/factory.dart
Normal file
21
plugins/aves_video_ijk/lib/src/factory.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:aves_video_ijk/aves_video_ijk.dart';
|
||||
import 'package:fijkplayer/fijkplayer.dart';
|
||||
|
||||
class IjkVideoControllerFactory extends AvesVideoControllerFactory {
|
||||
@override
|
||||
void init() => FijkLog.setLevel(FijkLogLevel.Warn);
|
||||
|
||||
@override
|
||||
AvesVideoController buildController(
|
||||
AvesEntryBase entry, {
|
||||
required PlaybackStateHandler playbackStateHandler,
|
||||
required VideoSettings settings,
|
||||
}) =>
|
||||
IjkVideoController(
|
||||
entry,
|
||||
playbackStateHandler: playbackStateHandler,
|
||||
settings: settings,
|
||||
);
|
||||
}
|
23
plugins/aves_video_ijk/lib/src/metadata.dart
Normal file
23
plugins/aves_video_ijk/lib/src/metadata.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:aves_video_ijk/aves_video_ijk.dart';
|
||||
import 'package:fijkplayer/fijkplayer.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class IjkVideoMetadataFetcher extends AvesVideoMetadataFetcher {
|
||||
@override
|
||||
void init() => FijkLog.setLevel(FijkLogLevel.Warn);
|
||||
|
||||
@override
|
||||
Future<Map> getMetadata(AvesEntryBase entry) async {
|
||||
final player = FijkPlayer();
|
||||
final info = await player.setDataSourceUntilPrepared(entry.uri).then((v) {
|
||||
return player.getInfo();
|
||||
}).catchError((error) {
|
||||
debugPrint('failed to get video metadata for entry=$entry, error=$error');
|
||||
return {};
|
||||
});
|
||||
await player.release();
|
||||
return info;
|
||||
}
|
||||
}
|
|
@ -64,10 +64,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
30
plugins/aves_video_mpv/.gitignore
vendored
Normal file
30
plugins/aves_video_mpv/.gitignore
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
#/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.packages
|
||||
build/
|
10
plugins/aves_video_mpv/.metadata
Normal file
10
plugins/aves_video_mpv/.metadata
Normal file
|
@ -0,0 +1,10 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 796c8ef79279f9c774545b3771238c3098dbefab
|
||||
channel: stable
|
||||
|
||||
project_type: package
|
1
plugins/aves_video_mpv/analysis_options.yaml
Normal file
1
plugins/aves_video_mpv/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
include: ../../analysis_options.yaml
|
4
plugins/aves_video_mpv/lib/aves_video_mpv.dart
Normal file
4
plugins/aves_video_mpv/lib/aves_video_mpv.dart
Normal file
|
@ -0,0 +1,4 @@
|
|||
library aves_video_mpv;
|
||||
|
||||
export 'src/controller.dart';
|
||||
export 'src/factory.dart';
|
368
plugins/aves_video_mpv/lib/src/controller.dart
Normal file
368
plugins/aves_video_mpv/lib/src/controller.dart
Normal file
|
@ -0,0 +1,368 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_utils/aves_utils.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
|
||||
class MpvVideoController extends AvesVideoController {
|
||||
late Player _instance;
|
||||
late VideoController _controller;
|
||||
late VideoStatus _status;
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
final StreamController<VideoStatus> _statusStreamController = StreamController.broadcast();
|
||||
final StreamController<String?> _timedTextStreamController = StreamController.broadcast();
|
||||
final AChangeNotifier _completedNotifier = AChangeNotifier();
|
||||
|
||||
@override
|
||||
double get minSpeed => .25;
|
||||
|
||||
@override
|
||||
double get maxSpeed => 4;
|
||||
|
||||
@override
|
||||
final ValueNotifier<bool> canCaptureFrameNotifier = ValueNotifier(false);
|
||||
|
||||
@override
|
||||
final ValueNotifier<bool> canMuteNotifier = ValueNotifier(true);
|
||||
|
||||
@override
|
||||
final ValueNotifier<bool> canSetSpeedNotifier = ValueNotifier(true);
|
||||
|
||||
@override
|
||||
final ValueNotifier<bool> canSelectStreamNotifier = ValueNotifier(false);
|
||||
|
||||
@override
|
||||
final ValueNotifier<double> sarNotifier = ValueNotifier(1);
|
||||
|
||||
MpvVideoController(
|
||||
super.entry, {
|
||||
required super.playbackStateHandler,
|
||||
required super.settings,
|
||||
}) {
|
||||
_status = VideoStatus.idle;
|
||||
_statusStreamController.add(_status);
|
||||
|
||||
_instance = Player(
|
||||
configuration: const PlayerConfiguration(
|
||||
logLevel: MPVLogLevel.warn,
|
||||
),
|
||||
);
|
||||
_initController();
|
||||
_init();
|
||||
|
||||
// TODO TLAD listening
|
||||
// canCaptureFrameNotifier.value = captureFrameEnabled && started;
|
||||
_startListening();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
await super.dispose();
|
||||
_stopListening();
|
||||
_stopStreamFetchTimer();
|
||||
await _statusStreamController.close();
|
||||
await _timedTextStreamController.close();
|
||||
await _instance.dispose();
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_subscriptions.add(statusStream.listen((v) => _status = v));
|
||||
_subscriptions.add(_instance.stream.completed.listen((v) {
|
||||
if (v) {
|
||||
_statusStreamController.add(VideoStatus.completed);
|
||||
_completedNotifier.notify();
|
||||
}
|
||||
}));
|
||||
_subscriptions.add(_instance.stream.playing.listen((v) {
|
||||
if (status == VideoStatus.idle) return;
|
||||
_statusStreamController.add(v ? VideoStatus.playing : VideoStatus.paused);
|
||||
}));
|
||||
_subscriptions.add(_instance.stream.log.listen((v) => debugPrint('libmpv log: $v')));
|
||||
_subscriptions.add(_instance.stream.error.listen((v) => debugPrint('libmpv error: $v')));
|
||||
_subscriptions.add(settings.updateStream.where((event) => event.key == SettingKeys.enableVideoHardwareAccelerationKey).listen((_) => _initController()));
|
||||
_subscriptions.add(settings.updateStream.where((event) => event.key == SettingKeys.videoLoopModeKey).listen((_) => _applyLoop()));
|
||||
}
|
||||
|
||||
void _stopListening() {
|
||||
_subscriptions
|
||||
..forEach((sub) => sub.cancel())
|
||||
..clear();
|
||||
}
|
||||
|
||||
Future<void> _applyLoop() async {
|
||||
final loopEnabled = settings.videoLoopMode.shouldLoop(entry.durationMillis);
|
||||
await _instance.setPlaylistMode(loopEnabled ? PlaylistMode.single : PlaylistMode.none);
|
||||
}
|
||||
|
||||
Future<void> _init({int startMillis = 0}) async {
|
||||
final playing = _instance.state.playing;
|
||||
|
||||
await _applyLoop();
|
||||
await _instance.open(Media(entry.uri), play: playing);
|
||||
if (startMillis > 0) {
|
||||
await seekTo(startMillis);
|
||||
}
|
||||
|
||||
_fetchStreams();
|
||||
_statusStreamController.add(_instance.state.playing ? VideoStatus.playing : VideoStatus.paused);
|
||||
}
|
||||
|
||||
void _initController() {
|
||||
_controller = VideoController(
|
||||
_instance,
|
||||
configuration: VideoControllerConfiguration(
|
||||
enableHardwareAcceleration: settings.enableVideoHardwareAcceleration,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onVisualChanged() => _init(startMillis: currentPosition);
|
||||
|
||||
@override
|
||||
Future<void> play() async {
|
||||
await untilReady;
|
||||
await _instance.play();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> pause() => _instance.pause();
|
||||
|
||||
@override
|
||||
Future<void> seekTo(int targetMillis) async {
|
||||
if (!isReady) {
|
||||
await untilReady;
|
||||
// When the player gets ready, it can play from the beginning right away,
|
||||
// but trying to seek then just plays from the start.
|
||||
// There is no state or hook identifying readiness to seek on start,
|
||||
// and `PlayerConfiguration.ready` hook is useless.
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
}
|
||||
await _instance.seek(Duration(milliseconds: targetMillis));
|
||||
}
|
||||
|
||||
@override
|
||||
Listenable get playCompletedListenable => _completedNotifier;
|
||||
|
||||
@override
|
||||
VideoStatus get status => _status;
|
||||
|
||||
@override
|
||||
Stream<VideoStatus> get statusStream => _statusStreamController.stream;
|
||||
|
||||
@override
|
||||
Stream<double> get volumeStream => _instance.stream.volume;
|
||||
|
||||
@override
|
||||
Stream<double> get speedStream => _instance.stream.rate;
|
||||
|
||||
@override
|
||||
bool get isReady {
|
||||
switch (_status) {
|
||||
case VideoStatus.error:
|
||||
case VideoStatus.idle:
|
||||
case VideoStatus.initialized:
|
||||
return false;
|
||||
case VideoStatus.paused:
|
||||
case VideoStatus.playing:
|
||||
case VideoStatus.completed:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
int get duration => _instance.state.duration.inMilliseconds;
|
||||
|
||||
@override
|
||||
int get currentPosition => _instance.state.position.inMilliseconds;
|
||||
|
||||
@override
|
||||
Stream<int> get positionStream => _instance.stream.position.map((pos) => pos.inMilliseconds);
|
||||
|
||||
@override
|
||||
Stream<String?> get timedTextStream => _timedTextStreamController.stream;
|
||||
|
||||
@override
|
||||
bool get isMuted => _instance.state.volume == 0;
|
||||
|
||||
@override
|
||||
Future<void> mute(bool muted) => _instance.setVolume(muted ? 0 : 100);
|
||||
|
||||
@override
|
||||
double get speed => _instance.state.rate;
|
||||
|
||||
@override
|
||||
set speed(double speed) => _instance.setRate(speed);
|
||||
|
||||
@override
|
||||
Future<Uint8List> captureFrame() {
|
||||
// TODO: implement captureFrame
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildPlayerWidget(BuildContext context) {
|
||||
// TODO TLAD handle SAR / DAR (media_kit Player.stream.width/height just gives raw video size, not rendered size)
|
||||
return Video(
|
||||
controller: _controller,
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.center,
|
||||
controls: NoVideoControls,
|
||||
wakelock: false,
|
||||
);
|
||||
}
|
||||
|
||||
// streams (aka tracks)
|
||||
|
||||
// `auto` and `no` are the first 2 tracks in the player state track lists
|
||||
static const int fakeTrackCount = 2;
|
||||
|
||||
Tracks get _tracks => _instance.state.tracks;
|
||||
|
||||
List<VideoTrack> get _videoTracks => _tracks.video.skip(fakeTrackCount).toList();
|
||||
|
||||
List<AudioTrack> get _audioTracks => _tracks.audio.skip(fakeTrackCount).toList();
|
||||
|
||||
List<SubtitleTrack> get _subtitleTracks => _tracks.subtitle.skip(fakeTrackCount).toList();
|
||||
|
||||
@override
|
||||
List<MediaStreamSummary> get streams {
|
||||
return {
|
||||
..._videoTracks.mapIndexed((i, v) => v.toAves(i)),
|
||||
..._audioTracks.mapIndexed((i, v) => v.toAves(i)),
|
||||
..._subtitleTracks.mapIndexed((i, v) => v.toAves(i)),
|
||||
}.toList();
|
||||
}
|
||||
|
||||
Timer? _streamFetchTimer;
|
||||
|
||||
void _stopStreamFetchTimer() {
|
||||
_streamFetchTimer?.cancel();
|
||||
_streamFetchTimer = null;
|
||||
}
|
||||
|
||||
void _fetchStreams() {
|
||||
_stopStreamFetchTimer();
|
||||
_streamFetchTimer = Timer.periodic(const Duration(milliseconds: 100), (_) {
|
||||
if (status != VideoStatus.error) {
|
||||
if (_videoTracks.isEmpty && _audioTracks.isEmpty) return;
|
||||
|
||||
final videoStreamCount = _videoTracks.length;
|
||||
final audioStreamCount = _audioTracks.length;
|
||||
final textStreamCount = _subtitleTracks.length;
|
||||
canSelectStreamNotifier.value = videoStreamCount > 1 || audioStreamCount > 1 || textStreamCount > 0;
|
||||
}
|
||||
_stopStreamFetchTimer();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MediaStreamSummary?> getSelectedStream(MediaStreamType type) async {
|
||||
final track = _instance.state.track;
|
||||
switch (type) {
|
||||
case MediaStreamType.video:
|
||||
final video = track.video;
|
||||
if (video != VideoTrack.no()) {
|
||||
final index = video == VideoTrack.auto() ? 0 : _videoTracks.indexOf(video);
|
||||
return video.toAves(index);
|
||||
}
|
||||
case MediaStreamType.audio:
|
||||
final audio = track.audio;
|
||||
if (audio != AudioTrack.no()) {
|
||||
final index = audio == AudioTrack.auto() ? 0 : _audioTracks.indexOf(audio);
|
||||
return audio.toAves(index);
|
||||
}
|
||||
case MediaStreamType.text:
|
||||
final subtitle = track.subtitle;
|
||||
if (subtitle != SubtitleTrack.no()) {
|
||||
final index = subtitle == SubtitleTrack.auto() ? 0 : _subtitleTracks.indexOf(subtitle);
|
||||
return subtitle.toAves(index);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> selectStream(MediaStreamType type, MediaStreamSummary? selected) async {
|
||||
final current = await getSelectedStream(type);
|
||||
if (current == selected) return;
|
||||
|
||||
if (selected != null) {
|
||||
final newIndex = selected.index;
|
||||
if (newIndex != null) {
|
||||
// select track
|
||||
switch (type) {
|
||||
case MediaStreamType.video:
|
||||
await _instance.setVideoTrack(_videoTracks[selected.index ?? 0]);
|
||||
break;
|
||||
case MediaStreamType.audio:
|
||||
await _instance.setAudioTrack(_audioTracks[selected.index ?? 0]);
|
||||
break;
|
||||
case MediaStreamType.text:
|
||||
await _instance.setSubtitleTrack(_subtitleTracks[selected.index ?? 0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (current != null) {
|
||||
// deselect track
|
||||
switch (type) {
|
||||
case MediaStreamType.video:
|
||||
await _instance.setVideoTrack(VideoTrack.no());
|
||||
break;
|
||||
case MediaStreamType.audio:
|
||||
await _instance.setAudioTrack(AudioTrack.no());
|
||||
break;
|
||||
case MediaStreamType.text:
|
||||
await _instance.setSubtitleTrack(SubtitleTrack.no());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtraVideoTrack on VideoTrack {
|
||||
MediaStreamSummary toAves(int index) {
|
||||
return MediaStreamSummary(
|
||||
type: MediaStreamType.video,
|
||||
index: index,
|
||||
codecName: null,
|
||||
language: language,
|
||||
title: title,
|
||||
width: null,
|
||||
height: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtraAudioTrack on AudioTrack {
|
||||
MediaStreamSummary toAves(int index) {
|
||||
return MediaStreamSummary(
|
||||
type: MediaStreamType.audio,
|
||||
index: index,
|
||||
codecName: null,
|
||||
language: language,
|
||||
title: title,
|
||||
width: null,
|
||||
height: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension ExtraSubtitleTrack on SubtitleTrack {
|
||||
MediaStreamSummary toAves(int index) {
|
||||
return MediaStreamSummary(
|
||||
type: MediaStreamType.text,
|
||||
index: index,
|
||||
codecName: null,
|
||||
language: language,
|
||||
title: title,
|
||||
width: null,
|
||||
height: null,
|
||||
);
|
||||
}
|
||||
}
|
21
plugins/aves_video_mpv/lib/src/factory.dart
Normal file
21
plugins/aves_video_mpv/lib/src/factory.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:aves_model/aves_model.dart';
|
||||
import 'package:aves_video/aves_video.dart';
|
||||
import 'package:aves_video_mpv/aves_video_mpv.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
class MpvVideoControllerFactory extends AvesVideoControllerFactory {
|
||||
@override
|
||||
void init() => MediaKit.ensureInitialized();
|
||||
|
||||
@override
|
||||
AvesVideoController buildController(
|
||||
AvesEntryBase entry, {
|
||||
required PlaybackStateHandler playbackStateHandler,
|
||||
required VideoSettings settings,
|
||||
}) =>
|
||||
MpvVideoController(
|
||||
entry,
|
||||
playbackStateHandler: playbackStateHandler,
|
||||
settings: settings,
|
||||
);
|
||||
}
|
362
plugins/aves_video_mpv/pubspec.lock
Normal file
362
plugins/aves_video_mpv/pubspec.lock
Normal file
|
@ -0,0 +1,362 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
aves_model:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../aves_model"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
aves_utils:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../aves_utils"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
aves_video:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../aves_video"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
collection:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.1"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: equatable
|
||||
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
media_kit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit
|
||||
sha256: "8c7d9417bed724a3fcaadd91c722fea042737cafb153aa1f1e6461a0fee683a3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
media_kit_libs_android_video:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit_libs_android_video
|
||||
sha256: "228c3b182831e194bb178d4d22a1839af812c917cb76fe87d6fdc9ea4328dc81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
media_kit_native_event_loop:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit_native_event_loop
|
||||
sha256: "5351f0c28124b5358756515d8619abad182cdefe967468d7fb5b274737cc2f59"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
media_kit_video:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: media_kit_video
|
||||
sha256: d31a0eab80cafadccdedb663d8a127750e38b8c75c1aa83d8943f8119b88cf99
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
safe_local_storage:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: safe_local_storage
|
||||
sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
screen_brightness:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness
|
||||
sha256: "62fd61a64e68b32b98b840bad7d8b6822bbc40e63c2b569a5f85528484c86b41"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
screen_brightness_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness_android
|
||||
sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0+2"
|
||||
screen_brightness_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness_ios
|
||||
sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
screen_brightness_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness_macos
|
||||
sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0+1"
|
||||
screen_brightness_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness_platform_interface
|
||||
sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
screen_brightness_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: screen_brightness_windows
|
||||
sha256: "80d90ecdc63fc0823f2ecb1be323471619287937e14210650d7b25ca181abd05"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
universal_platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: universal_platform
|
||||
sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0+1"
|
||||
uri_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uri_parser
|
||||
sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: volume_controller
|
||||
sha256: "189bdc7a554f476b412e4c8b2f474562b09d74bc458c23667356bce3ca1d48c9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.7"
|
||||
wakelock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock
|
||||
sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.2"
|
||||
wakelock_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_macos
|
||||
sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
wakelock_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_platform_interface
|
||||
sha256: "1f4aeb81fb592b863da83d2d0f7b8196067451e4df91046c26b54a403f9de621"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
wakelock_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_web
|
||||
sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
wakelock_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: wakelock_windows
|
||||
sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
sdks:
|
||||
dart: ">=3.0.0 <4.0.0"
|
||||
flutter: ">=3.7.0"
|
36
plugins/aves_video_mpv/pubspec.yaml
Normal file
36
plugins/aves_video_mpv/pubspec.yaml
Normal file
|
@ -0,0 +1,36 @@
|
|||
name: aves_video_mpv
|
||||
version: 0.0.1
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
aves_model:
|
||||
path: ../aves_model
|
||||
aves_video:
|
||||
path: ../aves_video
|
||||
aves_utils:
|
||||
path: ../aves_utils
|
||||
collection:
|
||||
media_kit:
|
||||
media_kit_video:
|
||||
media_kit_native_event_loop:
|
||||
media_kit_libs_android_video:
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints:
|
||||
|
||||
#dependency_overrides:
|
||||
# media_kit:
|
||||
# path: ../../../media_kit/media_kit
|
||||
# media_kit_video:
|
||||
# path: ../../../media_kit/media_kit_video
|
||||
# media_kit_native_event_loop:
|
||||
# path: ../../../media_kit/media_kit_native_event_loop
|
||||
# media_kit_libs_android_video:
|
||||
# path: ../../../media_kit/media_kit_libs_android_video
|
||||
|
||||
flutter:
|
95
pubspec.lock
95
pubspec.lock
|
@ -299,10 +299,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: dynamic_color
|
||||
sha256: "74dff1435a695887ca64899b8990004f8d1232b0e84bfc4faa1fdda7c6f57cc1"
|
||||
sha256: de4798a7069121aee12d5895315680258415de9b00e717723a1bd73d58f0126d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.5"
|
||||
version: "1.6.6"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -345,7 +345,7 @@ packages:
|
|||
source: hosted
|
||||
version: "2.0.2"
|
||||
fijkplayer:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: aves
|
||||
|
@ -413,19 +413,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: flex_seed_scheme
|
||||
sha256: e4168a6fc88a3e5bc3d6b7a748c6a6083eedc193d343ddc26bbad7fb1b258555
|
||||
sha256: "29c12aba221eb8a368a119685371381f8035011d18de5ba277ad11d7dfb8657f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
floating:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: b073419d48f099b5855816a7c6e04d397b1f1c37
|
||||
url: "https://github.com/wrbl606/floating.git"
|
||||
source: git
|
||||
version: "2.0.0"
|
||||
name: floating
|
||||
sha256: d9d563089e34fbd714ffdcdd2df447ec41b40c9226dacae6b4f78847aef8b991
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
fluster:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -472,10 +471,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
|
||||
sha256: "2118df84ef0c3ca93f96123a616ae8540879991b8b57af2f81b76a7ada49b2a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.2"
|
||||
flutter_localization_nn:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -502,10 +501,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: dc6d5258653f6857135b32896ccda7f7af0c54dcec832495ad6835154c6c77c0
|
||||
sha256: "86b76dbf30496024d6c816bdc13b97de9449dce1f035a73ee7b4ab7f67eab70b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.15"
|
||||
version: "0.6.16"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -629,10 +628,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: google_maps_flutter_web
|
||||
sha256: "5f58d7c491240b0074f455e70ce8d9b038f92472559e49e3b611d9f39b8d51a7"
|
||||
sha256: "280170a2dcac3364317b5786f0d2e3c4128fdb795bc0d87ffe56226b0cf1f57d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0+1"
|
||||
version: "0.5.1"
|
||||
highlight:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -653,10 +652,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -991,42 +990,42 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: permission_handler
|
||||
sha256: "1b6b3e73f0bcbc856548bbdfb1c33084a401c4f143e220629a9055233d76c331"
|
||||
sha256: "37fcc3c3182ac0bf8856f3e973e11c7bef5556d69f1a0d8fb908f51019c2912d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.3.0"
|
||||
version: "10.4.1"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_android
|
||||
sha256: "8f6a95ccbca13766882f95d32684d7c9bfe6c45650c32bedba948ef1c6a4ddf7"
|
||||
sha256: "3b61f3da3b1c83bc3fb6a2b431e8dab01d0e5b45f6a3d9c7609770ec88b2a89e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.2.3"
|
||||
version: "10.3.0"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_apple
|
||||
sha256: "08dcb6ce628ac0b257e429944b4c652c2a4e6af725bdf12b498daa2c6b2b1edb"
|
||||
sha256: "0d1f8007b17573ff1fbeae0f04b6c8e83e1d2f6c4fe8e8226d4d2456aa8ecffe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.0"
|
||||
version: "9.1.2"
|
||||
permission_handler_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_platform_interface
|
||||
sha256: de20a5c3269229c1ae2e5a6b822f6cb59578b23e8255c93fbeebfc82116e6b11
|
||||
sha256: "79b36d93a41a4aecfd0d635d77552f327cb84227c718ce5e68b5f7b85546fe7e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.0"
|
||||
version: "3.11.0+1"
|
||||
permission_handler_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: permission_handler_windows
|
||||
sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
|
||||
sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
version: "0.1.3"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1039,10 +1038,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: pin_code_fields
|
||||
sha256: c8652519d14688f3fe2a8288d86910a46aa0b9046d728f292d3bf6067c31b4c7
|
||||
sha256: "4c0db7fbc889e622e7c71ea54b9ee624bb70c7365b532abea0271b17ea75b729"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.4.0"
|
||||
version: "8.0.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1191,58 +1190,58 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "396f85b8afc6865182610c0a2fc470853d56499f75f7499e2a73a9f0539d23d0"
|
||||
sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.2.0"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
|
||||
sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.2.0"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
|
||||
sha256: "0dc5c49ad8a05ed358b991b60c7b0ba1a14e16dae58af9b420d6b9e82dc024ab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
version: "2.3.0"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
|
||||
sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.3.0"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
|
||||
sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.3.0"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
|
||||
sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
version: "2.2.0"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
|
||||
sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.3.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1570,13 +1569,13 @@ packages:
|
|||
source: hosted
|
||||
version: "1.2.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: win32
|
||||
sha256: "1414f27dd781737e51afa9711f2ac2ace6ab4498ee98e20863fa5505aa00c58c"
|
||||
sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.4"
|
||||
version: "5.0.5"
|
||||
win32_registry:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
23
pubspec.yaml
23
pubspec.yaml
|
@ -42,6 +42,8 @@ dependencies:
|
|||
path: plugins/aves_video
|
||||
aves_video_ijk:
|
||||
path: plugins/aves_video_ijk
|
||||
# aves_video_mpv:
|
||||
# path: plugins/aves_video_mpv
|
||||
aves_ui:
|
||||
path: plugins/aves_ui
|
||||
aves_utils:
|
||||
|
@ -65,16 +67,8 @@ dependencies:
|
|||
expansion_tile_card:
|
||||
git:
|
||||
url: https://github.com/deckerst/expansion_tile_card.git
|
||||
fijkplayer:
|
||||
git:
|
||||
url: https://github.com/deckerst/fijkplayer.git
|
||||
ref: aves
|
||||
flex_color_picker:
|
||||
floating:
|
||||
git:
|
||||
url: https://github.com/wrbl606/floating.git
|
||||
# v2.0.0 is incompatible with AGP8
|
||||
ref: main
|
||||
fluster:
|
||||
flutter_displaymode:
|
||||
flutter_highlight:
|
||||
|
@ -130,6 +124,19 @@ dev_dependencies:
|
|||
shared_preferences_platform_interface:
|
||||
test:
|
||||
|
||||
dependency_overrides:
|
||||
# `media_kit v1.0.0` depends on `wakelock: ^0.6.2`
|
||||
# which is incompatible with packages that moved on with Dart 3
|
||||
win32: ^5.0.0
|
||||
# media_kit:
|
||||
# path: ../media_kit/media_kit
|
||||
# media_kit_video:
|
||||
# path: ../media_kit/media_kit_video
|
||||
# media_kit_native_event_loop:
|
||||
# path: ../media_kit/media_kit_native_event_loop
|
||||
# media_kit_libs_android_video:
|
||||
# path: ../media_kit/media_kit_libs_android_video
|
||||
|
||||
flutter:
|
||||
assets:
|
||||
- assets/
|
||||
|
|
Loading…
Reference in a new issue