mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-26 12:07:11 +08:00
feat: loudnorm (#1358)
* feat: loudnorm * fix * fix: android only * fix: toString
This commit is contained in:
committed by
GitHub
parent
046412b709
commit
22c57bf468
@@ -15,6 +15,7 @@ import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart';
|
||||
import 'package:PiliPlus/models/common/super_resolution_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_type.dart';
|
||||
import 'package:PiliPlus/models/user/danmaku_rule.dart';
|
||||
import 'package:PiliPlus/models/video/play/url.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_shot/data.dart';
|
||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart';
|
||||
@@ -54,7 +55,6 @@ import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
class PlPlayerController {
|
||||
@@ -598,6 +598,7 @@ class PlPlayerController {
|
||||
int? pgcType,
|
||||
VideoType? videoType,
|
||||
VoidCallback? callback,
|
||||
Volume? volume,
|
||||
}) async {
|
||||
try {
|
||||
_isLive = isLive;
|
||||
@@ -637,6 +638,7 @@ class PlPlayerController {
|
||||
dataSource,
|
||||
_looping,
|
||||
seekTo,
|
||||
volume,
|
||||
);
|
||||
callback?.call();
|
||||
// 获取视频时长 00:00
|
||||
@@ -716,7 +718,7 @@ class PlPlayerController {
|
||||
setting.put(SettingBoxKey.superResolutionType, type.index);
|
||||
}
|
||||
}
|
||||
pp ??= _videoPlayerController?.platform as NativePlayer;
|
||||
pp ??= _videoPlayerController!.platform!;
|
||||
await pp.waitForPlayerInitialization;
|
||||
await pp.waitForVideoControllerInitializationIfAttached;
|
||||
switch (type) {
|
||||
@@ -745,11 +747,14 @@ class PlPlayerController {
|
||||
}
|
||||
}
|
||||
|
||||
static final loudnormRegExp = RegExp('loudnorm=[^,]+');
|
||||
|
||||
// 配置播放器
|
||||
Future<Player> _createVideoController(
|
||||
DataSource dataSource,
|
||||
PlaylistMode looping,
|
||||
Duration? seekTo,
|
||||
Volume? volume,
|
||||
) async {
|
||||
// 每次配置时先移除监听
|
||||
removeListeners();
|
||||
@@ -759,6 +764,7 @@ class PlPlayerController {
|
||||
_position.value = Duration.zero;
|
||||
// 初始化时清空弹幕,防止上次重叠
|
||||
danmakuController?.clear();
|
||||
|
||||
Player player =
|
||||
_videoPlayerController ??
|
||||
Player(
|
||||
@@ -769,20 +775,14 @@ class PlPlayerController {
|
||||
: (isLive ? 16 * 1024 * 1024 : 4 * 1024 * 1024),
|
||||
),
|
||||
);
|
||||
var pp = player.platform as NativePlayer;
|
||||
final pp = player.platform!;
|
||||
if (_videoPlayerController == null) {
|
||||
if (isAnim) {
|
||||
setShader(superResolutionType.value, pp);
|
||||
}
|
||||
String audioNormalization = Pref.audioNormalization;
|
||||
audioNormalization = switch (audioNormalization) {
|
||||
'0' => '',
|
||||
'1' => ',${AudioNormalization.dynaudnorm.param}',
|
||||
_ => ',$audioNormalization',
|
||||
};
|
||||
await pp.setProperty(
|
||||
"af",
|
||||
"scaletempo2=max-speed=8$audioNormalization",
|
||||
"scaletempo2=max-speed=8",
|
||||
);
|
||||
if (Platform.isAndroid) {
|
||||
await pp.setProperty("volume-max", "100");
|
||||
@@ -804,7 +804,7 @@ class PlPlayerController {
|
||||
if (dataSource.audioSource?.isNotEmpty == true) {
|
||||
await pp.setProperty(
|
||||
'audio-files',
|
||||
UniversalPlatform.isWindows
|
||||
Platform.isWindows
|
||||
? dataSource.audioSource!.replaceAll(';', '\\;')
|
||||
: dataSource.audioSource!.replaceAll(':', '\\:'),
|
||||
);
|
||||
@@ -816,7 +816,7 @@ class PlPlayerController {
|
||||
if (dataSource.subFiles?.isNotEmpty == true) {
|
||||
await pp.setProperty(
|
||||
'sub-files',
|
||||
UniversalPlatform.isWindows
|
||||
Platform.isWindows
|
||||
? dataSource.subFiles!.replaceAll(';', '\\;')
|
||||
: dataSource.subFiles!.replaceAll(':', '\\:'),
|
||||
);
|
||||
@@ -835,12 +835,44 @@ class PlPlayerController {
|
||||
);
|
||||
|
||||
player.setPlaylistMode(looping);
|
||||
|
||||
final Map<String, String>? filters;
|
||||
if (kDebugMode || Platform.isAndroid) {
|
||||
String audioNormalization = '';
|
||||
audioNormalization = AudioNormalization.getParamFromConfig(
|
||||
Pref.audioNormalization,
|
||||
);
|
||||
if (volume != null && volume.isNotEmpty) {
|
||||
audioNormalization = audioNormalization.replaceFirstMapped(
|
||||
loudnormRegExp,
|
||||
(i) => '${i[0]}:$volume',
|
||||
);
|
||||
} else {
|
||||
audioNormalization = audioNormalization.replaceFirst(
|
||||
loudnormRegExp,
|
||||
AudioNormalization.getParamFromConfig(Pref.fallbackNormalization),
|
||||
);
|
||||
}
|
||||
filters = audioNormalization.isEmpty
|
||||
? null
|
||||
: {'lavfi-complex': '"[aid1] $audioNormalization [ao]"'};
|
||||
} else {
|
||||
filters = null;
|
||||
}
|
||||
|
||||
if (kDebugMode) debugPrint(filters.toString());
|
||||
|
||||
if (dataSource.type == DataSourceType.asset) {
|
||||
final assetUrl = dataSource.videoSource!.startsWith("asset://")
|
||||
? dataSource.videoSource!
|
||||
: "asset://${dataSource.videoSource!}";
|
||||
await player.open(
|
||||
Media(assetUrl, httpHeaders: dataSource.httpHeaders, start: seekTo),
|
||||
Media(
|
||||
assetUrl,
|
||||
httpHeaders: dataSource.httpHeaders,
|
||||
start: seekTo,
|
||||
extras: filters,
|
||||
),
|
||||
play: false,
|
||||
);
|
||||
} else {
|
||||
@@ -849,6 +881,7 @@ class PlPlayerController {
|
||||
dataSource.videoSource!,
|
||||
httpHeaders: dataSource.httpHeaders,
|
||||
start: seekTo,
|
||||
extras: filters,
|
||||
),
|
||||
play: false,
|
||||
);
|
||||
@@ -874,9 +907,9 @@ class PlPlayerController {
|
||||
if (dataSource.audioSource.isNullOrEmpty) {
|
||||
SmartDialog.showToast('音频源为空');
|
||||
} else {
|
||||
await (_videoPlayerController!.platform as NativePlayer).setProperty(
|
||||
await (_videoPlayerController!.platform!).setProperty(
|
||||
'audio-files',
|
||||
UniversalPlatform.isWindows
|
||||
Platform.isWindows
|
||||
? dataSource.audioSource!.replaceAll(';', '\\;')
|
||||
: dataSource.audioSource!.replaceAll(':', '\\:'),
|
||||
);
|
||||
@@ -1658,7 +1691,7 @@ class PlPlayerController {
|
||||
// dataStatus.status.close();
|
||||
|
||||
if (_videoPlayerController != null) {
|
||||
var pp = _videoPlayerController!.platform as NativePlayer;
|
||||
var pp = _videoPlayerController!.platform!;
|
||||
await pp.setProperty('audio-files', '');
|
||||
removeListeners();
|
||||
await _videoPlayerController!.dispose();
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:get/get_rx/get_rx.dart';
|
||||
import 'package:media_kit/ffi/src/allocation.dart';
|
||||
import 'package:media_kit/ffi/src/utf8.dart';
|
||||
import 'package:media_kit/generated/libmpv/bindings.dart' as generated;
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit/src/player/native/core/initializer.dart';
|
||||
import 'package:media_kit/src/player/native/core/native_library.dart';
|
||||
|
||||
@@ -54,7 +55,15 @@ class MpvConvertWebp {
|
||||
'${Pref.hardwareDecoding},auto-copy', // transcode only support copy
|
||||
},
|
||||
);
|
||||
_setHeader();
|
||||
NativePlayer.setHeader(
|
||||
const {
|
||||
'user-agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
|
||||
'referer': HttpString.baseUrl,
|
||||
},
|
||||
_mpv,
|
||||
_ctx,
|
||||
);
|
||||
if (progress != null) {
|
||||
_observeProperty('time-pos');
|
||||
}
|
||||
@@ -79,7 +88,7 @@ class MpvConvertWebp {
|
||||
switch (event.ref.event_id) {
|
||||
case generated.mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
|
||||
final prop = event.ref.data.cast<generated.mpv_event_property>().ref;
|
||||
if (prop.name.cast<Utf8>().toDartString() == 'time-pos' &&
|
||||
if (prop.name.toDartString() == 'time-pos' &&
|
||||
prop.format == generated.mpv_format.MPV_FORMAT_DOUBLE) {
|
||||
progress!.value = (prop.data.cast<Double>().value - start) / duration;
|
||||
}
|
||||
@@ -89,9 +98,9 @@ class MpvConvertWebp {
|
||||
break;
|
||||
case generated.mpv_event_id.MPV_EVENT_LOG_MESSAGE:
|
||||
final log = event.ref.data.cast<generated.mpv_event_log_message>().ref;
|
||||
final prefix = log.prefix.cast<Utf8>().toDartString().trim();
|
||||
final level = log.level.cast<Utf8>().toDartString().trim();
|
||||
final text = log.text.cast<Utf8>().toDartString().trim();
|
||||
final prefix = log.prefix.toDartString().trim();
|
||||
final level = log.level.toDartString().trim();
|
||||
final text = log.text.toDartString().trim();
|
||||
debugPrint('WebpConvert: $level $prefix : $text');
|
||||
if (kDebugMode) {
|
||||
_success = level != 'error' && level != 'fatal';
|
||||
@@ -108,18 +117,8 @@ class MpvConvertWebp {
|
||||
}
|
||||
}
|
||||
|
||||
void _command(List<String> args) {
|
||||
final pointers = args.map((e) => e.toNativeUtf8()).toList();
|
||||
final arr = calloc<Pointer<Utf8>>(128);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
arr[i] = pointers[i];
|
||||
}
|
||||
|
||||
_mpv.mpv_command(_ctx, arr.cast());
|
||||
|
||||
calloc.free(arr);
|
||||
pointers.forEach(calloc.free);
|
||||
}
|
||||
void _command(List<String> args) =>
|
||||
NativePlayer.statiCommand(args, _mpv, _ctx);
|
||||
|
||||
void _observeProperty(String property) {
|
||||
final name = property.toNativeUtf8();
|
||||
@@ -132,47 +131,6 @@ class MpvConvertWebp {
|
||||
|
||||
calloc.free(name);
|
||||
}
|
||||
|
||||
void _setHeader() {
|
||||
final property = 'http-header-fields'.toNativeUtf8();
|
||||
// Allocate & fill the [mpv_node] with the headers.
|
||||
final value = calloc<generated.mpv_node>();
|
||||
final valRef = value.ref
|
||||
..format = generated.mpv_format.MPV_FORMAT_NODE_ARRAY;
|
||||
valRef.u.list = calloc<generated.mpv_node_list>();
|
||||
final valList = valRef.u.list.ref
|
||||
..num = 2
|
||||
..values = calloc<generated.mpv_node>(2);
|
||||
|
||||
const entries = [
|
||||
(
|
||||
'user-agent',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
|
||||
),
|
||||
('referer', HttpString.baseUrl),
|
||||
];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final (k, v) = entries[i];
|
||||
valList.values[i]
|
||||
..format = generated.mpv_format.MPV_FORMAT_STRING
|
||||
..u.string = '$k: $v'.toNativeUtf8().cast();
|
||||
}
|
||||
_mpv.mpv_set_property(
|
||||
_ctx,
|
||||
property.cast(),
|
||||
generated.mpv_format.MPV_FORMAT_NODE,
|
||||
value.cast(),
|
||||
);
|
||||
// Free the allocated memory.
|
||||
calloc.free(property);
|
||||
for (int i = 0; i < valList.num; i++) {
|
||||
calloc.free(valList.values[i].u.string);
|
||||
}
|
||||
calloc
|
||||
..free(valList.values)
|
||||
..free(valRef.u.list)
|
||||
..free(value);
|
||||
}
|
||||
}
|
||||
|
||||
enum WebpPreset {
|
||||
|
||||
Reference in New Issue
Block a user