mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-20 17:30:13 +08:00
feat: custom buffer size (#2370)
* feat: custom buffer size * cache buffer params --------- Co-authored-by: dom <githubaccount56556@proton.me>
This commit is contained in:
@@ -60,9 +60,7 @@ class _CachedNetworkSVGImageState extends State<CachedNetworkSVGImage> {
|
||||
double? height;
|
||||
late TextScaler textScaler;
|
||||
|
||||
static final _sizeRegExp = RegExp(
|
||||
r'height="([\d\.]+)([c-x]{2})?"',
|
||||
);
|
||||
static final _sizeRegExp = RegExp(r'height="([\d\.]+)([c-x]{2})?"');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
||||
@@ -16,6 +16,7 @@ import 'package:PiliPlus/pages/setting/widgets/slider_dialog.dart';
|
||||
import 'package:PiliPlus/services/download/download_service.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
import 'package:PiliPlus/utils/filtering_text.dart';
|
||||
import 'package:PiliPlus/utils/path_utils.dart';
|
||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
@@ -24,7 +25,6 @@ import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart' hide RefreshIndicator;
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
@@ -229,9 +229,7 @@ void _showTouchSlopDialog(BuildContext context, VoidCallback setState) {
|
||||
initialValue: initialValue,
|
||||
keyboardType: const .numberWithOptions(decimal: true),
|
||||
onChanged: (value) => initialValue = value,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d\.]+')),
|
||||
],
|
||||
inputFormatters: FilteringText.decimal,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
@@ -417,9 +415,7 @@ void _showCacheDialog(BuildContext context, VoidCallback setState) {
|
||||
autofocus: true,
|
||||
onChanged: (value) => valueStr = value,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d\.]+')),
|
||||
],
|
||||
inputFormatters: FilteringText.decimal,
|
||||
decoration: const InputDecoration(suffixText: 'MB'),
|
||||
),
|
||||
actions: [
|
||||
|
||||
@@ -10,12 +10,14 @@ import 'package:PiliPlus/pages/setting/widgets/ordered_multi_select_dialog.dart'
|
||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/audio_output_type.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/hwdec_type.dart';
|
||||
import 'package:PiliPlus/utils/filtering_text.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/video_utils.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
@@ -102,6 +104,20 @@ List<SettingsModel> get videoSettings => [
|
||||
getSubtitle: () => '当前:${Pref.audioOutput}',
|
||||
onTap: _showAudioOutputDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '缓冲大小',
|
||||
leading: const Icon(Icons.storage_outlined),
|
||||
getSubtitle: () =>
|
||||
'当前:${Pref.bufferSize}MB。同时为前向和后向缓冲区大小。对于直播流,无后向缓冲大小,全部转给前向(此选项即mpv的--demuxer-max-bytes,--demuxer-max-back-bytes)',
|
||||
onTap: _showBufferSizeDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '缓冲时长',
|
||||
leading: const Icon(Icons.av_timer),
|
||||
getSubtitle: () =>
|
||||
'当前:${Pref.bufferSec}s。实际缓冲为二者最小值。对于直播流,该选项无效(此选项即mpv的--cache-secs)',
|
||||
onTap: _showBufferSecDialog,
|
||||
),
|
||||
NormalModel(
|
||||
title: '视频同步',
|
||||
leading: const Icon(Icons.view_timeline_outlined),
|
||||
@@ -399,3 +415,70 @@ Future<void> _showHwDecDialog(
|
||||
setState();
|
||||
}
|
||||
}
|
||||
|
||||
void _showDecimalDialog(
|
||||
BuildContext context,
|
||||
VoidCallback setState, {
|
||||
required String key,
|
||||
required double defVal,
|
||||
required Widget title,
|
||||
required InputDecoration? decoration,
|
||||
}) {
|
||||
String value = (GStorage.setting.get(key) ?? defVal).toString();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: title,
|
||||
content: TextFormField(
|
||||
autofocus: true,
|
||||
initialValue: value,
|
||||
keyboardType: const .numberWithOptions(decimal: true),
|
||||
onChanged: (val) => value = val,
|
||||
inputFormatters: FilteringText.decimal,
|
||||
decoration: decoration,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(color: ColorScheme.of(context).outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
final val = double.parse(value);
|
||||
Get.back();
|
||||
await GStorage.setting.put(key, val);
|
||||
setState();
|
||||
} catch (e) {
|
||||
SmartDialog.showToast(e.toString());
|
||||
}
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showBufferSizeDialog(BuildContext context, VoidCallback setState) =>
|
||||
_showDecimalDialog(
|
||||
context,
|
||||
setState,
|
||||
key: SettingBoxKey.bufferSize,
|
||||
defVal: Pref.bufferSize,
|
||||
title: const Text('缓冲大小'),
|
||||
decoration: const InputDecoration(suffixText: 'MB'),
|
||||
);
|
||||
|
||||
void _showBufferSecDialog(BuildContext context, VoidCallback setState) =>
|
||||
_showDecimalDialog(
|
||||
context,
|
||||
setState,
|
||||
key: SettingBoxKey.bufferSec,
|
||||
defVal: Pref.bufferSec,
|
||||
title: const Text('缓冲时长'),
|
||||
decoration: const InputDecoration(suffixText: 's'),
|
||||
);
|
||||
|
||||
@@ -4,11 +4,11 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart';
|
||||
import 'package:PiliPlus/common/widgets/scaffold.dart';
|
||||
import 'package:PiliPlus/common/widgets/view_safe_area.dart';
|
||||
import 'package:PiliPlus/utils/extension/context_ext.dart';
|
||||
import 'package:PiliPlus/utils/filtering_text.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:flutter/material.dart' hide ListTile;
|
||||
import 'package:flutter/services.dart' show FilteringTextInputFormatter;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive_ce/hive.dart';
|
||||
@@ -73,9 +73,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||
border: OutlineInputBorder(borderRadius: .all(.circular(6))),
|
||||
),
|
||||
onChanged: (value) => initialValue = value,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d\.]+')),
|
||||
],
|
||||
inputFormatters: FilteringText.decimal,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -809,12 +809,6 @@ class HeaderControlState extends State<HeaderControl>
|
||||
onTap: () =>
|
||||
Utils.copyText('VideoTrack\n${state.track.audio}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("pitch"),
|
||||
subtitle: Text(state.pitch.toString()),
|
||||
onTap: () => Utils.copyText('pitch\n${state.pitch}'),
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text("rate"),
|
||||
|
||||
@@ -597,7 +597,6 @@ class PlPlayerController with BlockConfigMixin {
|
||||
|
||||
final player = await Player.create(
|
||||
configuration: PlayerConfiguration(
|
||||
bufferSize: isLive ? 16 * 1024 * 1024 : 4 * 1024 * 1024,
|
||||
logLevel: kDebugMode ? .warn : .error,
|
||||
options: opt,
|
||||
),
|
||||
@@ -614,17 +613,38 @@ class PlPlayerController with BlockConfigMixin {
|
||||
),
|
||||
);
|
||||
|
||||
player.setMediaHeader(
|
||||
userAgent: BrowserUa.pc,
|
||||
referer: HttpString.baseUrl,
|
||||
);
|
||||
// await player.setAudioTrack(.auto());
|
||||
player.setMediaHeader(userAgent: BrowserUa.pc, referer: HttpString.baseUrl);
|
||||
|
||||
_startListeners(player);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
Map<String, String>? _buffer;
|
||||
Map<String, String> get buffer => _buffer ??= _initBuffer();
|
||||
Map<String, String>? _liveBuffer;
|
||||
Map<String, String> get liveBuffer => _liveBuffer ??= _initLiveBuffer();
|
||||
|
||||
Map<String, String> _initBuffer() {
|
||||
final bufSec = Pref.bufferSec * _playbackSpeed.value;
|
||||
final bufSiz = (Pref.bufferSize * 0x100000).toStringAsFixed(0);
|
||||
return {
|
||||
'cache': 'yes',
|
||||
'cache-secs': bufSec.toStringAsFixed(3),
|
||||
'demuxer-hysteresis-secs': (bufSec / 1.5).toStringAsFixed(3),
|
||||
'demuxer-max-bytes': bufSiz,
|
||||
'demuxer-max-back-bytes': bufSiz,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, String> _initLiveBuffer() {
|
||||
return {
|
||||
'cache': 'yes',
|
||||
'demuxer-max-bytes': (Pref.bufferSize * 0x200000).toStringAsFixed(0),
|
||||
'demuxer-max-back-bytes': '0',
|
||||
};
|
||||
}
|
||||
|
||||
// 配置播放器
|
||||
Future<void> _createVideoController(
|
||||
DataSource dataSource,
|
||||
@@ -654,6 +674,16 @@ class PlPlayerController with BlockConfigMixin {
|
||||
|
||||
final Map<String, String> extras = {};
|
||||
|
||||
if (dataSource is FileSource) {
|
||||
extras['cache'] = 'no';
|
||||
} else {
|
||||
if (isLive) {
|
||||
extras.addAll(liveBuffer);
|
||||
} else {
|
||||
extras.addAll(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
String video = dataSource.videoSource;
|
||||
if (dataSource.audioSource case final audio? when (audio.isNotEmpty)) {
|
||||
if (onlyPlayAudio.value) {
|
||||
@@ -678,11 +708,8 @@ class PlPlayerController with BlockConfigMixin {
|
||||
if (dataSource is FileSource) {
|
||||
return null;
|
||||
}
|
||||
if (_videoPlayerController?.current.isNotEmpty ?? false) {
|
||||
return _videoPlayerController!.open(
|
||||
_videoPlayerController!.current.last.copyWith(start: position),
|
||||
play: true,
|
||||
);
|
||||
if (_videoPlayerController case final ctr? when (ctr.current.isNotEmpty)) {
|
||||
return ctr.open(ctr.current.last.copyWith(start: position), play: true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
7
lib/utils/filtering_text.dart
Normal file
7
lib/utils/filtering_text.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
abstract final class FilteringText {
|
||||
static final decimal = [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[\d\.]+')),
|
||||
];
|
||||
}
|
||||
@@ -9,6 +9,8 @@ abstract final class SettingBoxKey {
|
||||
secondDecode = 'secondDecode',
|
||||
defaultPicQa = 'defaultPicQa',
|
||||
audioOutput = 'audioOutput',
|
||||
bufferSize = 'bufferSize',
|
||||
bufferSec = 'bufferSec',
|
||||
hardwareDecoding = 'hardwareDecoding',
|
||||
videoSync = 'videoSync',
|
||||
enableOnlineTotal = 'enableOnlineTotal',
|
||||
|
||||
@@ -429,6 +429,12 @@ abstract final class Pref {
|
||||
defaultValue: PlatformUtils.isMobile ? 5 : 6,
|
||||
);
|
||||
|
||||
static double get bufferSize =>
|
||||
_setting.get(SettingBoxKey.bufferSize, defaultValue: 4.0);
|
||||
|
||||
static double get bufferSec =>
|
||||
_setting.get(SettingBoxKey.bufferSec, defaultValue: 16.0);
|
||||
|
||||
static String get audioOutput => _setting.get(
|
||||
SettingBoxKey.audioOutput,
|
||||
defaultValue: AudioOutput.defaultValue,
|
||||
|
||||
14
pubspec.lock
14
pubspec.lock
@@ -1077,7 +1077,7 @@ packages:
|
||||
description:
|
||||
path: media_kit
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.1.11"
|
||||
@@ -1086,7 +1086,7 @@ packages:
|
||||
description:
|
||||
path: "libs/android/media_kit_libs_android_video"
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.3.7"
|
||||
@@ -1095,7 +1095,7 @@ packages:
|
||||
description:
|
||||
path: "libs/ios/media_kit_libs_ios_video"
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.1.4"
|
||||
@@ -1120,7 +1120,7 @@ packages:
|
||||
description:
|
||||
path: "libs/universal/media_kit_libs_video"
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.0.5"
|
||||
@@ -1129,7 +1129,7 @@ packages:
|
||||
description:
|
||||
path: "libs/windows/media_kit_libs_windows_video"
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.0.10"
|
||||
@@ -1138,7 +1138,7 @@ packages:
|
||||
description:
|
||||
path: media_kit_native_event_loop
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.0.9"
|
||||
@@ -1147,7 +1147,7 @@ packages:
|
||||
description:
|
||||
path: media_kit_video
|
||||
ref: "version_1.2.5"
|
||||
resolved-ref: e6c3481025959a23c259aa6072a28cebaa1c0fcc
|
||||
resolved-ref: deac6b62569584b6a5e28e6c60c187a0a7281b3a
|
||||
url: "https://github.com/My-Responsitories/media-kit.git"
|
||||
source: git
|
||||
version: "1.2.5"
|
||||
|
||||
Reference in New Issue
Block a user