feature: Video BufferSize settings for MPV (#314)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
Julien9969 2025-04-17 13:56:36 -04:00 committed by GitHub
parent 3896bb90f5
commit d4380d5f6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 56 additions and 8 deletions

View file

@ -747,6 +747,10 @@
"@settingsPlayerNativeLibassAccelDesc": {}, "@settingsPlayerNativeLibassAccelDesc": {},
"settingsPlayerNativeLibassAccelTitle": "Native libass subtitles", "settingsPlayerNativeLibassAccelTitle": "Native libass subtitles",
"@settingsPlayerNativeLibassAccelTitle": {}, "@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": "Player",
"@settingsPlayerTitle": {}, "@settingsPlayerTitle": {},
"settingsPlayerVideoHWAccelDesc": "Use the GPU to render video (recommended)", "settingsPlayerVideoHWAccelDesc": "Use the GPU to render video (recommended)",

View file

@ -22,6 +22,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
@Default(false) bool fillScreen, @Default(false) bool fillScreen,
@Default(true) bool hardwareAccel, @Default(true) bool hardwareAccel,
@Default(false) bool useLibass, @Default(false) bool useLibass,
@Default(32) int bufferSize,
PlayerOptions? playerOptions, PlayerOptions? playerOptions,
@Default(100) double internalVolume, @Default(100) double internalVolume,
Set<DeviceOrientation>? allowedOrientations, Set<DeviceOrientation>? allowedOrientations,
@ -42,7 +43,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
PlayerOptions get wantedPlayer => playerOptions ?? PlayerOptions.platformDefaults; PlayerOptions get wantedPlayer => playerOptions ?? PlayerOptions.platformDefaults;
bool playerSame(VideoPlayerSettingsModel other) { 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 @override
@ -55,6 +56,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
other.fillScreen == fillScreen && other.fillScreen == fillScreen &&
other.hardwareAccel == hardwareAccel && other.hardwareAccel == hardwareAccel &&
other.useLibass == useLibass && other.useLibass == useLibass &&
other.bufferSize == bufferSize &&
other.internalVolume == internalVolume && other.internalVolume == internalVolume &&
other.playerOptions == playerOptions && other.playerOptions == playerOptions &&
other.audioDevice == audioDevice; other.audioDevice == audioDevice;
@ -67,6 +69,7 @@ class VideoPlayerSettingsModel with _$VideoPlayerSettingsModel {
fillScreen.hashCode ^ fillScreen.hashCode ^
hardwareAccel.hashCode ^ hardwareAccel.hashCode ^
useLibass.hashCode ^ useLibass.hashCode ^
bufferSize.hashCode ^
internalVolume.hashCode ^ internalVolume.hashCode ^
audioDevice.hashCode; audioDevice.hashCode;
} }

View file

@ -26,6 +26,7 @@ mixin _$VideoPlayerSettingsModel {
bool get fillScreen => throw _privateConstructorUsedError; bool get fillScreen => throw _privateConstructorUsedError;
bool get hardwareAccel => throw _privateConstructorUsedError; bool get hardwareAccel => throw _privateConstructorUsedError;
bool get useLibass => throw _privateConstructorUsedError; bool get useLibass => throw _privateConstructorUsedError;
int get bufferSize => throw _privateConstructorUsedError;
PlayerOptions? get playerOptions => throw _privateConstructorUsedError; PlayerOptions? get playerOptions => throw _privateConstructorUsedError;
double get internalVolume => throw _privateConstructorUsedError; double get internalVolume => throw _privateConstructorUsedError;
Set<DeviceOrientation>? get allowedOrientations => Set<DeviceOrientation>? get allowedOrientations =>
@ -59,6 +60,7 @@ abstract class $VideoPlayerSettingsModelCopyWith<$Res> {
bool fillScreen, bool fillScreen,
bool hardwareAccel, bool hardwareAccel,
bool useLibass, bool useLibass,
int bufferSize,
PlayerOptions? playerOptions, PlayerOptions? playerOptions,
double internalVolume, double internalVolume,
Set<DeviceOrientation>? allowedOrientations, Set<DeviceOrientation>? allowedOrientations,
@ -90,6 +92,7 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
Object? fillScreen = null, Object? fillScreen = null,
Object? hardwareAccel = null, Object? hardwareAccel = null,
Object? useLibass = null, Object? useLibass = null,
Object? bufferSize = null,
Object? playerOptions = freezed, Object? playerOptions = freezed,
Object? internalVolume = null, Object? internalVolume = null,
Object? allowedOrientations = freezed, Object? allowedOrientations = freezed,
@ -120,6 +123,10 @@ class _$VideoPlayerSettingsModelCopyWithImpl<$Res,
? _value.useLibass ? _value.useLibass
: useLibass // ignore: cast_nullable_to_non_nullable : useLibass // ignore: cast_nullable_to_non_nullable
as bool, as bool,
bufferSize: null == bufferSize
? _value.bufferSize
: bufferSize // ignore: cast_nullable_to_non_nullable
as int,
playerOptions: freezed == playerOptions playerOptions: freezed == playerOptions
? _value.playerOptions ? _value.playerOptions
: playerOptions // ignore: cast_nullable_to_non_nullable : playerOptions // ignore: cast_nullable_to_non_nullable
@ -171,6 +178,7 @@ abstract class _$$VideoPlayerSettingsModelImplCopyWith<$Res>
bool fillScreen, bool fillScreen,
bool hardwareAccel, bool hardwareAccel,
bool useLibass, bool useLibass,
int bufferSize,
PlayerOptions? playerOptions, PlayerOptions? playerOptions,
double internalVolume, double internalVolume,
Set<DeviceOrientation>? allowedOrientations, Set<DeviceOrientation>? allowedOrientations,
@ -201,6 +209,7 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
Object? fillScreen = null, Object? fillScreen = null,
Object? hardwareAccel = null, Object? hardwareAccel = null,
Object? useLibass = null, Object? useLibass = null,
Object? bufferSize = null,
Object? playerOptions = freezed, Object? playerOptions = freezed,
Object? internalVolume = null, Object? internalVolume = null,
Object? allowedOrientations = freezed, Object? allowedOrientations = freezed,
@ -231,6 +240,10 @@ class __$$VideoPlayerSettingsModelImplCopyWithImpl<$Res>
? _value.useLibass ? _value.useLibass
: useLibass // ignore: cast_nullable_to_non_nullable : useLibass // ignore: cast_nullable_to_non_nullable
as bool, as bool,
bufferSize: null == bufferSize
? _value.bufferSize
: bufferSize // ignore: cast_nullable_to_non_nullable
as int,
playerOptions: freezed == playerOptions playerOptions: freezed == playerOptions
? _value.playerOptions ? _value.playerOptions
: playerOptions // ignore: cast_nullable_to_non_nullable : playerOptions // ignore: cast_nullable_to_non_nullable
@ -277,6 +290,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
this.fillScreen = false, this.fillScreen = false,
this.hardwareAccel = true, this.hardwareAccel = true,
this.useLibass = false, this.useLibass = false,
this.bufferSize = 32,
this.playerOptions, this.playerOptions,
this.internalVolume = 100, this.internalVolume = 100,
final Set<DeviceOrientation>? allowedOrientations, final Set<DeviceOrientation>? allowedOrientations,
@ -308,6 +322,9 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
@JsonKey() @JsonKey()
final bool useLibass; final bool useLibass;
@override @override
@JsonKey()
final int bufferSize;
@override
final PlayerOptions? playerOptions; final PlayerOptions? playerOptions;
@override @override
@JsonKey() @JsonKey()
@ -346,7 +363,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
@override @override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { 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 @override
@ -359,6 +376,7 @@ class _$VideoPlayerSettingsModelImpl extends _VideoPlayerSettingsModel
..add(DiagnosticsProperty('fillScreen', fillScreen)) ..add(DiagnosticsProperty('fillScreen', fillScreen))
..add(DiagnosticsProperty('hardwareAccel', hardwareAccel)) ..add(DiagnosticsProperty('hardwareAccel', hardwareAccel))
..add(DiagnosticsProperty('useLibass', useLibass)) ..add(DiagnosticsProperty('useLibass', useLibass))
..add(DiagnosticsProperty('bufferSize', bufferSize))
..add(DiagnosticsProperty('playerOptions', playerOptions)) ..add(DiagnosticsProperty('playerOptions', playerOptions))
..add(DiagnosticsProperty('internalVolume', internalVolume)) ..add(DiagnosticsProperty('internalVolume', internalVolume))
..add(DiagnosticsProperty('allowedOrientations', allowedOrientations)) ..add(DiagnosticsProperty('allowedOrientations', allowedOrientations))
@ -393,6 +411,7 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
final bool fillScreen, final bool fillScreen,
final bool hardwareAccel, final bool hardwareAccel,
final bool useLibass, final bool useLibass,
final int bufferSize,
final PlayerOptions? playerOptions, final PlayerOptions? playerOptions,
final double internalVolume, final double internalVolume,
final Set<DeviceOrientation>? allowedOrientations, final Set<DeviceOrientation>? allowedOrientations,
@ -418,6 +437,8 @@ abstract class _VideoPlayerSettingsModel extends VideoPlayerSettingsModel {
@override @override
bool get useLibass; bool get useLibass;
@override @override
int get bufferSize;
@override
PlayerOptions? get playerOptions; PlayerOptions? get playerOptions;
@override @override
double get internalVolume; double get internalVolume;

View file

@ -15,6 +15,7 @@ _$VideoPlayerSettingsModelImpl _$$VideoPlayerSettingsModelImplFromJson(
fillScreen: json['fillScreen'] as bool? ?? false, fillScreen: json['fillScreen'] as bool? ?? false,
hardwareAccel: json['hardwareAccel'] as bool? ?? true, hardwareAccel: json['hardwareAccel'] as bool? ?? true,
useLibass: json['useLibass'] as bool? ?? false, useLibass: json['useLibass'] as bool? ?? false,
bufferSize: (json['bufferSize'] as num?)?.toInt() ?? 32,
playerOptions: playerOptions:
$enumDecodeNullable(_$PlayerOptionsEnumMap, json['playerOptions']), $enumDecodeNullable(_$PlayerOptionsEnumMap, json['playerOptions']),
internalVolume: (json['internalVolume'] as num?)?.toDouble() ?? 100, internalVolume: (json['internalVolume'] as num?)?.toDouble() ?? 100,
@ -47,6 +48,7 @@ Map<String, dynamic> _$$VideoPlayerSettingsModelImplToJson(
'fillScreen': instance.fillScreen, 'fillScreen': instance.fillScreen,
'hardwareAccel': instance.hardwareAccel, 'hardwareAccel': instance.hardwareAccel,
'useLibass': instance.useLibass, 'useLibass': instance.useLibass,
'bufferSize': instance.bufferSize,
'playerOptions': _$PlayerOptionsEnumMap[instance.playerOptions], 'playerOptions': _$PlayerOptionsEnumMap[instance.playerOptions],
'internalVolume': instance.internalVolume, 'internalVolume': instance.internalVolume,
'allowedOrientations': instance.allowedOrientations 'allowedOrientations': instance.allowedOrientations

View file

@ -22,16 +22,16 @@ class DiscoveryInfoMapper extends ClassMapperBase<DiscoveryInfo> {
static String _$id(DiscoveryInfo v) => v.id; static String _$id(DiscoveryInfo v) => v.id;
static const Field<DiscoveryInfo, String> _f$id = static const Field<DiscoveryInfo, String> _f$id =
Field('id', _$id, key: 'Id'); Field('id', _$id, key: r'Id');
static String _$name(DiscoveryInfo v) => v.name; static String _$name(DiscoveryInfo v) => v.name;
static const Field<DiscoveryInfo, String> _f$name = static const Field<DiscoveryInfo, String> _f$name =
Field('name', _$name, key: 'Name'); Field('name', _$name, key: r'Name');
static String _$address(DiscoveryInfo v) => v.address; static String _$address(DiscoveryInfo v) => v.address;
static const Field<DiscoveryInfo, String> _f$address = static const Field<DiscoveryInfo, String> _f$address =
Field('address', _$address, key: 'Address'); Field('address', _$address, key: r'Address');
static String? _$endPointAddress(DiscoveryInfo v) => v.endPointAddress; static String? _$endPointAddress(DiscoveryInfo v) => v.endPointAddress;
static const Field<DiscoveryInfo, String> _f$endPointAddress = static const Field<DiscoveryInfo, String> _f$endPointAddress =
Field('endPointAddress', _$endPointAddress, key: 'EndpointAddress'); Field('endPointAddress', _$endPointAddress, key: r'EndpointAddress');
@override @override
final MappableFields<DiscoveryInfo> fields = const { final MappableFields<DiscoveryInfo> fields = const {

View file

@ -51,7 +51,7 @@ class VideoPlayerSettingsProviderNotifier extends StateNotifier<VideoPlayerSetti
void setHardwareAccel(bool? value) => state = state.copyWith(hardwareAccel: value ?? true); void setHardwareAccel(bool? value) => state = state.copyWith(hardwareAccel: value ?? true);
void setUseLibass(bool? value) => state = state.copyWith(useLibass: value ?? false); 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 setFitType(BoxFit? value) => state = state.copyWith(videoFit: value ?? BoxFit.contain);
void setVolume(double value) { void setVolume(double value) {

View file

@ -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/settings_message_box.dart';
import 'package:fladder/screens/settings/widgets/subtitle_editor.dart'; import 'package:fladder/screens/settings/widgets/subtitle_editor.dart';
import 'package:fladder/screens/shared/animated_fade_size.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/screens/video_player/components/video_player_options_sheet.dart';
import 'package:fladder/util/adaptive_layout.dart'; import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/bitrate_helper.dart'; import 'package:fladder/util/bitrate_helper.dart';
@ -230,6 +231,21 @@ class _PlayerSettingsPageState extends ConsumerState<PlayerSettingsPage> {
: Container(), : 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( SettingsListTile(
label: Text(context.localized.settingsPlayerCustomSubtitlesTitle), label: Text(context.localized.settingsPlayerCustomSubtitlesTitle),
subLabel: Text(context.localized.settingsPlayerCustomSubtitlesDesc), subLabel: Text(context.localized.settingsPlayerCustomSubtitlesDesc),

View file

@ -25,6 +25,7 @@ extension StringExtensions on String {
var buffer = StringBuffer(); var buffer = StringBuffer();
var split = this.split(' '); var split = this.split(' ');
for (var i = 0; i < (limitTo.clamp(0, split.length)); i++) { for (var i = 0; i < (limitTo.clamp(0, split.length)); i++) {
if (split[i].isEmpty) continue;
buffer.write(split[i][0]); buffer.write(split[i][0]);
} }

View file

@ -31,12 +31,13 @@ class LibMPV extends BasePlayer {
dispose(); dispose();
mpv.MediaKit.ensureInitialized(); mpv.MediaKit.ensureInitialized();
_player = mpv.Player( _player = mpv.Player(
configuration: mpv.PlayerConfiguration( configuration: mpv.PlayerConfiguration(
title: "nl.jknaapen.fladder", title: "nl.jknaapen.fladder",
libassAndroidFont: libassFallbackFont, libassAndroidFont: libassFallbackFont,
libass: !kIsWeb && settings.useLibass, libass: !kIsWeb && settings.useLibass,
bufferSize: settings.bufferSize * 1024 * 1024, // MPV uses buffer size in bytes
), ),
); );