From d4380d5f6f22f1e7d6b82eb4a4c56c89185dffb6 Mon Sep 17 00:00:00 2001 From: Julien9969 <89881833+Julien9969@users.noreply.github.com> Date: Thu, 17 Apr 2025 13:56:36 -0400 Subject: [PATCH] feature: Video BufferSize settings for MPV (#314) Co-authored-by: PartyDonut --- lib/l10n/app_en.arb | 4 ++++ .../settings/video_player_settings.dart | 5 +++- .../video_player_settings.freezed.dart | 23 ++++++++++++++++++- .../settings/video_player_settings.g.dart | 2 ++ lib/providers/discovery_provider.mapper.dart | 8 +++---- .../video_player_settings_provider.dart | 2 +- .../settings/player_settings_page.dart | 16 +++++++++++++ lib/util/string_extensions.dart | 1 + lib/wrappers/players/lib_mpv.dart | 3 ++- 9 files changed, 56 insertions(+), 8 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f32ae7e..f392f79 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -747,6 +747,10 @@ "@settingsPlayerNativeLibassAccelDesc": {}, "settingsPlayerNativeLibassAccelTitle": "Native libass subtitles", "@settingsPlayerNativeLibassAccelTitle": {}, + "settingsPlayerBufferSizeTitle": "Video buffer size", + "@settingsPlayerBufferSizeTitle": {}, + "settingsPlayerBufferSizeDesc": "Configure the buffer size for video playback, determining how much data is loaded into the cache.", + "@settingsPlayerBufferSizeDesc": {}, "settingsPlayerTitle": "Player", "@settingsPlayerTitle": {}, "settingsPlayerVideoHWAccelDesc": "Use the GPU to render video (recommended)", diff --git a/lib/models/settings/video_player_settings.dart b/lib/models/settings/video_player_settings.dart index dbc99fc..71f1499 100644 --- a/lib/models/settings/video_player_settings.dart +++ b/lib/models/settings/video_player_settings.dart @@ -22,6 +22,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel { @Default(false) bool fillScreen, @Default(true) bool hardwareAccel, @Default(false) bool useLibass, + @Default(32) int bufferSize, PlayerOptions? playerOptions, @Default(100) double internalVolume, Set? allowedOrientations, @@ -42,7 +43,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel { PlayerOptions get wantedPlayer => playerOptions ?? PlayerOptions.platformDefaults; bool playerSame(VideoPlayerSettingsModel other) { - return other.hardwareAccel == hardwareAccel && other.useLibass == useLibass && other.wantedPlayer == wantedPlayer; + return other.hardwareAccel == hardwareAccel && other.useLibass == useLibass && other.bufferSize == bufferSize && other.wantedPlayer == wantedPlayer; } @override @@ -55,6 +56,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel { other.fillScreen == fillScreen && other.hardwareAccel == hardwareAccel && other.useLibass == useLibass && + other.bufferSize == bufferSize && other.internalVolume == internalVolume && other.playerOptions == playerOptions && other.audioDevice == audioDevice; @@ -67,6 +69,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel { fillScreen.hashCode ^ hardwareAccel.hashCode ^ useLibass.hashCode ^ + bufferSize.hashCode ^ internalVolume.hashCode ^ audioDevice.hashCode; } diff --git a/lib/models/settings/video_player_settings.freezed.dart b/lib/models/settings/video_player_settings.freezed.dart index b15464e..736ca45 100644 --- a/lib/models/settings/video_player_settings.freezed.dart +++ b/lib/models/settings/video_player_settings.freezed.dart @@ -26,6 +26,7 @@ mixin _$VideoPlayerSettingsModel { bool get fillScreen => throw _privateConstructorUsedError; bool get hardwareAccel => throw _privateConstructorUsedError; bool get useLibass => throw _privateConstructorUsedError; + int get bufferSize => throw _privateConstructorUsedError; PlayerOptions? get playerOptions => throw _privateConstructorUsedError; double get internalVolume => throw _privateConstructorUsedError; Set? get allowedOrientations => @@ -59,6 +60,7 @@ abstract class $VideoPlayerSettingsModelCopyWith<$Res> { bool fillScreen, bool hardwareAccel, bool useLibass, + int bufferSize, PlayerOptions? playerOptions, double internalVolume, Set? allowedOrientations, @@ -90,6 +92,7 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res, Object? fillScreen = null, Object? hardwareAccel = null, Object? useLibass = null, + Object? bufferSize = null, Object? playerOptions = freezed, Object? internalVolume = null, Object? allowedOrientations = freezed, @@ -120,6 +123,10 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res, ? _value.useLibass : useLibass // ignore: cast_nullable_to_non_nullable as bool, + bufferSize: null == bufferSize + ? _value.bufferSize + : bufferSize // ignore: cast_nullable_to_non_nullable + as int, playerOptions: freezed == playerOptions ? _value.playerOptions : playerOptions // ignore: cast_nullable_to_non_nullable @@ -171,6 +178,7 @@ abstract class _$$VideoPlayerSettingsModelImplCopyWith<$Res> bool fillScreen, bool hardwareAccel, bool useLibass, + int bufferSize, PlayerOptions? playerOptions, double internalVolume, Set? allowedOrientations, @@ -201,6 +209,7 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res> Object? fillScreen = null, Object? hardwareAccel = null, Object? useLibass = null, + Object? bufferSize = null, Object? playerOptions = freezed, Object? internalVolume = null, Object? allowedOrientations = freezed, @@ -231,6 +240,10 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res> ? _value.useLibass : useLibass // ignore: cast_nullable_to_non_nullable as bool, + bufferSize: null == bufferSize + ? _value.bufferSize + : bufferSize // ignore: cast_nullable_to_non_nullable + as int, playerOptions: freezed == playerOptions ? _value.playerOptions : playerOptions // ignore: cast_nullable_to_non_nullable @@ -277,6 +290,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel this.fillScreen = false, this.hardwareAccel = true, this.useLibass = false, + this.bufferSize = 32, this.playerOptions, this.internalVolume = 100, final Set? allowedOrientations, @@ -308,6 +322,9 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel @JsonKey() final bool useLibass; @override + @JsonKey() + final int bufferSize; + @override final PlayerOptions? playerOptions; @override @JsonKey() @@ -346,7 +363,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel @override String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { - return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, playerOptions: $playerOptions, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, maxHomeBitrate: $maxHomeBitrate, maxInternetBitrate: $maxInternetBitrate, audioDevice: $audioDevice, segmentSkipSettings: $segmentSkipSettings)'; + return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, bufferSize: $bufferSize, playerOptions: $playerOptions, internalVolume: $internalVolume, allowedOrientations: $allowedOrientations, nextVideoType: $nextVideoType, maxHomeBitrate: $maxHomeBitrate, maxInternetBitrate: $maxInternetBitrate, audioDevice: $audioDevice, segmentSkipSettings: $segmentSkipSettings)'; } @override @@ -359,6 +376,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel ..add(DiagnosticsProperty('fillScreen', fillScreen)) ..add(DiagnosticsProperty('hardwareAccel', hardwareAccel)) ..add(DiagnosticsProperty('useLibass', useLibass)) + ..add(DiagnosticsProperty('bufferSize', bufferSize)) ..add(DiagnosticsProperty('playerOptions', playerOptions)) ..add(DiagnosticsProperty('internalVolume', internalVolume)) ..add(DiagnosticsProperty('allowedOrientations', allowedOrientations)) @@ -393,6 +411,7 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel { final bool fillScreen, final bool hardwareAccel, final bool useLibass, + final int bufferSize, final PlayerOptions? playerOptions, final double internalVolume, final Set? allowedOrientations, @@ -418,6 +437,8 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel { @override bool get useLibass; @override + int get bufferSize; + @override PlayerOptions? get playerOptions; @override double get internalVolume; diff --git a/lib/models/settings/video_player_settings.g.dart b/lib/models/settings/video_player_settings.g.dart index 6743497..a00fbb2 100644 --- a/lib/models/settings/video_player_settings.g.dart +++ b/lib/models/settings/video_player_settings.g.dart @@ -15,6 +15,7 @@ _$VideoPlayerSettingsModelImpl _$$VideoPlayerSettingsModelImplFromJson( fillScreen: json['fillScreen'] as bool? ?? false, hardwareAccel: json['hardwareAccel'] as bool? ?? true, useLibass: json['useLibass'] as bool? ?? false, + bufferSize: (json['bufferSize'] as num?)?.toInt() ?? 32, playerOptions: $enumDecodeNullable(_$PlayerOptionsEnumMap, json['playerOptions']), internalVolume: (json['internalVolume'] as num?)?.toDouble() ?? 100, @@ -47,6 +48,7 @@ Map _$$VideoPlayerSettingsModelImplToJson( 'fillScreen': instance.fillScreen, 'hardwareAccel': instance.hardwareAccel, 'useLibass': instance.useLibass, + 'bufferSize': instance.bufferSize, 'playerOptions': _$PlayerOptionsEnumMap[instance.playerOptions], 'internalVolume': instance.internalVolume, 'allowedOrientations': instance.allowedOrientations diff --git a/lib/providers/discovery_provider.mapper.dart b/lib/providers/discovery_provider.mapper.dart index 1d25071..aeb8044 100644 --- a/lib/providers/discovery_provider.mapper.dart +++ b/lib/providers/discovery_provider.mapper.dart @@ -22,16 +22,16 @@ class DiscoveryInfoMapper extends ClassMapperBase { static String _$id(DiscoveryInfo v) => v.id; static const Field _f$id = - Field('id', _$id, key: 'Id'); + Field('id', _$id, key: r'Id'); static String _$name(DiscoveryInfo v) => v.name; static const Field _f$name = - Field('name', _$name, key: 'Name'); + Field('name', _$name, key: r'Name'); static String _$address(DiscoveryInfo v) => v.address; static const Field _f$address = - Field('address', _$address, key: 'Address'); + Field('address', _$address, key: r'Address'); static String? _$endPointAddress(DiscoveryInfo v) => v.endPointAddress; static const Field _f$endPointAddress = - Field('endPointAddress', _$endPointAddress, key: 'EndpointAddress'); + Field('endPointAddress', _$endPointAddress, key: r'EndpointAddress'); @override final MappableFields fields = const { diff --git a/lib/providers/settings/video_player_settings_provider.dart b/lib/providers/settings/video_player_settings_provider.dart index 55b77c9..4e52f89 100644 --- a/lib/providers/settings/video_player_settings_provider.dart +++ b/lib/providers/settings/video_player_settings_provider.dart @@ -51,7 +51,7 @@ class VideoPlayerSettingsProviderNotifier extends StateNotifier state = state.copyWith(hardwareAccel: value ?? true); void setUseLibass(bool? value) => state = state.copyWith(useLibass: value ?? false); - + void setBufferSize(int? value) => state = state.copyWith(bufferSize: value ?? 32); void setFitType(BoxFit? value) => state = state.copyWith(videoFit: value ?? BoxFit.contain); void setVolume(double value) { diff --git a/lib/screens/settings/player_settings_page.dart b/lib/screens/settings/player_settings_page.dart index 3c45e57..2e5eb22 100644 --- a/lib/screens/settings/player_settings_page.dart +++ b/lib/screens/settings/player_settings_page.dart @@ -18,6 +18,7 @@ import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; import 'package:fladder/screens/settings/widgets/settings_message_box.dart'; import 'package:fladder/screens/settings/widgets/subtitle_editor.dart'; import 'package:fladder/screens/shared/animated_fade_size.dart'; +import 'package:fladder/screens/shared/input_fields.dart'; import 'package:fladder/screens/video_player/components/video_player_options_sheet.dart'; import 'package:fladder/util/adaptive_layout.dart'; import 'package:fladder/util/bitrate_helper.dart'; @@ -230,6 +231,21 @@ class _PlayerSettingsPageState extends ConsumerState { : Container(), ), ], + SettingsListTile( + label: Text(context.localized.settingsPlayerBufferSizeTitle), + subLabel: Text(context.localized.settingsPlayerBufferSizeDesc), + trailing: SizedBox( + width: 70, + child: IntInputField( + suffix: 'MB', + controller: TextEditingController(text: videoSettings.bufferSize.toString()), + onSubmitted: (value) { + if (value != null) { + provider.setBufferSize(value); + } + }, + )), + ), SettingsListTile( label: Text(context.localized.settingsPlayerCustomSubtitlesTitle), subLabel: Text(context.localized.settingsPlayerCustomSubtitlesDesc), diff --git a/lib/util/string_extensions.dart b/lib/util/string_extensions.dart index 18da0aa..b7f8982 100644 --- a/lib/util/string_extensions.dart +++ b/lib/util/string_extensions.dart @@ -25,6 +25,7 @@ extension StringExtensions on String { var buffer = StringBuffer(); var split = this.split(' '); for (var i = 0; i < (limitTo.clamp(0, split.length)); i++) { + if (split[i].isEmpty) continue; buffer.write(split[i][0]); } diff --git a/lib/wrappers/players/lib_mpv.dart b/lib/wrappers/players/lib_mpv.dart index c9ee9c0..a0ac078 100644 --- a/lib/wrappers/players/lib_mpv.dart +++ b/lib/wrappers/players/lib_mpv.dart @@ -31,12 +31,13 @@ class LibMPV extends BasePlayer { dispose(); mpv.MediaKit.ensureInitialized(); - + _player = mpv.Player( configuration: mpv.PlayerConfiguration( title: "nl.jknaapen.fladder", libassAndroidFont: libassFallbackFont, libass: !kIsWeb && settings.useLibass, + bufferSize: settings.bufferSize * 1024 * 1024, // MPV uses buffer size in bytes ), );