From 3b47c8cf949b3aba70babedb207b2ae0fca83696 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 10 Aug 2024 11:50:55 -0300 Subject: [PATCH 01/24] feat: Create unity_video_player_fvp --- .../unity_video_player_fvp/.gitignore | 29 ++++++++++ .../unity_video_player_fvp/.metadata | 10 ++++ .../unity_video_player_fvp/CHANGELOG.md | 3 ++ .../unity_video_player_fvp/LICENSE | 1 + .../unity_video_player_fvp/README.md | 39 ++++++++++++++ .../analysis_options.yaml | 4 ++ .../lib/unity_video_player_fvp.dart | 7 +++ .../unity_video_player_fvp/pubspec.yaml | 54 +++++++++++++++++++ 8 files changed, 147 insertions(+) create mode 100644 packages/unity_video_player/unity_video_player_fvp/.gitignore create mode 100644 packages/unity_video_player/unity_video_player_fvp/.metadata create mode 100644 packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md create mode 100644 packages/unity_video_player/unity_video_player_fvp/LICENSE create mode 100644 packages/unity_video_player/unity_video_player_fvp/README.md create mode 100644 packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml create mode 100644 packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart create mode 100644 packages/unity_video_player/unity_video_player_fvp/pubspec.yaml diff --git a/packages/unity_video_player/unity_video_player_fvp/.gitignore b/packages/unity_video_player/unity_video_player_fvp/.gitignore new file mode 100644 index 00000000..ac5aa989 --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/.gitignore @@ -0,0 +1,29 @@ +# 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/ +build/ diff --git a/packages/unity_video_player/unity_video_player_fvp/.metadata b/packages/unity_video_player/unity_video_player_fvp/.metadata new file mode 100644 index 00000000..d36dfbcc --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/.metadata @@ -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: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" + channel: "stable" + +project_type: package diff --git a/packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md b/packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md new file mode 100644 index 00000000..41cc7d81 --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/packages/unity_video_player/unity_video_player_fvp/LICENSE b/packages/unity_video_player/unity_video_player_fvp/LICENSE new file mode 100644 index 00000000..ba75c69f --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/unity_video_player/unity_video_player_fvp/README.md b/packages/unity_video_player/unity_video_player_fvp/README.md new file mode 100644 index 00000000..02fe8eca --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml b/packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml new file mode 100644 index 00000000..a5744c1c --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart new file mode 100644 index 00000000..966d01ed --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart @@ -0,0 +1,7 @@ +library unity_video_player_fvp; + +/// A Calculator. +class Calculator { + /// Returns [value] plus 1. + int addOne(int value) => value + 1; +} diff --git a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml new file mode 100644 index 00000000..ae6045e9 --- /dev/null +++ b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml @@ -0,0 +1,54 @@ +name: unity_video_player_fvp +description: "A new Flutter package project." +version: 0.0.1 +homepage: + +environment: + sdk: '>=3.4.1 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages From aa3b25ce4970b9277df59e82362ae4a892f60240 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 10 Aug 2024 11:51:38 -0300 Subject: [PATCH 02/24] chore: Delete unecessary docs --- .../unity_video_player/README.md | 39 ------------------- .../unity_video_player_flutter/README.md | 3 -- .../unity_video_player_fvp/CHANGELOG.md | 3 -- .../unity_video_player_fvp/README.md | 39 ------------------- .../unity_video_player_main/README.md | 1 - .../README.md | 39 ------------------- 6 files changed, 124 deletions(-) delete mode 100644 packages/unity_video_player/unity_video_player/README.md delete mode 100644 packages/unity_video_player/unity_video_player_flutter/README.md delete mode 100644 packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md delete mode 100644 packages/unity_video_player/unity_video_player_fvp/README.md delete mode 100644 packages/unity_video_player/unity_video_player_main/README.md delete mode 100644 packages/unity_video_player/unity_video_player_platform_interface/README.md diff --git a/packages/unity_video_player/unity_video_player/README.md b/packages/unity_video_player/unity_video_player/README.md deleted file mode 100644 index 02fe8eca..00000000 --- a/packages/unity_video_player/unity_video_player/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. diff --git a/packages/unity_video_player/unity_video_player_flutter/README.md b/packages/unity_video_player/unity_video_player_flutter/README.md deleted file mode 100644 index 6d8f7f72..00000000 --- a/packages/unity_video_player/unity_video_player_flutter/README.md +++ /dev/null @@ -1,3 +0,0 @@ -`unity_video_player` imeplementation with `video_player`. - -This was created to be used in the Raspberry Pi, but it should work on any platform. \ No newline at end of file diff --git a/packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md b/packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md deleted file mode 100644 index 41cc7d81..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 0.0.1 - -* TODO: Describe initial release. diff --git a/packages/unity_video_player/unity_video_player_fvp/README.md b/packages/unity_video_player/unity_video_player_fvp/README.md deleted file mode 100644 index 02fe8eca..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. diff --git a/packages/unity_video_player/unity_video_player_main/README.md b/packages/unity_video_player/unity_video_player_main/README.md deleted file mode 100644 index b63191bb..00000000 --- a/packages/unity_video_player/unity_video_player_main/README.md +++ /dev/null @@ -1 +0,0 @@ -`unity_video_player` implementation with `media_kit` \ No newline at end of file diff --git a/packages/unity_video_player/unity_video_player_platform_interface/README.md b/packages/unity_video_player/unity_video_player_platform_interface/README.md deleted file mode 100644 index 02fe8eca..00000000 --- a/packages/unity_video_player/unity_video_player_platform_interface/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. From a06a62fd5cfe9014d92282b2db5035992ad24919 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 10 Aug 2024 12:43:26 -0300 Subject: [PATCH 03/24] feat: Use fvp --- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + .../unity_video_player/pubspec.yaml | 4 +- .../lib/unity_video_player_fvp.dart | 438 +++++++++++++++++- .../unity_video_player_fvp/pubspec.yaml | 55 +-- pubspec.lock | 17 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 9 files changed, 485 insertions(+), 40 deletions(-) diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index c4ad27ae..6dc847c4 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -19,6 +20,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) awesome_notifications_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AwesomeNotificationsPlugin"); awesome_notifications_plugin_register_with_registrar(awesome_notifications_registrar); + g_autoptr(FlPluginRegistrar) fvp_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FvpPlugin"); + fvp_plugin_register_with_registrar(fvp_registrar); g_autoptr(FlPluginRegistrar) gtk_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); gtk_plugin_register_with_registrar(gtk_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 3b009456..06e9c034 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST awesome_notifications + fvp gtk media_kit_libs_linux media_kit_video diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6dbc1bb5..5398a142 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import connectivity_plus import device_info_plus import firebase_core import firebase_messaging +import fvp import media_kit_libs_macos_video import media_kit_video import package_info_plus @@ -30,6 +31,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FvpPlugin.register(with: registry.registrar(forPlugin: "FvpPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) diff --git a/packages/unity_video_player/unity_video_player/pubspec.yaml b/packages/unity_video_player/unity_video_player/pubspec.yaml index f8c8ac98..41a4933a 100644 --- a/packages/unity_video_player/unity_video_player/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player/pubspec.yaml @@ -16,6 +16,8 @@ dependencies: path: ../unity_video_player_main unity_video_player_flutter: path: ../unity_video_player_flutter + unity_video_player_fvp: + path: ../unity_video_player_fvp dev_dependencies: flutter_test: @@ -34,6 +36,6 @@ flutter: linux: default_package: unity_video_player_flutter windows: - default_package: unity_video_player_main + default_package: unity_video_player_fvp web: default_package: unity_video_player_main diff --git a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart index 966d01ed..d74b299f 100644 --- a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart +++ b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart @@ -1,7 +1,437 @@ library unity_video_player_fvp; -/// A Calculator. -class Calculator { - /// Returns [value] plus 1. - int addOne(int value) => value + 1; +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:unity_video_player_platform_interface/unity_video_player_platform_interface.dart'; +import 'package:fvp/mdk.dart'; + +class UnityVideoPlayerFvpInterface extends UnityVideoPlayerInterface { + /// Registers this class as the default instance of [UnityVideoPlayerInterface]. + static void registerWith([registrar]) { + UnityVideoPlayerInterface.instance = UnityVideoPlayerFvpInterface(); + } + + @override + Future initialize() async { + // fvp.registerWith(options: { + // 'platforms': ['windows'] + // }); + } + + @override + UnityVideoPlayer createPlayer({ + int? width, + int? height, + bool enableCache = false, + RTSPProtocol? rtspProtocol, + VoidCallback? onReload, + MatrixType matrixType = MatrixType.t16, + bool softwareZoom = false, + }) { + final player = UnityVideoPlayerFvp( + width: width, + height: height, + enableCache: enableCache, + rtspProtocol: rtspProtocol, + ) + ..zoom.matrixType = matrixType + ..zoom.softwareZoom = softwareZoom + ..onReload = onReload; + UnityVideoPlayerInterface.registerPlayer(player); + return player; + } + + @override + Widget createVideoView({ + Key? key, + required UnityVideoPlayer player, + UnityVideoFit fit = UnityVideoFit.contain, + UnityVideoPaneBuilder? paneBuilder, + UnityVideoBuilder? videoBuilder, + Color color = const Color(0xFF000000), + }) { + videoBuilder ??= (context, video) => video; + final mdkPlayer = (player as UnityVideoPlayerFvp); + + return Builder(builder: (context) { + return Stack(children: [ + Positioned.fill( + child: videoBuilder!( + context, + _MKVideo( + key: ValueKey(player), + mdkPlayer: mdkPlayer, + color: color, + fit: () { + return switch (fit) { + UnityVideoFit.contain => BoxFit.contain, + UnityVideoFit.cover => BoxFit.cover, + UnityVideoFit.fill => BoxFit.fill, + }; + }(), + ), + ), + ), + if (paneBuilder != null) + Positioned.fill( + child: Material( + type: MaterialType.transparency, + child: paneBuilder(context, player), + ), + ), + ]); + }); + } +} + +class _MKVideo extends StatefulWidget { + const _MKVideo({ + super.key, + required this.mdkPlayer, + required this.fit, + required this.color, + }); + + final UnityVideoPlayerFvp mdkPlayer; + final BoxFit fit; + final Color color; + + @override + State<_MKVideo> createState() => _MKVideoState(); +} + +class _MKVideoState extends State<_MKVideo> { + @override + void didUpdateWidget(covariant _MKVideo oldWidget) { + super.didUpdateWidget(oldWidget); + } + + @override + void initState() { + super.initState(); + widget.mdkPlayer.mdkPlayer.updateTexture(); + } + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: widget.mdkPlayer.mdkPlayer.textureId, + builder: (context, id, _) => + id == null ? const SizedBox.shrink() : Texture(textureId: id), + ); + } +} + +class UnityVideoPlayerFvp extends UnityVideoPlayer { + late final Player mdkPlayer; + + double _fps = 0; + @override + double get fps => _fps; + final _fpsStreamController = StreamController.broadcast(); + @override + Stream get fpsStream => _fpsStreamController.stream; + + Size maxSize = Size.zero; + final bool enableCache; + + UnityVideoPlayerFvp({ + super.width, + super.height, + this.enableCache = false, + RTSPProtocol? rtspProtocol, + }) { + mdkPlayer = Player(); + final pixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio; + if (width != null) width = (width! * pixelRatio).toInt(); + if (height != null) height = (height! * pixelRatio).toInt(); + + onLog?.call( + 'Initialized player $title with width=$width and height=$height'); + + // Check type. Only true for libmpv based platforms. Currently Windows & Linux. + // if (!kIsWeb && platform is NativePlayer) { + // platform + // ..observeProperty('estimated-vf-fps', (fps) async { + // _fps = double.parse(fps); + // _fpsStreamController.add(_fps); + // }) + // ..observeProperty('width', (width) async { + // debugPrint('$title: display width: $width/${this.width}'); + // this.width = int.tryParse(width); + // if (this.width != null && this.width! > maxSize.width) { + // maxSize = Size(this.width!.toDouble(), maxSize.height); + // } + // }) + // ..observeProperty('height', (height) async { + // debugPrint('$title: display height: $height/${this.height}'); + // this.height = int.tryParse(height); + // if (this.height != null && this.height! > maxSize.height) { + // maxSize = Size(maxSize.width, this.height!.toDouble()); + // } + // }); + + // mdkPlayer.stream.log.listen((event) { + // final logMessage = '${event.level} | ${event.prefix}: ${event.text}'; + // if (event.level != 'v') debugPrint(logMessage); + // if (event.level == 'fatal') { + // // ignore: invalid_use_of_protected_member + // platform.errorController.add(event.text); + // } + // onLog?.call(logMessage); + // }); + + // // Some servers use self-signed certificates. This is necessary to allow + // // the connection to these servers. + // platform.setProperty('tls-verify', 'no'); + // platform.setProperty('insecure', 'yes'); + + // // Defines the protocol to be used in the RTSP connection. + // if (rtspProtocol != null) { + // platform.setProperty( + // 'rtsp-transport', + // switch (rtspProtocol) { + // RTSPProtocol.tcp => 'tcp', + // RTSPProtocol.udp => 'udp', + // // _ => 'udp_multicast' + // }, + // ); + // } + + // Ensures the stream can be seekable. We use seekable streams to dismiss + // late streams. + // platform.setProperty('force-seekable', 'yes'); + // } + } + + @override + String? get dataSource { + final media = mdkPlayer.media; + return media.isNotEmpty ? media : null; + } + + @override + Stream get onError => const Stream.empty(broadcast: false); + + @override + Duration get duration => Duration(milliseconds: mdkPlayer.mediaInfo.duration); + + @override + Stream get onDurationUpdate => const Stream.empty(broadcast: false); + + @override + Duration get currentPos => Duration(milliseconds: mdkPlayer.position); + + @override + Stream get onCurrentPosUpdate => + const Stream.empty(broadcast: false); + + @override + bool get isBuffering => + mdkPlayer.mediaStatus.rawValue == MediaStatus.buffering; + + @override + Duration get currentBuffer => Duration(milliseconds: mdkPlayer.buffered()); + + @override + Stream get onBufferUpdate => const Stream.empty(broadcast: false); + + @override + bool get isSeekable => duration > Duration.zero; + + @override + Stream get onBufferStateUpdate => const Stream.empty(broadcast: false); + + @override + bool get isPlaying => mdkPlayer.state == PlaybackState.playing; + + @override + Stream get onPlayingStateUpdate => const Stream.empty(broadcast: false); + + /// Gets a property from the media kit player. + /// + /// Do not use this to get the properties of already observed properties. + @override + Future getProperty(String propertyName) async { + return ''; + } + + @override + Future setDataSource(String url, {bool autoPlay = true}) async { + if (url == dataSource) return Future.value(); + debugPrint('Playing $url'); + mdkPlayer.setMedia(url, MediaType.video); + if (autoPlay) start(); + // await mdkPlayer.setPlaylistMode(PlaylistMode.loop); + // // do not use mdkPlayer.add because it doesn't support auto play + // await mdkPlayer.open(Playlist([Media(url)]), play: autoPlay); + } + + @override + Future setMultipleDataSource( + Iterable url, { + bool autoPlay = true, + }) async { + // await mdkPlayer.open( + // Playlist(url.map(Media.new).toList()), + // play: autoPlay, + // ); + setDataSource(url.first); + } + + @override + Future jumpToIndex(int index) async {} + + @override + Future setVolume(double volume) async => + mdkPlayer.volume = volume / 100; + + @override + double get volume => mdkPlayer.volume; + + @override + Stream get volumeStream => Stream.value(volume); + + @override + Future setSpeed(double speed) async => mdkPlayer.playbackRate = speed; + @override + Future seekTo(Duration position) => + mdkPlayer.seek(position: position.inMilliseconds); + + @override + Future setSize(Size size) async { + // return ensureVideoControllerInitialized((controller) async { + // await controller.setSize( + // width: size.width.toInt(), + // height: size.height.toInt(), + // ); + // }); + } + + @override + double get aspectRatio => maxSize.aspectRatio; + + @override + Future start() async { + mdkPlayer.state = PlaybackState.playing; + } + + @override + Future pause() async { + mdkPlayer.state = PlaybackState.paused; + } + + @override + Future release() async { + if (!kIsWeb && Platform.isLinux) { + await pause(); + await Future.delayed(const Duration(milliseconds: 150)); + } + } + + @override + Future reset() async { + await pause(); + await seekTo(Duration.zero); + } + + /// Crops the current video into a box at the given row and column + @override + Future crop(int row, int col) async { + super.crop(row, col); + if (kIsWeb || + // On macOS, the mpv options don't seem to work properly. Because of this, + // software zoom is used instead. + Platform.isMacOS || + zoom.softwareZoom) return; + + final reset = zoom.zoomAxis == (-1, -1); + // final player = mdkPlayer.platform as dynamic; + + final Future Function(Rect rect) crop; + if (Platform.isLinux) { + // On linux, the mpv binaries used come from the distros (sudo apt install mpv ...) + // As of now (18 nov 2023), the "video-crop" parameter is not supported on + // most distros. In this case, there is the "vf=crop" parameter that does + // the same thing. "video-crop" is preferred on the other platforms because + // of its performance. + crop = _cropWithFilter; + } else { + crop = _cropWithoutFilter; + } + + if (reset) { + await crop(Rect.zero); + } else if (width != null && height != null) { + final tileWidth = maxSize.width / zoom.matrixType.size; + final tileHeight = maxSize.height / zoom.matrixType.size; + + zoom.zoomRect = Rect.fromLTWH( + col * tileWidth, + row * tileHeight, + tileWidth, + tileHeight, + ); + + debugPrint( + 'Cropping ${zoom.softwareZoom} | row=$row | col=$col | size=$maxSize | viewport=${zoom.zoomRect}', + ); + + await crop(zoom.zoomRect); + } + } + + Future _cropWithFilter(Rect viewportRect) async { + // Usage as dynamic is necessary because the property is not available on the + // web platform, and the compiler will complain about it. + // final player = mdkPlayer.platform as dynamic; + // if (viewportRect.isEmpty) { + // await player.setProperty('vf', 'crop='); + // } else { + // await player.setProperty( + // 'vf', + // 'crop=' + // '${viewportRect.width.toInt()}:' + // '${viewportRect.height.toInt()}:' + // '${viewportRect.left.toInt()}:' + // '${viewportRect.top.toInt()}', + // ); + // } + } + + Future _cropWithoutFilter(Rect viewportRect) async { + // Usage as dynamic is necessary because the property is not available on the + // web platform, and the compiler will complain about it. + // final player = mdkPlayer.platform as dynamic; + // if (viewportRect.isEmpty) { + // await player.setProperty('video-crop', '0x0+0+0'); + // } else { + // await player.setProperty( + // 'video-crop', + // '${viewportRect.width.toInt()}x' + // '${viewportRect.height.toInt()}+' + // '${viewportRect.left.toInt()}+' + // '${viewportRect.top.toInt()}', + // ); + // } + } + + @override + Future dispose() async { + await release(); + await super.dispose(); + // if (!kIsWeb && mdkPlayer.platform is NativePlayer) { + // final platform = mdkPlayer.platform as dynamic; + + // await platform.unobserveProperty('estimated-vf-fps'); + // await platform.unobserveProperty('width'); + // await platform.unobserveProperty('height'); + // } + await _fpsStreamController.close(); + mdkPlayer.dispose(); + UnityVideoPlayerInterface.unregisterPlayer(this); + } } diff --git a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml index ae6045e9..a9e0f53c 100644 --- a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml @@ -3,6 +3,8 @@ description: "A new Flutter package project." version: 0.0.1 homepage: +publish_to: none + environment: sdk: '>=3.4.1 <4.0.0' flutter: ">=1.17.0" @@ -10,45 +12,30 @@ environment: dependencies: flutter: sdk: flutter + unity_video_player_platform_interface: + path: ../unity_video_player_platform_interface/ + fvp: ^0.23.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.0 -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec -# The following section is specific to Flutter packages. flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages + plugin: + implements: unity_video_player + platforms: + windows: + dartPluginClass: UnityVideoPlayerFvpInterface + # linux: + # dartPluginClass: UnityVideoPlayerFvpInterface + # macos: + # dartPluginClass: UnityVideoPlayerFvpInterface + # ios: + # dartPluginClass: UnityVideoPlayerFvpInterface + # android: + # dartPluginClass: UnityVideoPlayerFvpInterface + # web: + # pluginClass: UnityVideoPlayerFvpInterface + # fileName: unity_video_player_main.dart \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 06007f7b..3bfbdf3b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -365,6 +365,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1+1" + fvp: + dependency: transitive + description: + name: fvp + sha256: "19a605fb32c2ee7a0b594ed51a2dd5fd5e8326bfa287ffd88c3e1ef0289d9afc" + url: "https://pub.dev" + source: hosted + version: "0.23.0" get_it: dependency: transitive description: @@ -981,6 +989,13 @@ packages: relative: true source: path version: "0.0.1" + unity_video_player_fvp: + dependency: transitive + description: + path: "packages/unity_video_player/unity_video_player_fvp" + relative: true + source: path + version: "0.0.1" unity_video_player_main: dependency: transitive description: @@ -1236,5 +1251,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.4.0 <4.0.0" + dart: ">=3.4.1 <4.0.0" flutter: ">=3.19.0" diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 3de2ce8d..9d1d583d 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AwesomeNotificationsPluginCApi")); ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FvpPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FvpPluginCApi")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); MediaKitVideoPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 566b17f2..f7b0a094 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST app_links awesome_notifications connectivity_plus + fvp media_kit_libs_windows_video media_kit_video permission_handler_windows From 86555181e4341c27ee275951db571d8ad55adb03 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 24 Aug 2024 16:19:55 -0300 Subject: [PATCH 04/24] feat: Enable low latency for all players --- .../lib/unity_video_player_fvp.dart | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart index d74b299f..46cdf3e8 100644 --- a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart +++ b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:unity_video_player_platform_interface/unity_video_player_platform_interface.dart'; import 'package:fvp/mdk.dart'; +import 'package:fvp/fvp.dart' as fvp; class UnityVideoPlayerFvpInterface extends UnityVideoPlayerInterface { /// Registers this class as the default instance of [UnityVideoPlayerInterface]. @@ -16,9 +17,15 @@ class UnityVideoPlayerFvpInterface extends UnityVideoPlayerInterface { @override Future initialize() async { - // fvp.registerWith(options: { - // 'platforms': ['windows'] - // }); + fvp.registerWith(options: { + 'player': { + 'avformat.analyzeduration': '10000', + 'avformat.probesize': '1000', + 'avformat.fpsprobesize': '0', + 'avformat.fflags': '+nobuffer', + 'avformat.avioflags': 'direct', + } + }); } @override @@ -112,7 +119,13 @@ class _MKVideoState extends State<_MKVideo> { @override void initState() { super.initState(); - widget.mdkPlayer.mdkPlayer.updateTexture(); + final player = widget.mdkPlayer.mdkPlayer; + player.setProperty("avformat.fflags", "+nobuffer"); + player.setProperty("avformat.analyzeduration", "10000"); + player.setProperty("avformat.probesize", "1000"); + player.setProperty("avformat.fpsprobesize", "0"); + player.setProperty("avformat.avioflags", "direct"); + player.updateTexture(); } @override From 411d658c5bd1cf8b40b108de6f4b71ffdd05e86b Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 24 Aug 2024 16:20:19 -0300 Subject: [PATCH 05/24] feat: Set surface size --- .../unity_video_player_fvp/lib/unity_video_player_fvp.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart index 46cdf3e8..020e5bda 100644 --- a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart +++ b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart @@ -322,6 +322,8 @@ class UnityVideoPlayerFvp extends UnityVideoPlayer { // height: size.height.toInt(), // ); // }); + + mdkPlayer.setVideoSurfaceSize(size.width.toInt(), size.height.toInt()); } @override From 440356ebd4e625bb49e7df42a58206f104885008 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 24 Aug 2024 16:30:44 -0300 Subject: [PATCH 06/24] feat: Include pub resolver --- packages/pub_resolver.dart | 65 +++++++++++++++++++ .../unity_video_player_fvp/pubspec.yaml | 2 +- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 packages/pub_resolver.dart diff --git a/packages/pub_resolver.dart b/packages/pub_resolver.dart new file mode 100644 index 00000000..39c8b8d9 --- /dev/null +++ b/packages/pub_resolver.dart @@ -0,0 +1,65 @@ +// A script that resolves the dependencies of all unity packages. + +// ignore_for_file: avoid_print + +import 'dart:convert'; +import 'dart:io'; + +void main() async { + print('Resolving dependencies'); + + final packagePaths = [ + 'packages/unity_multi_window', + 'packages/unity_video_player/unity_video_player', + 'packages/unity_video_player/unity_video_player_flutter', + 'packages/unity_video_player/unity_video_player_fvp', + 'packages/unity_video_player/unity_video_player_main', + 'packages/unity_video_player/unity_video_player_platform_interface', + ]; + + print('Running pub get in all packages:'); + await Future.wait(packagePaths.map(_runPubGet)); + + print('Running pub upgrade in all packages:'); + await Future.wait(packagePaths.map(_runPubUpgrade)); + + print('All done'); +} + +Future _runPubGet(String packagePath) async { + void printLine(String line) { + print('[$packagePath] $line'); + } + + final process = await Process.start( + 'flutter', + ['pub', 'get'], + workingDirectory: packagePath, + runInShell: true, + ); + process.stdout.transform(utf8.decoder).listen(printLine); + process.stderr.transform(utf8.decoder).listen(printLine); + final exitCode = await process.exitCode; + if (exitCode != 0) { + throw Exception('Failed to run pub get in $packagePath'); + } +} + +Future _runPubUpgrade(String packagePath) async { + void printLine(String line) { + print('[$packagePath] $line'); + } + + final process = await Process.start( + 'flutter', + ['pub', 'upgrade'], + workingDirectory: packagePath, + runInShell: true, + ); + process.stdout.transform(utf8.decoder).listen(printLine); + process.stderr.transform(utf8.decoder).listen(printLine); + final exitCode = await process.exitCode; + if (exitCode != 0) { + throw Exception('Failed to run pub upgrade in $packagePath'); + } +} diff --git a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml index a9e0f53c..8ca1303a 100644 --- a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: sdk: flutter unity_video_player_platform_interface: path: ../unity_video_player_platform_interface/ - fvp: ^0.23.0 + fvp: ^0.24.1 dev_dependencies: flutter_test: From f46b0376b207aae1caede362f6f04396249262e1 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 24 Aug 2024 16:42:36 -0300 Subject: [PATCH 07/24] fix: Include current repository in pub resolver --- packages/pub_resolver.dart | 1 + pubspec.lock | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/packages/pub_resolver.dart b/packages/pub_resolver.dart index 39c8b8d9..a3ceee9c 100644 --- a/packages/pub_resolver.dart +++ b/packages/pub_resolver.dart @@ -9,6 +9,7 @@ void main() async { print('Resolving dependencies'); final packagePaths = [ + '.', 'packages/unity_multi_window', 'packages/unity_video_player/unity_video_player', 'packages/unity_video_player/unity_video_player_flutter', diff --git a/pubspec.lock b/pubspec.lock index 0a0aebb4..a5868fc9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -373,6 +373,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1+1" + fvp: + dependency: transitive + description: + name: fvp + sha256: "6462fd078de4478a0990d437463897036cff98aff3f0ac9efbbf817c99654c87" + url: "https://pub.dev" + source: hosted + version: "0.24.1" get_it: dependency: transitive description: @@ -989,6 +997,13 @@ packages: relative: true source: path version: "0.0.1" + unity_video_player_fvp: + dependency: transitive + description: + path: "packages/unity_video_player/unity_video_player_fvp" + relative: true + source: path + version: "0.0.1" unity_video_player_main: dependency: transitive description: From dc58a3ecf8330e9ce8b5b29b4f9da174f9bbf90d Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 24 Aug 2024 17:13:39 -0300 Subject: [PATCH 08/24] feat: Add stream data --- lib/screens/layouts/desktop/sidebar.dart | 4 +- .../lib/unity_video_player_fvp.dart | 38 ++++++++++++++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lib/screens/layouts/desktop/sidebar.dart b/lib/screens/layouts/desktop/sidebar.dart index 879b3b61..f5d64f49 100644 --- a/lib/screens/layouts/desktop/sidebar.dart +++ b/lib/screens/layouts/desktop/sidebar.dart @@ -51,9 +51,7 @@ class _DesktopSidebarState extends State { final devices = server.devices.sorted( searchQuery: searchQuery, ); - if (devices.isNotEmpty) { - _servers[server] = devices; - } + _servers[server] = devices; } } diff --git a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart index 020e5bda..7df356c1 100644 --- a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart +++ b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart @@ -144,6 +144,7 @@ class UnityVideoPlayerFvp extends UnityVideoPlayer { double _fps = 0; @override double get fps => _fps; + final _fpsStreamController = StreamController.broadcast(); @override Stream get fpsStream => _fpsStreamController.stream; @@ -218,6 +219,27 @@ class UnityVideoPlayerFvp extends UnityVideoPlayer { // late streams. // platform.setProperty('force-seekable', 'yes'); // } + + mdkPlayer + ..onStateChanged((previous, state) { + _playingStateStreamController.add(state == PlaybackState.playing); + }) + ..onMediaStatus((previous, status) { + _bufferStateStreamController.add( + status.rawValue == MediaStatus.buffering, + ); + + return false; + }) + ..onEvent((_) { + // we will add the current value to the stream + _positionStreamController.add(currentPos); + _bufferStreamController.add(currentBuffer); + _durationStreamController.add(duration); + _fpsStreamController.add(fps); + _playingStateStreamController.add(isPlaying); + _bufferStateStreamController.add(isBuffering); + }); } @override @@ -232,15 +254,16 @@ class UnityVideoPlayerFvp extends UnityVideoPlayer { @override Duration get duration => Duration(milliseconds: mdkPlayer.mediaInfo.duration); + final _durationStreamController = StreamController.broadcast(); @override - Stream get onDurationUpdate => const Stream.empty(broadcast: false); + Stream get onDurationUpdate => _durationStreamController.stream; @override Duration get currentPos => Duration(milliseconds: mdkPlayer.position); + final _positionStreamController = StreamController.broadcast(); @override - Stream get onCurrentPosUpdate => - const Stream.empty(broadcast: false); + Stream get onCurrentPosUpdate => _positionStreamController.stream; @override bool get isBuffering => @@ -249,20 +272,23 @@ class UnityVideoPlayerFvp extends UnityVideoPlayer { @override Duration get currentBuffer => Duration(milliseconds: mdkPlayer.buffered()); + final _bufferStreamController = StreamController.broadcast(); @override - Stream get onBufferUpdate => const Stream.empty(broadcast: false); + Stream get onBufferUpdate => _bufferStreamController.stream; @override bool get isSeekable => duration > Duration.zero; + final _bufferStateStreamController = StreamController.broadcast(); @override - Stream get onBufferStateUpdate => const Stream.empty(broadcast: false); + Stream get onBufferStateUpdate => _bufferStateStreamController.stream; @override bool get isPlaying => mdkPlayer.state == PlaybackState.playing; + final _playingStateStreamController = StreamController.broadcast(); @override - Stream get onPlayingStateUpdate => const Stream.empty(broadcast: false); + Stream get onPlayingStateUpdate => _playingStateStreamController.stream; /// Gets a property from the media kit player. /// From 9e75abdaa529930f00074c6efeb713806945f64a Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Sat, 24 Aug 2024 17:27:49 -0300 Subject: [PATCH 09/24] feat: Enable fvp on Linux --- .../lib/unity_video_player_flutter.dart | 15 ++++++++++++++- .../unity_video_player_flutter/pubspec.yaml | 1 + .../unity_video_player_fvp/pubspec.yaml | 6 +++--- pubspec.lock | 4 ++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index 13dd0943..d06b4a56 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutterpi_gstreamer_video_player/flutterpi_gstreamer_video_player.dart'; import 'package:video_player/video_player.dart'; import 'package:unity_video_player_platform_interface/unity_video_player_platform_interface.dart'; +import 'package:fvp/fvp.dart' as fvp; class UnityVideoPlayerFlutterInterface extends UnityVideoPlayerInterface { /// Registers this class as the default instance of [UnityVideoPlayerInterface]. @@ -21,7 +22,19 @@ class UnityVideoPlayerFlutterInterface extends UnityVideoPlayerInterface { @override Future initialize() async { - FlutterpiVideoPlayer.registerWith(); + if ('pi' case const String.fromEnvironment('linux_environment')) { + FlutterpiVideoPlayer.registerWith(); + } else { + fvp.registerWith(options: { + 'player': { + 'avformat.analyzeduration': '10000', + 'avformat.probesize': '1000', + 'avformat.fpsprobesize': '0', + 'avformat.fflags': '+nobuffer', + 'avformat.avioflags': 'direct', + } + }); + } } @override diff --git a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml index 46ceff25..52bf004b 100644 --- a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: path: ../unity_video_player_main video_player: ^2.8.1 flutterpi_gstreamer_video_player: ^0.1.1+1 + fvp: ^0.24.1 dev_dependencies: flutter_test: diff --git a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml index 8ca1303a..3cbf650d 100644 --- a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml @@ -1,5 +1,5 @@ name: unity_video_player_fvp -description: "A new Flutter package project." +description: "Implements MDK Unity Video Player for Flutter" version: 0.0.1 homepage: @@ -28,8 +28,8 @@ flutter: platforms: windows: dartPluginClass: UnityVideoPlayerFvpInterface - # linux: - # dartPluginClass: UnityVideoPlayerFvpInterface + linux: + dartPluginClass: UnityVideoPlayerFvpInterface # macos: # dartPluginClass: UnityVideoPlayerFvpInterface # ios: diff --git a/pubspec.lock b/pubspec.lock index a5868fc9..cf6c15be 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1134,10 +1134,10 @@ packages: dependency: transitive description: name: video_player_android - sha256: "4de50df9ee786f5891d3281e1e633d7b142ef1acf47392592eb91cba5d355849" + sha256: "28b1d818f2beeb108a1ed7c58a40becae86735922a98c81c7052cb278b89ea65" url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" video_player_avfoundation: dependency: transitive description: From bc3b894cae899d15c3dd9583238f6de343b38e3f Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Tue, 27 Aug 2024 11:08:16 -0300 Subject: [PATCH 10/24] feat: Use flutter's video_player --- .../unity_video_player/pubspec.yaml | 6 ++-- .../lib/unity_video_player_flutter.dart | 31 ++++++++++++------- .../unity_video_player_flutter/pubspec.yaml | 7 +++++ pubspec.lock | 8 ++--- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/packages/unity_video_player/unity_video_player/pubspec.yaml b/packages/unity_video_player/unity_video_player/pubspec.yaml index 41a4933a..2c9a1bb6 100644 --- a/packages/unity_video_player/unity_video_player/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../unity_video_player_main unity_video_player_flutter: path: ../unity_video_player_flutter - unity_video_player_fvp: - path: ../unity_video_player_fvp + # unity_video_player_fvp: + # path: ../unity_video_player_fvp dev_dependencies: flutter_test: @@ -36,6 +36,6 @@ flutter: linux: default_package: unity_video_player_flutter windows: - default_package: unity_video_player_fvp + default_package: unity_video_player_flutter web: default_package: unity_video_player_main diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index d06b4a56..6840efd3 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -119,40 +119,41 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { Duration get duration => player?.value.duration ?? Duration.zero; @override - Stream get onDurationUpdate => - _videoStream.stream.map((_) => duration); + Stream get onDurationUpdate => _videoStream.stream + .where((value) => value.duration != Duration.zero) + .map((value) => value.duration); @override Duration get currentPos => player?.value.position ?? Duration.zero; @override Stream get onCurrentPosUpdate => - _videoStream.stream.map((_) => currentPos); - - @override - bool get isBuffering => player?.value.isBuffering ?? false; + _videoStream.stream.map((value) => value.position); @override Duration get currentBuffer => player?.value.buffered.last.end ?? Duration.zero; @override - Stream get onBufferUpdate => - _videoStream.stream.map((_) => currentBuffer); + Stream get onBufferUpdate => _videoStream.stream + .where((value) => value.buffered.isNotEmpty) + .map((value) => value.buffered.last.end); @override bool get isSeekable => duration > Duration.zero; + @override + bool get isBuffering => player?.value.isBuffering ?? false; @override Stream get onBufferStateUpdate => - _videoStream.stream.map((_) => isBuffering); + _videoStream.stream.map((value) => value.isBuffering); @override bool get isPlaying => player?.value.isPlaying ?? false; @override Stream get onPlayingStateUpdate => - _videoStream.stream.map((_) => isPlaying); + _videoStream.stream.map((value) => value.isPlaying); @override Future setDataSource(String url, {bool autoPlay = true}) async { @@ -163,7 +164,15 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { await player?.dispose(); } - player = VideoPlayerController.networkUrl(Uri.parse(url)); + final uri = Uri.parse(url); + + // check if the url is a file + if (uri.scheme == 'file') { + player = VideoPlayerController.file(File.fromUri(uri)); + } else { + player = VideoPlayerController.networkUrl(uri); + } + await player!.initialize(); notifyListeners(); player!.addListener(() { diff --git a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml index 52bf004b..07dc4f0a 100644 --- a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml @@ -26,3 +26,10 @@ dev_dependencies: flutter_lints: ^3.0.0 flutter: + plugin: + implements: unity_video_player + platforms: + windows: + dartPluginClass: UnityVideoPlayerFlutterInterface + linux: + dartPluginClass: UnityVideoPlayerFlutterInterface \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index cf6c15be..f5409666 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -335,10 +335,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "9d98bd47ef9d34e803d438f17fd32b116d31009f534a6fa5ce3a1167f189a6de" + sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" url: "https://pub.dev" source: hosted - version: "2.0.21" + version: "2.0.22" flutter_simple_treeview: dependency: "direct main" description: @@ -1134,10 +1134,10 @@ packages: dependency: transitive description: name: video_player_android - sha256: "28b1d818f2beeb108a1ed7c58a40becae86735922a98c81c7052cb278b89ea65" + sha256: "101028b643a3b43ced72107aacdbc4d30d55365487751de001a36cf0d86038d1" url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.7.2" video_player_avfoundation: dependency: transitive description: From 1b2f718e57604943b54b629ab6c55df528f6b2da Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Tue, 27 Aug 2024 11:14:27 -0300 Subject: [PATCH 11/24] fix: Set error when failed to initialize --- .../lib/unity_video_player_flutter.dart | 21 ++++++++++++------- ...unity_video_player_platform_interface.dart | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index 6840efd3..48f7b0b7 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -173,13 +173,20 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { player = VideoPlayerController.networkUrl(uri); } - await player!.initialize(); - notifyListeners(); - player!.addListener(() { - _videoStream.add(player!.value); - }); - if (autoPlay) { - await player!.play(); + try { + await player!.initialize(); + player!.addListener(() { + _videoStream.add(player!.value); + }); + onReady(); + if (autoPlay) { + await player!.play(); + } + } catch (e, _) { + error = e.toString(); + notifyListeners(); + + rethrow; } } diff --git a/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart b/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart index 4ff5c7df..69c8eb68 100644 --- a/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart +++ b/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart @@ -230,6 +230,10 @@ abstract class UnityVideoPlayer with ChangeNotifier { UnityVideoQuality? quality; VideoZoom zoom = VideoZoom(); + /// Called when the video source is ready to be listened to. + /// + /// Implementations must call this when the video source is ready to be + /// listened to. late final VoidCallback onReady; UnityVideoPlayer({this.width, this.height}) { From 6f69e911b5ea97e5a8d7e8921af930b18c15e2be Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Tue, 27 Aug 2024 11:35:39 -0300 Subject: [PATCH 12/24] fix: Do not throw error when listening to the fps stream --- .../lib/unity_video_player_flutter.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index 48f7b0b7..cdb1473f 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -219,8 +219,7 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { @override double get fps => 0.0; @override - Stream get fpsStream => - throw UnsupportedError('Fps is not implemented on this platform'); + Stream get fpsStream => Stream.value(fps); @override double get aspectRatio => player?.value.aspectRatio ?? 1.0; From a12e6a68e47d8443201d4bbd2df87eed71504d6c Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Tue, 27 Aug 2024 11:56:18 -0300 Subject: [PATCH 13/24] feat: Video Disposal --- .../lib/unity_video_player_flutter.dart | 11 +++++++++-- .../lib/unity_video_player_platform_interface.dart | 14 +++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index cdb1473f..68644baa 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -131,8 +131,11 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { _videoStream.stream.map((value) => value.position); @override - Duration get currentBuffer => - player?.value.buffered.last.end ?? Duration.zero; + Duration get currentBuffer { + if (player == null) return Duration.zero; + if (player!.value.buffered.isEmpty) return Duration.zero; + return player!.value.buffered.last.end; + } @override Stream get onBufferUpdate => _videoStream.stream @@ -176,6 +179,7 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { try { await player!.initialize(); player!.addListener(() { + if (_videoStream.isClosed) return; _videoStream.add(player!.value); }); onReady(); @@ -266,6 +270,9 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { await release(); await super.dispose(); await _videoStream.close(); + player + ?..pause() + ..dispose(); UnityVideoPlayerInterface.unregisterPlayer(this); } } diff --git a/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart b/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart index 69c8eb68..899f2340 100644 --- a/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart +++ b/packages/unity_video_player/unity_video_player_platform_interface/lib/unity_video_player_platform_interface.dart @@ -438,11 +438,15 @@ abstract class UnityVideoPlayer with ChangeNotifier { @mustCallSuper @override Future dispose() async { - _onDurationUpdateSubscription.cancel(); - _onErrorSubscription.cancel(); - _onPositionUpdateSubscription.cancel(); - _fpsSubscription.cancel(); - _oldImageTimer?.cancel(); + try { + _onDurationUpdateSubscription.cancel(); + _onErrorSubscription.cancel(); + _onPositionUpdateSubscription.cancel(); + _fpsSubscription.cancel(); + _oldImageTimer?.cancel(); + } catch (error, stack) { + debugPrint('Tried to cancel subscriptions but failed: $error, $stack'); + } _lastImageTime = null; _isImageOld = false; From eadb9ab77b65143913324dc788b8275235a9aa8b Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Wed, 28 Aug 2024 11:05:08 -0300 Subject: [PATCH 14/24] feat: Set up multiple data sources --- .../desktop/timeline_card.dart | 6 +++++ .../lib/unity_video_player_flutter.dart | 22 ++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/screens/events_timeline/desktop/timeline_card.dart b/lib/screens/events_timeline/desktop/timeline_card.dart index c5a73e37..05011180 100644 --- a/lib/screens/events_timeline/desktop/timeline_card.dart +++ b/lib/screens/events_timeline/desktop/timeline_card.dart @@ -72,6 +72,12 @@ class _TimelineCardState extends State { fit: _fit ?? device.server.additionalSettings.videoFit ?? settings.kVideoFit.value, + videoBuilder: (context, video) { + return AspectRatio( + aspectRatio: 16 / 9, + child: video, + ); + }, paneBuilder: (context, controller) { if (currentEvent == null) { return RepaintBoundary( diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index 68644baa..fd4bb092 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -194,19 +194,25 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { } } + var _multipleDataSources = []; + @override - Future setMultipleDataSource(Iterable url, - {bool autoPlay = true}) { - throw UnsupportedError( - 'setMultipleDataSource is not supported on this platform', - ); + Future setMultipleDataSource( + Iterable url, { + bool autoPlay = true, + int startIndex = 0, + }) { + _multipleDataSources = url.toList(); + return setDataSource(url.elementAt(startIndex), autoPlay: autoPlay); } @override Future jumpToIndex(int index) { - throw UnsupportedError( - 'jumpToIndex is not supported on this platform', - ); + if (index < 0 || index >= _multipleDataSources.length) { + return Future.error('Index out of range'); + } + + return setDataSource(_multipleDataSources[index]); } // Volume in media kit goes from 0 to 100 From fc1cb4a25536f974000ac2246c7b9347f45cad1b Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Wed, 28 Aug 2024 11:07:48 -0300 Subject: [PATCH 15/24] chore: Remove unused package --- .../unity_video_player_fvp/.gitignore | 29 -- .../unity_video_player_fvp/.metadata | 10 - .../unity_video_player_fvp/LICENSE | 1 - .../analysis_options.yaml | 4 - .../lib/unity_video_player_fvp.dart | 478 ------------------ .../unity_video_player_fvp/pubspec.yaml | 41 -- 6 files changed, 563 deletions(-) delete mode 100644 packages/unity_video_player/unity_video_player_fvp/.gitignore delete mode 100644 packages/unity_video_player/unity_video_player_fvp/.metadata delete mode 100644 packages/unity_video_player/unity_video_player_fvp/LICENSE delete mode 100644 packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml delete mode 100644 packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart delete mode 100644 packages/unity_video_player/unity_video_player_fvp/pubspec.yaml diff --git a/packages/unity_video_player/unity_video_player_fvp/.gitignore b/packages/unity_video_player/unity_video_player_fvp/.gitignore deleted file mode 100644 index ac5aa989..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -# 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/ -build/ diff --git a/packages/unity_video_player/unity_video_player_fvp/.metadata b/packages/unity_video_player/unity_video_player_fvp/.metadata deleted file mode 100644 index d36dfbcc..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# 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: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" - channel: "stable" - -project_type: package diff --git a/packages/unity_video_player/unity_video_player_fvp/LICENSE b/packages/unity_video_player/unity_video_player_fvp/LICENSE deleted file mode 100644 index ba75c69f..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. diff --git a/packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml b/packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml deleted file mode 100644 index a5744c1c..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:flutter_lints/flutter.yaml - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart b/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart deleted file mode 100644 index 7df356c1..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/lib/unity_video_player_fvp.dart +++ /dev/null @@ -1,478 +0,0 @@ -library unity_video_player_fvp; - -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:unity_video_player_platform_interface/unity_video_player_platform_interface.dart'; -import 'package:fvp/mdk.dart'; -import 'package:fvp/fvp.dart' as fvp; - -class UnityVideoPlayerFvpInterface extends UnityVideoPlayerInterface { - /// Registers this class as the default instance of [UnityVideoPlayerInterface]. - static void registerWith([registrar]) { - UnityVideoPlayerInterface.instance = UnityVideoPlayerFvpInterface(); - } - - @override - Future initialize() async { - fvp.registerWith(options: { - 'player': { - 'avformat.analyzeduration': '10000', - 'avformat.probesize': '1000', - 'avformat.fpsprobesize': '0', - 'avformat.fflags': '+nobuffer', - 'avformat.avioflags': 'direct', - } - }); - } - - @override - UnityVideoPlayer createPlayer({ - int? width, - int? height, - bool enableCache = false, - RTSPProtocol? rtspProtocol, - VoidCallback? onReload, - MatrixType matrixType = MatrixType.t16, - bool softwareZoom = false, - }) { - final player = UnityVideoPlayerFvp( - width: width, - height: height, - enableCache: enableCache, - rtspProtocol: rtspProtocol, - ) - ..zoom.matrixType = matrixType - ..zoom.softwareZoom = softwareZoom - ..onReload = onReload; - UnityVideoPlayerInterface.registerPlayer(player); - return player; - } - - @override - Widget createVideoView({ - Key? key, - required UnityVideoPlayer player, - UnityVideoFit fit = UnityVideoFit.contain, - UnityVideoPaneBuilder? paneBuilder, - UnityVideoBuilder? videoBuilder, - Color color = const Color(0xFF000000), - }) { - videoBuilder ??= (context, video) => video; - final mdkPlayer = (player as UnityVideoPlayerFvp); - - return Builder(builder: (context) { - return Stack(children: [ - Positioned.fill( - child: videoBuilder!( - context, - _MKVideo( - key: ValueKey(player), - mdkPlayer: mdkPlayer, - color: color, - fit: () { - return switch (fit) { - UnityVideoFit.contain => BoxFit.contain, - UnityVideoFit.cover => BoxFit.cover, - UnityVideoFit.fill => BoxFit.fill, - }; - }(), - ), - ), - ), - if (paneBuilder != null) - Positioned.fill( - child: Material( - type: MaterialType.transparency, - child: paneBuilder(context, player), - ), - ), - ]); - }); - } -} - -class _MKVideo extends StatefulWidget { - const _MKVideo({ - super.key, - required this.mdkPlayer, - required this.fit, - required this.color, - }); - - final UnityVideoPlayerFvp mdkPlayer; - final BoxFit fit; - final Color color; - - @override - State<_MKVideo> createState() => _MKVideoState(); -} - -class _MKVideoState extends State<_MKVideo> { - @override - void didUpdateWidget(covariant _MKVideo oldWidget) { - super.didUpdateWidget(oldWidget); - } - - @override - void initState() { - super.initState(); - final player = widget.mdkPlayer.mdkPlayer; - player.setProperty("avformat.fflags", "+nobuffer"); - player.setProperty("avformat.analyzeduration", "10000"); - player.setProperty("avformat.probesize", "1000"); - player.setProperty("avformat.fpsprobesize", "0"); - player.setProperty("avformat.avioflags", "direct"); - player.updateTexture(); - } - - @override - Widget build(BuildContext context) { - return ValueListenableBuilder( - valueListenable: widget.mdkPlayer.mdkPlayer.textureId, - builder: (context, id, _) => - id == null ? const SizedBox.shrink() : Texture(textureId: id), - ); - } -} - -class UnityVideoPlayerFvp extends UnityVideoPlayer { - late final Player mdkPlayer; - - double _fps = 0; - @override - double get fps => _fps; - - final _fpsStreamController = StreamController.broadcast(); - @override - Stream get fpsStream => _fpsStreamController.stream; - - Size maxSize = Size.zero; - final bool enableCache; - - UnityVideoPlayerFvp({ - super.width, - super.height, - this.enableCache = false, - RTSPProtocol? rtspProtocol, - }) { - mdkPlayer = Player(); - final pixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio; - if (width != null) width = (width! * pixelRatio).toInt(); - if (height != null) height = (height! * pixelRatio).toInt(); - - onLog?.call( - 'Initialized player $title with width=$width and height=$height'); - - // Check type. Only true for libmpv based platforms. Currently Windows & Linux. - // if (!kIsWeb && platform is NativePlayer) { - // platform - // ..observeProperty('estimated-vf-fps', (fps) async { - // _fps = double.parse(fps); - // _fpsStreamController.add(_fps); - // }) - // ..observeProperty('width', (width) async { - // debugPrint('$title: display width: $width/${this.width}'); - // this.width = int.tryParse(width); - // if (this.width != null && this.width! > maxSize.width) { - // maxSize = Size(this.width!.toDouble(), maxSize.height); - // } - // }) - // ..observeProperty('height', (height) async { - // debugPrint('$title: display height: $height/${this.height}'); - // this.height = int.tryParse(height); - // if (this.height != null && this.height! > maxSize.height) { - // maxSize = Size(maxSize.width, this.height!.toDouble()); - // } - // }); - - // mdkPlayer.stream.log.listen((event) { - // final logMessage = '${event.level} | ${event.prefix}: ${event.text}'; - // if (event.level != 'v') debugPrint(logMessage); - // if (event.level == 'fatal') { - // // ignore: invalid_use_of_protected_member - // platform.errorController.add(event.text); - // } - // onLog?.call(logMessage); - // }); - - // // Some servers use self-signed certificates. This is necessary to allow - // // the connection to these servers. - // platform.setProperty('tls-verify', 'no'); - // platform.setProperty('insecure', 'yes'); - - // // Defines the protocol to be used in the RTSP connection. - // if (rtspProtocol != null) { - // platform.setProperty( - // 'rtsp-transport', - // switch (rtspProtocol) { - // RTSPProtocol.tcp => 'tcp', - // RTSPProtocol.udp => 'udp', - // // _ => 'udp_multicast' - // }, - // ); - // } - - // Ensures the stream can be seekable. We use seekable streams to dismiss - // late streams. - // platform.setProperty('force-seekable', 'yes'); - // } - - mdkPlayer - ..onStateChanged((previous, state) { - _playingStateStreamController.add(state == PlaybackState.playing); - }) - ..onMediaStatus((previous, status) { - _bufferStateStreamController.add( - status.rawValue == MediaStatus.buffering, - ); - - return false; - }) - ..onEvent((_) { - // we will add the current value to the stream - _positionStreamController.add(currentPos); - _bufferStreamController.add(currentBuffer); - _durationStreamController.add(duration); - _fpsStreamController.add(fps); - _playingStateStreamController.add(isPlaying); - _bufferStateStreamController.add(isBuffering); - }); - } - - @override - String? get dataSource { - final media = mdkPlayer.media; - return media.isNotEmpty ? media : null; - } - - @override - Stream get onError => const Stream.empty(broadcast: false); - - @override - Duration get duration => Duration(milliseconds: mdkPlayer.mediaInfo.duration); - - final _durationStreamController = StreamController.broadcast(); - @override - Stream get onDurationUpdate => _durationStreamController.stream; - - @override - Duration get currentPos => Duration(milliseconds: mdkPlayer.position); - - final _positionStreamController = StreamController.broadcast(); - @override - Stream get onCurrentPosUpdate => _positionStreamController.stream; - - @override - bool get isBuffering => - mdkPlayer.mediaStatus.rawValue == MediaStatus.buffering; - - @override - Duration get currentBuffer => Duration(milliseconds: mdkPlayer.buffered()); - - final _bufferStreamController = StreamController.broadcast(); - @override - Stream get onBufferUpdate => _bufferStreamController.stream; - - @override - bool get isSeekable => duration > Duration.zero; - - final _bufferStateStreamController = StreamController.broadcast(); - @override - Stream get onBufferStateUpdate => _bufferStateStreamController.stream; - - @override - bool get isPlaying => mdkPlayer.state == PlaybackState.playing; - - final _playingStateStreamController = StreamController.broadcast(); - @override - Stream get onPlayingStateUpdate => _playingStateStreamController.stream; - - /// Gets a property from the media kit player. - /// - /// Do not use this to get the properties of already observed properties. - @override - Future getProperty(String propertyName) async { - return ''; - } - - @override - Future setDataSource(String url, {bool autoPlay = true}) async { - if (url == dataSource) return Future.value(); - debugPrint('Playing $url'); - mdkPlayer.setMedia(url, MediaType.video); - if (autoPlay) start(); - // await mdkPlayer.setPlaylistMode(PlaylistMode.loop); - // // do not use mdkPlayer.add because it doesn't support auto play - // await mdkPlayer.open(Playlist([Media(url)]), play: autoPlay); - } - - @override - Future setMultipleDataSource( - Iterable url, { - bool autoPlay = true, - }) async { - // await mdkPlayer.open( - // Playlist(url.map(Media.new).toList()), - // play: autoPlay, - // ); - setDataSource(url.first); - } - - @override - Future jumpToIndex(int index) async {} - - @override - Future setVolume(double volume) async => - mdkPlayer.volume = volume / 100; - - @override - double get volume => mdkPlayer.volume; - - @override - Stream get volumeStream => Stream.value(volume); - - @override - Future setSpeed(double speed) async => mdkPlayer.playbackRate = speed; - @override - Future seekTo(Duration position) => - mdkPlayer.seek(position: position.inMilliseconds); - - @override - Future setSize(Size size) async { - // return ensureVideoControllerInitialized((controller) async { - // await controller.setSize( - // width: size.width.toInt(), - // height: size.height.toInt(), - // ); - // }); - - mdkPlayer.setVideoSurfaceSize(size.width.toInt(), size.height.toInt()); - } - - @override - double get aspectRatio => maxSize.aspectRatio; - - @override - Future start() async { - mdkPlayer.state = PlaybackState.playing; - } - - @override - Future pause() async { - mdkPlayer.state = PlaybackState.paused; - } - - @override - Future release() async { - if (!kIsWeb && Platform.isLinux) { - await pause(); - await Future.delayed(const Duration(milliseconds: 150)); - } - } - - @override - Future reset() async { - await pause(); - await seekTo(Duration.zero); - } - - /// Crops the current video into a box at the given row and column - @override - Future crop(int row, int col) async { - super.crop(row, col); - if (kIsWeb || - // On macOS, the mpv options don't seem to work properly. Because of this, - // software zoom is used instead. - Platform.isMacOS || - zoom.softwareZoom) return; - - final reset = zoom.zoomAxis == (-1, -1); - // final player = mdkPlayer.platform as dynamic; - - final Future Function(Rect rect) crop; - if (Platform.isLinux) { - // On linux, the mpv binaries used come from the distros (sudo apt install mpv ...) - // As of now (18 nov 2023), the "video-crop" parameter is not supported on - // most distros. In this case, there is the "vf=crop" parameter that does - // the same thing. "video-crop" is preferred on the other platforms because - // of its performance. - crop = _cropWithFilter; - } else { - crop = _cropWithoutFilter; - } - - if (reset) { - await crop(Rect.zero); - } else if (width != null && height != null) { - final tileWidth = maxSize.width / zoom.matrixType.size; - final tileHeight = maxSize.height / zoom.matrixType.size; - - zoom.zoomRect = Rect.fromLTWH( - col * tileWidth, - row * tileHeight, - tileWidth, - tileHeight, - ); - - debugPrint( - 'Cropping ${zoom.softwareZoom} | row=$row | col=$col | size=$maxSize | viewport=${zoom.zoomRect}', - ); - - await crop(zoom.zoomRect); - } - } - - Future _cropWithFilter(Rect viewportRect) async { - // Usage as dynamic is necessary because the property is not available on the - // web platform, and the compiler will complain about it. - // final player = mdkPlayer.platform as dynamic; - // if (viewportRect.isEmpty) { - // await player.setProperty('vf', 'crop='); - // } else { - // await player.setProperty( - // 'vf', - // 'crop=' - // '${viewportRect.width.toInt()}:' - // '${viewportRect.height.toInt()}:' - // '${viewportRect.left.toInt()}:' - // '${viewportRect.top.toInt()}', - // ); - // } - } - - Future _cropWithoutFilter(Rect viewportRect) async { - // Usage as dynamic is necessary because the property is not available on the - // web platform, and the compiler will complain about it. - // final player = mdkPlayer.platform as dynamic; - // if (viewportRect.isEmpty) { - // await player.setProperty('video-crop', '0x0+0+0'); - // } else { - // await player.setProperty( - // 'video-crop', - // '${viewportRect.width.toInt()}x' - // '${viewportRect.height.toInt()}+' - // '${viewportRect.left.toInt()}+' - // '${viewportRect.top.toInt()}', - // ); - // } - } - - @override - Future dispose() async { - await release(); - await super.dispose(); - // if (!kIsWeb && mdkPlayer.platform is NativePlayer) { - // final platform = mdkPlayer.platform as dynamic; - - // await platform.unobserveProperty('estimated-vf-fps'); - // await platform.unobserveProperty('width'); - // await platform.unobserveProperty('height'); - // } - await _fpsStreamController.close(); - mdkPlayer.dispose(); - UnityVideoPlayerInterface.unregisterPlayer(this); - } -} diff --git a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml b/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml deleted file mode 100644 index 3cbf650d..00000000 --- a/packages/unity_video_player/unity_video_player_fvp/pubspec.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: unity_video_player_fvp -description: "Implements MDK Unity Video Player for Flutter" -version: 0.0.1 -homepage: - -publish_to: none - -environment: - sdk: '>=3.4.1 <4.0.0' - flutter: ">=1.17.0" - -dependencies: - flutter: - sdk: flutter - unity_video_player_platform_interface: - path: ../unity_video_player_platform_interface/ - fvp: ^0.24.1 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^3.0.0 - - -flutter: - plugin: - implements: unity_video_player - platforms: - windows: - dartPluginClass: UnityVideoPlayerFvpInterface - linux: - dartPluginClass: UnityVideoPlayerFvpInterface - # macos: - # dartPluginClass: UnityVideoPlayerFvpInterface - # ios: - # dartPluginClass: UnityVideoPlayerFvpInterface - # android: - # dartPluginClass: UnityVideoPlayerFvpInterface - # web: - # pluginClass: UnityVideoPlayerFvpInterface - # fileName: unity_video_player_main.dart \ No newline at end of file From 1e40f3d07df34a49d65b80672fa35fa8c41d279e Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Wed, 28 Aug 2024 11:16:17 -0300 Subject: [PATCH 16/24] fix: Ensure video_player is used on the web --- .../unity_video_player/unity_video_player/pubspec.yaml | 2 +- .../lib/unity_video_player_flutter.dart | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/unity_video_player/unity_video_player/pubspec.yaml b/packages/unity_video_player/unity_video_player/pubspec.yaml index 2c9a1bb6..e13a73f3 100644 --- a/packages/unity_video_player/unity_video_player/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player/pubspec.yaml @@ -38,4 +38,4 @@ flutter: windows: default_package: unity_video_player_flutter web: - default_package: unity_video_player_main + default_package: unity_video_player_flutter diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index fd4bb092..4830bf25 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -99,13 +99,17 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { final _videoStream = StreamController.broadcast(); + RTSPProtocol? rtspProtocol; + UnityVideoPlayerFlutter({ super.width, super.height, bool enableCache = false, - RTSPProtocol? rtspProtocol, + this.rtspProtocol, String? title, - }); + }) { + if (title != null) this.title = title; + } @override String? get dataSource => player?.dataSource; @@ -165,6 +169,7 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { if (player != null) { await player?.dispose(); + player = null; } final uri = Uri.parse(url); From 0c5e4d31d4e8df2f9fe3796da2bc344b1213f9af Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Wed, 28 Aug 2024 11:28:39 -0300 Subject: [PATCH 17/24] fix: Enforce software zoom when using fvp --- lib/providers/settings_provider.dart | 22 +++++++++++++++---- .../lib/unity_video_player_flutter.dart | 4 +++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index 8965b6bd..a5ad099f 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -31,6 +31,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:intl/intl.dart'; import 'package:unity_video_player/unity_video_player.dart'; +import 'package:unity_video_player_main/unity_video_player_main.dart'; enum NetworkUsage { auto, @@ -407,8 +408,23 @@ class SettingsProvider extends UnityProvider { loadFrom: (value) => MatrixType.values[int.parse(value)], saveAs: (value) => value.index.toString(), ); + static bool get isHardwareZoomSupported { + if (Platform.isMacOS || kIsWeb || UpdateManager.isEmbedded) { + return false; + } + + try { + if (UnityVideoPlayerInterface.instance.runtimeType != + UnityVideoPlayerMediaKitInterface) { + return false; + } + } catch (_) {} + + return true; + } + final kSoftwareZooming = _SettingsOption( - def: Platform.isMacOS || kIsWeb || UpdateManager.isEmbedded ? true : false, + def: isHardwareZoomSupported ? true : false, key: 'other.software_zoom', onChanged: (value) { for (final player in UnityPlayers.players.values) { @@ -417,9 +433,7 @@ class SettingsProvider extends UnityProvider { ..zoom.softwareZoom = value; } }, - valueOverrider: Platform.isMacOS || kIsWeb || UpdateManager.isEmbedded - ? () => true - : null, + valueOverrider: isHardwareZoomSupported ? () => true : null, ); final kEventsMatrixedZoom = _SettingsOption( def: true, diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index 4830bf25..af3994d1 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -165,12 +165,13 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { @override Future setDataSource(String url, {bool autoPlay = true}) async { if (url == dataSource) return Future.value(); - debugPrint('Playing $url'); if (player != null) { + debugPrint('Disposing player for $dataSource'); await player?.dispose(); player = null; } + debugPrint('Playing $url'); final uri = Uri.parse(url); @@ -278,6 +279,7 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { @override Future dispose() async { + debugPrint('Disposing player for $dataSource'); await release(); await super.dispose(); await _videoStream.close(); From 1b52172f1eb68a5f27b159605955304c75cbcff2 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Wed, 28 Aug 2024 11:30:58 -0300 Subject: [PATCH 18/24] fix: Sidebar properly release its resources --- lib/screens/layouts/desktop/sidebar.dart | 269 +++++++++++------------ 1 file changed, 133 insertions(+), 136 deletions(-) diff --git a/lib/screens/layouts/desktop/sidebar.dart b/lib/screens/layouts/desktop/sidebar.dart index f5d64f49..9badc158 100644 --- a/lib/screens/layouts/desktop/sidebar.dart +++ b/lib/screens/layouts/desktop/sidebar.dart @@ -35,7 +35,7 @@ class DesktopSidebar extends StatefulWidget { class _DesktopSidebarState extends State { var isSidebarHovering = false; var searchQuery = ''; - final _servers = >{}; + var _servers = >{}; @override void didChangeDependencies() { @@ -46,7 +46,7 @@ class _DesktopSidebarState extends State { void _updateServers() { final servers = context.read(); - _servers.clear(); + _servers = {}; for (final server in servers.servers) { final devices = server.devices.sorted( searchQuery: searchQuery, @@ -90,145 +90,142 @@ class _DesktopSidebarState extends State { child: Material( type: MaterialType.transparency, child: CustomScrollView(slivers: [ - for (final entry in _servers.entries) - () { - final server = entry.key; - final devices = entry.value; - final isLoading = servers.isServerLoading(server); - if (!isLoading && - devices.isEmpty && - searchQuery.isNotEmpty) { - return const SliverToBoxAdapter( - child: SizedBox.shrink(), - ); - } - - /// Whether all the online devices are in the current view. - final isAllInView = devices - .where((d) => d.status) - .every( - (d) => view.currentLayout.devices.contains(d)); - - return MultiSliver(pushPinnedChildren: true, children: [ - SliverPinnedHeader( - child: SubHeader( - server.name, - materialType: MaterialType.canvas, - subtext: () { - if (!settings.checkServerCertificates(server)) { - return loc.certificateNotPassed; - } else if (server.online) { - return loc.nDevices(devices.length); - } else { - return loc.offline; - } - }(), - subtextStyle: TextStyle( - color: !server.online - ? theme.colorScheme.error - : null, - ), - trailing: Builder(builder: (context) { - if (isLoading) { - // wrap in an icon button to ensure ui consistency - return const SquaredIconButton( - onPressed: null, - icon: SizedBox( - height: 16.0, - width: 16.0, - child: CircularProgressIndicator.adaptive( - strokeWidth: 1.5, - ), - ), - ); - } else if (!server.online && - isSidebarHovering) { - return SquaredIconButton( - icon: const Icon(Icons.refresh), - tooltip: loc.refreshServer, - onPressed: () => servers - .refreshDevices(ids: [server.id]), - ); - } else if (isSidebarHovering && - devices.isNotEmpty) { - return SquaredIconButton( - icon: Icon( - isAllInView - ? Icons.playlist_remove - : Icons.playlist_add, + ..._servers.entries.map((entry) { + final server = entry.key; + final devices = entry.value; + final isLoading = servers.isServerLoading(server); + if (!isLoading && + devices.isEmpty && + searchQuery.isNotEmpty) { + return const SliverToBoxAdapter( + child: SizedBox.shrink(), + ); + } + + /// Whether all the online devices are in the current view. + final isAllInView = devices + .where((d) => d.status) + .every((d) => view.currentLayout.devices.contains(d)); + + return MultiSliver(pushPinnedChildren: true, children: [ + SliverPinnedHeader( + child: SubHeader( + server.name, + materialType: MaterialType.canvas, + subtext: () { + if (!settings.checkServerCertificates(server)) { + return loc.certificateNotPassed; + } else if (server.online) { + return loc.nDevices(devices.length); + } else { + return loc.offline; + } + }(), + subtextStyle: TextStyle( + color: !server.online + ? theme.colorScheme.error + : null, + ), + trailing: Builder(builder: (context) { + if (isLoading) { + // wrap in an icon button to ensure ui consistency + return const SquaredIconButton( + onPressed: null, + icon: SizedBox( + height: 16.0, + width: 16.0, + child: CircularProgressIndicator.adaptive( + strokeWidth: 1.5, ), - tooltip: isAllInView - ? loc.removeAllFromView - : loc.addAllToView, - onPressed: () { - if (isAllInView) { - view.removeDevicesFromCurrentLayout( - devices, - ); - } else { - for (final device in devices) { - if (device.status && - !view.currentLayout.devices - .contains(device)) { - view.add(device); - } + ), + ); + } else if (!server.online && isSidebarHovering) { + return SquaredIconButton( + icon: const Icon(Icons.refresh), + tooltip: loc.refreshServer, + onPressed: () => + servers.refreshDevices(ids: [server.id]), + ); + } else if (isSidebarHovering && + devices.isNotEmpty) { + return SquaredIconButton( + icon: Icon( + isAllInView + ? Icons.playlist_remove + : Icons.playlist_add, + ), + tooltip: isAllInView + ? loc.removeAllFromView + : loc.addAllToView, + onPressed: () { + if (isAllInView) { + view.removeDevicesFromCurrentLayout( + devices, + ); + } else { + for (final device in devices) { + if (device.status && + !view.currentLayout.devices + .contains(device)) { + view.add(device); } } - }, - ); - } else { - return const SizedBox.shrink(); - } - }), - ), - ), - if (server.online && !isLoading) - SliverList.builder( - itemCount: devices.length, - itemBuilder: (context, index) { - final device = devices.elementAt(index); - final selected = - view.currentLayout.devices.contains(device); - - final tile = DeviceSelectorTile( - device: device, - selected: selected, + } + }, ); - - if (!device.status && - !settings.kListOfflineDevices.value) { - return const SizedBox.shrink(); - } - if (selected || !device.status) return tile; - - final isBlocked = view.currentLayout.type == - DesktopLayoutType.singleView && - view.currentLayout.devices.isNotEmpty; - - return Draggable( - data: device, - feedback: Card( - child: SizedBox( - height: kDeviceSelectorTileHeight, - width: kSidebarConstraints.maxWidth, - child: Row(children: [ - Expanded(child: tile), - if (isBlocked) - Icon( - Icons.block, - color: theme.colorScheme.error, - size: 18.0, - ), - const SizedBox(width: 16.0), - ]), - ), + } else { + return const SizedBox.shrink(); + } + }), + ), + ), + if (server.online && !isLoading) + SliverList.builder( + itemCount: devices.length, + itemBuilder: (context, index) { + final device = devices.elementAt(index); + final selected = + view.currentLayout.devices.contains(device); + + final tile = DeviceSelectorTile( + device: device, + selected: selected, + ); + + if (!device.status && + !settings.kListOfflineDevices.value) { + return const SizedBox.shrink(); + } + if (selected || !device.status) return tile; + + final isBlocked = view.currentLayout.type == + DesktopLayoutType.singleView && + view.currentLayout.devices.isNotEmpty; + + return Draggable( + data: device, + feedback: Card( + child: SizedBox( + height: kDeviceSelectorTileHeight, + width: kSidebarConstraints.maxWidth, + child: Row(children: [ + Expanded(child: tile), + if (isBlocked) + Icon( + Icons.block, + color: theme.colorScheme.error, + size: 18.0, + ), + const SizedBox(width: 16.0), + ]), ), - child: tile, - ); - }, - ), - ]); - }(), + ), + child: tile, + ); + }, + ), + ]); + }), ]), ), ), From 31c75a78964bf654b0f4c06fab3c3bb2e108f6cf Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Wed, 28 Aug 2024 11:51:38 -0300 Subject: [PATCH 19/24] fix: Empty aspect ratio is 0 --- .../lib/unity_video_player_flutter.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart index af3994d1..7cf326b6 100644 --- a/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart +++ b/packages/unity_video_player/unity_video_player_flutter/lib/unity_video_player_flutter.dart @@ -71,6 +71,7 @@ class UnityVideoPlayerFlutterInterface extends UnityVideoPlayerInterface { return Builder(builder: (context) { return Stack(children: [ + const SizedBox.expand(), Positioned.fill( child: videoBuilder!( context, @@ -238,7 +239,7 @@ class UnityVideoPlayerFlutter extends UnityVideoPlayer { Stream get fpsStream => Stream.value(fps); @override - double get aspectRatio => player?.value.aspectRatio ?? 1.0; + double get aspectRatio => player?.value.aspectRatio ?? 0; @override Future getProperty(String propertyName) { From 9f7796667863d8a85a1540b5204b1a2d4cfc46a2 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Thu, 29 Aug 2024 09:50:47 -0300 Subject: [PATCH 20/24] fix: Do not manually define the video backend --- lib/main.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 5d4826e3..878db172 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -85,13 +85,13 @@ Future main(List args) async { DevHttpOverrides.configureCertificates(); API.initialize(); await UnityVideoPlayerInterface.instance.initialize(); - if (isDesktopPlatform && Platform.isLinux) { - if (isEmbedded) { - UnityVideoPlayerFlutterInterface.registerWith(); - } else { - UnityVideoPlayerMediaKitInterface.registerWith(); - } - } + // if (isDesktopPlatform && Platform.isLinux) { + // if (isEmbedded) { + // UnityVideoPlayerFlutterInterface.registerWith(); + // } else { + // UnityVideoPlayerMediaKitInterface.registerWith(); + // } + // } debugPrint(UnityVideoPlayerInterface.instance.runtimeType.toString()); await configureStorage(); From 03029b6426005a1f04e14a932a5ef9a9eede6ec1 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Thu, 29 Aug 2024 10:01:04 -0300 Subject: [PATCH 21/24] fix: Get server hostname scheme is not correct --- lib/main.dart | 4 ++-- lib/screens/servers/configure_dvr_server.dart | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 878db172..ec967be2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -62,8 +62,8 @@ import 'package:path/path.dart' as path; import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:unity_video_player/unity_video_player.dart'; -import 'package:unity_video_player_flutter/unity_video_player_flutter.dart'; -import 'package:unity_video_player_main/unity_video_player_main.dart'; +// import 'package:unity_video_player_flutter/unity_video_player_flutter.dart'; +// import 'package:unity_video_player_main/unity_video_player_main.dart'; import 'package:window_manager/window_manager.dart'; final navigatorKey = GlobalKey(); diff --git a/lib/screens/servers/configure_dvr_server.dart b/lib/screens/servers/configure_dvr_server.dart index c51f36e2..7500c243 100644 --- a/lib/screens/servers/configure_dvr_server.dart +++ b/lib/screens/servers/configure_dvr_server.dart @@ -68,7 +68,11 @@ class _ConfigureDVRServerScreenState extends State { final finishFocusNode = FocusNode(); String getServerHostname(String text) { - if (Uri.parse(text).scheme.isEmpty) text = 'https://$text'; + try { + if (Uri.parse(text).scheme.isEmpty) text = 'https://$text'; + } catch (e) { + text = 'https://$text'; + } return Uri.parse(text).host; } From 2330c7ee1a3f743aae7119dc30d9bb28ce557f3a Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Thu, 29 Aug 2024 10:05:27 -0300 Subject: [PATCH 22/24] fix: Parsing server devices null issue --- lib/models/server.dart | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/models/server.dart b/lib/models/server.dart index 0baf136b..52d10807 100644 --- a/lib/models/server.dart +++ b/lib/models/server.dart @@ -310,9 +310,14 @@ class Server { port: json['port'], login: json['login'], password: json['password'], - devices: List>.from(json['devices'] as List) - .map(Device.fromJson) - .toList(), + devices: () { + if (json['devices'] == null) return []; + if ((json['devices'] as List).isEmpty) return []; + return List?>.from(json['devices'] as List) + .where((element) => element != null) + .map((device) => Device.fromJson(device!)) + .toList(); + }(), rtspPort: json['rtspPort'], serverUUID: json['serverUUID'], cookie: json['cookie'], From 048f19c3e00833473a65ef9001a929b3131e17e9 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Thu, 29 Aug 2024 13:53:06 -0300 Subject: [PATCH 23/24] fix: Use mpv as default windows video backend --- .../events_timeline/desktop/timeline_card.dart | 12 ++++++------ .../unity_video_player/pubspec.yaml | 2 +- .../unity_video_player_flutter/pubspec.yaml | 2 ++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/screens/events_timeline/desktop/timeline_card.dart b/lib/screens/events_timeline/desktop/timeline_card.dart index 05011180..e45fa658 100644 --- a/lib/screens/events_timeline/desktop/timeline_card.dart +++ b/lib/screens/events_timeline/desktop/timeline_card.dart @@ -72,12 +72,12 @@ class _TimelineCardState extends State { fit: _fit ?? device.server.additionalSettings.videoFit ?? settings.kVideoFit.value, - videoBuilder: (context, video) { - return AspectRatio( - aspectRatio: 16 / 9, - child: video, - ); - }, + // videoBuilder: (context, video) { + // return AspectRatio( + // aspectRatio: 16 / 9, + // child: video, + // ); + // }, paneBuilder: (context, controller) { if (currentEvent == null) { return RepaintBoundary( diff --git a/packages/unity_video_player/unity_video_player/pubspec.yaml b/packages/unity_video_player/unity_video_player/pubspec.yaml index e13a73f3..2d3f03b4 100644 --- a/packages/unity_video_player/unity_video_player/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player/pubspec.yaml @@ -36,6 +36,6 @@ flutter: linux: default_package: unity_video_player_flutter windows: - default_package: unity_video_player_flutter + default_package: unity_video_player_main web: default_package: unity_video_player_flutter diff --git a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml index 07dc4f0a..a675a702 100644 --- a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml @@ -32,4 +32,6 @@ flutter: windows: dartPluginClass: UnityVideoPlayerFlutterInterface linux: + dartPluginClass: UnityVideoPlayerFlutterInterface + web: dartPluginClass: UnityVideoPlayerFlutterInterface \ No newline at end of file From df1b4b1b5d8ec1a6290231d79db822a011e96195 Mon Sep 17 00:00:00 2001 From: Bruno D'Luka Date: Tue, 3 Sep 2024 11:31:37 -0300 Subject: [PATCH 24/24] fix: Correctly list the implementations --- .../unity_video_player_flutter/pubspec.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml index a675a702..29153665 100644 --- a/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml +++ b/packages/unity_video_player/unity_video_player_flutter/pubspec.yaml @@ -29,9 +29,16 @@ flutter: plugin: implements: unity_video_player platforms: + android: + dartPluginClass: UnityVideoPlayerFlutterInterface + ios: + dartPluginClass: UnityVideoPlayerFlutterInterface windows: dartPluginClass: UnityVideoPlayerFlutterInterface + macos: + dartPluginClass: UnityVideoPlayerFlutterInterface linux: dartPluginClass: UnityVideoPlayerFlutterInterface web: - dartPluginClass: UnityVideoPlayerFlutterInterface \ No newline at end of file + pluginClass: UnityVideoPlayerMediaKitInterface + fileName: unity_video_player_flutter.dart \ No newline at end of file