mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-27 05:50:12 +08:00
feat: codec list options
This commit is contained in:
@@ -2,12 +2,12 @@ import 'package:PiliPlus/http/loading_state.dart';
|
|||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
import 'package:PiliPlus/models/common/account_type.dart';
|
import 'package:PiliPlus/models/common/account_type.dart';
|
||||||
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
||||||
import 'package:PiliPlus/models/common/video/video_decode_type.dart';
|
|
||||||
import 'package:PiliPlus/models/common/video/video_quality.dart';
|
import 'package:PiliPlus/models/common/video/video_quality.dart';
|
||||||
import 'package:PiliPlus/models/common/video/video_type.dart';
|
import 'package:PiliPlus/models/common/video/video_type.dart';
|
||||||
import 'package:PiliPlus/models/video/play/url.dart';
|
import 'package:PiliPlus/models/video/play/url.dart';
|
||||||
import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart';
|
import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart';
|
||||||
import 'package:PiliPlus/models_new/download/bili_download_media_file_info.dart';
|
import 'package:PiliPlus/models_new/download/bili_download_media_file_info.dart';
|
||||||
|
import 'package:PiliPlus/pages/video/controller.dart';
|
||||||
import 'package:PiliPlus/utils/accounts.dart';
|
import 'package:PiliPlus/utils/accounts.dart';
|
||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||||
@@ -40,9 +40,9 @@ abstract final class DownloadHttp {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (res case Success(:final response)) {
|
if (res case Success(:final response)) {
|
||||||
final Dash? dash = response.dash;
|
final dash = response.dash;
|
||||||
if (dash != null) {
|
if (dash != null) {
|
||||||
final List<VideoItem> videoList = dash.video!;
|
final videoList = dash.video!;
|
||||||
final curHighestVideoQa = videoList.first.quality.code;
|
final curHighestVideoQa = videoList.first.quality.code;
|
||||||
final preferVideoQa = entry.preferedVideoQuality;
|
final preferVideoQa = entry.preferedVideoQuality;
|
||||||
int targetVideoQa = curHighestVideoQa;
|
int targetVideoQa = curHighestVideoQa;
|
||||||
@@ -55,19 +55,18 @@ abstract final class DownloadHttp {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 取出符合当前画质的videoList
|
|
||||||
final List<VideoItem> videosList = videoList
|
|
||||||
.where((e) => e.quality.code == targetVideoQa)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
||||||
final List<FormatItem> supportFormats = response.supportFormats!;
|
final supportFormats = response.supportFormats!;
|
||||||
// 根据画质选编码格式
|
// 根据画质选编码格式
|
||||||
final FormatItem targetSupportFormats = supportFormats.firstWhere(
|
final targetSupportFormats = supportFormats.firstWhere(
|
||||||
(e) => e.quality == targetVideoQa,
|
(e) => e.quality == targetVideoQa,
|
||||||
orElse: () => supportFormats.first,
|
orElse: () => supportFormats.first,
|
||||||
);
|
);
|
||||||
final List<String> supportDecodeFormats = targetSupportFormats.codecs!;
|
|
||||||
|
final currentDecodeFormats = VideoDetailController.selectCodec(
|
||||||
|
targetSupportFormats.codecs!,
|
||||||
|
Pref.preferCodecs,
|
||||||
|
);
|
||||||
|
|
||||||
entry
|
entry
|
||||||
..typeTag = targetVideoQa.toString()
|
..typeTag = targetVideoQa.toString()
|
||||||
@@ -77,31 +76,10 @@ abstract final class DownloadHttp {
|
|||||||
targetSupportFormats.newDesc ??
|
targetSupportFormats.newDesc ??
|
||||||
VideoQuality.fromCode(targetVideoQa).desc;
|
VideoQuality.fromCode(targetVideoQa).desc;
|
||||||
|
|
||||||
String preferDecode = Pref.defaultDecode; // def avc
|
/// 取出符合当前画质的videoList
|
||||||
String preferSecondDecode = Pref.secondDecode; // def av1
|
final videosList = videoList
|
||||||
|
.where((e) => e.quality.code == targetVideoQa)
|
||||||
// 默认从设置中取AV1
|
.toList();
|
||||||
VideoDecodeFormatType currentDecodeFormats =
|
|
||||||
VideoDecodeFormatType.fromString(preferDecode);
|
|
||||||
VideoDecodeFormatType secondDecodeFormats =
|
|
||||||
VideoDecodeFormatType.fromString(preferSecondDecode);
|
|
||||||
// 当前视频没有对应格式返回第一个
|
|
||||||
int flag = 0;
|
|
||||||
for (final e in supportDecodeFormats) {
|
|
||||||
if (currentDecodeFormats.codes.any(e.startsWith)) {
|
|
||||||
flag = 1;
|
|
||||||
break;
|
|
||||||
} else if (secondDecodeFormats.codes.any(e.startsWith)) {
|
|
||||||
flag = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flag == 2) {
|
|
||||||
currentDecodeFormats = secondDecodeFormats;
|
|
||||||
} else if (flag == 0) {
|
|
||||||
currentDecodeFormats = VideoDecodeFormatType.fromString(
|
|
||||||
supportDecodeFormats.first,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 取出符合当前解码格式的videoItem
|
/// 取出符合当前解码格式的videoItem
|
||||||
final videoDash = videosList.firstWhere(
|
final videoDash = videosList.firstWhere(
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ enum VideoDecodeFormatType {
|
|||||||
|
|
||||||
const VideoDecodeFormatType(this.codes);
|
const VideoDecodeFormatType(this.codes);
|
||||||
|
|
||||||
static VideoDecodeFormatType fromCode(String code) =>
|
|
||||||
values.firstWhere((i) => i.codes.contains(code));
|
|
||||||
|
|
||||||
static VideoDecodeFormatType fromString(String val) =>
|
static VideoDecodeFormatType fromString(String val) =>
|
||||||
values.firstWhere((i) => i.codes.any(val.startsWith));
|
values.firstWhere((i) => i.codes.any(val.startsWith));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,16 +127,11 @@ List<SettingsModel> get videoSettings => [
|
|||||||
NormalModel(
|
NormalModel(
|
||||||
title: '首选解码格式',
|
title: '首选解码格式',
|
||||||
leading: const Icon(Icons.movie_creation_outlined),
|
leading: const Icon(Icons.movie_creation_outlined),
|
||||||
getSubtitle: () =>
|
getSubtitle: () {
|
||||||
'首选解码格式:${VideoDecodeFormatType.fromCode(Pref.defaultDecode).description},请根据设备支持情况与需求调整',
|
final list = Pref.preferCodecs;
|
||||||
onTap: _showDecodeDialog,
|
return '首选解码格式:${(list.isEmpty ? '第一个可用' : list.map((i) => i.name).join(","))},请根据设备支持情况与需求调整';
|
||||||
),
|
},
|
||||||
NormalModel(
|
onTap: _showCodecsDialog,
|
||||||
title: '次选解码格式',
|
|
||||||
getSubtitle: () =>
|
|
||||||
'非杜比视频次选:${VideoDecodeFormatType.fromCode(Pref.secondDecode).description},仍无则选择首个提供的解码格式',
|
|
||||||
leading: const Icon(Icons.swap_horizontal_circle_outlined),
|
|
||||||
onTap: _showSecondDecodeDialog,
|
|
||||||
),
|
),
|
||||||
if (kDebugMode || Platform.isAndroid)
|
if (kDebugMode || Platform.isAndroid)
|
||||||
NormalModel(
|
NormalModel(
|
||||||
@@ -349,42 +344,25 @@ Future<void> _showLiveCellularQaDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showDecodeDialog(
|
Future<void> _showCodecsDialog(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
VoidCallback setState,
|
VoidCallback setState,
|
||||||
) async {
|
) async {
|
||||||
final res = await showDialog<String>(
|
final res = await showDialog<List<VideoDecodeFormatType>>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => SelectDialog<String>(
|
builder: (context) => OrderedMultiSelectDialog<VideoDecodeFormatType>(
|
||||||
title: '默认解码格式',
|
title: '首选解码格式',
|
||||||
value: Pref.defaultDecode,
|
initValues: Pref.preferCodecs,
|
||||||
values: VideoDecodeFormatType.values
|
values: {for (final e in VideoDecodeFormatType.values) e: e.name},
|
||||||
.map((e) => (e.codes.first, e.description))
|
|
||||||
.toList(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
await GStorage.setting.put(SettingBoxKey.defaultDecode, res);
|
await (res.isEmpty
|
||||||
setState();
|
? GStorage.setting.delete(SettingBoxKey.preferCodecs)
|
||||||
}
|
: GStorage.setting.put(
|
||||||
}
|
SettingBoxKey.preferCodecs,
|
||||||
|
res.map((i) => i.name).toList(),
|
||||||
Future<void> _showSecondDecodeDialog(
|
));
|
||||||
BuildContext context,
|
|
||||||
VoidCallback setState,
|
|
||||||
) async {
|
|
||||||
final res = await showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => SelectDialog<String>(
|
|
||||||
title: '次选解码格式',
|
|
||||||
value: Pref.secondDecode,
|
|
||||||
values: VideoDecodeFormatType.values
|
|
||||||
.map((e) => (e.codes.first, e.description))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (res != null) {
|
|
||||||
await GStorage.setting.put(SettingBoxKey.secondDecode, res);
|
|
||||||
setState();
|
setState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,8 +143,7 @@ class VideoDetailController extends GetxController
|
|||||||
Box setting = GStorage.setting;
|
Box setting = GStorage.setting;
|
||||||
|
|
||||||
// 预设的解码格式
|
// 预设的解码格式
|
||||||
late String cacheDecode = Pref.defaultDecode; // def avc
|
late List<VideoDecodeFormatType> preferCodecs = Pref.preferCodecs;
|
||||||
late String cacheSecondDecode = Pref.secondDecode; // def av1
|
|
||||||
|
|
||||||
bool get showReply => isFileSource
|
bool get showReply => isFileSource
|
||||||
? false
|
? false
|
||||||
@@ -669,31 +668,38 @@ class VideoDetailController extends GetxController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoItem findVideoByQa(int qa) {
|
VideoItem findVideoByQa(int qa, {bool setCodecs = false}) {
|
||||||
/// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl
|
/// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl
|
||||||
final videoList = data.dash!.video!.where((i) => i.id == qa).toList();
|
final videoList = data.dash!.video!.where((i) => i.id == qa).toList();
|
||||||
|
|
||||||
final currentDecodeFormats = this.currentDecodeFormats.codes;
|
final currentCodes = currentDecodeFormats.codes;
|
||||||
final defaultDecodeFormats = VideoDecodeFormatType.fromString(
|
VideoItem? bestVideo;
|
||||||
cacheDecode,
|
int bestIndex = preferCodecs.length;
|
||||||
).codes;
|
for (final video in videoList) {
|
||||||
final secondDecodeFormats = VideoDecodeFormatType.fromString(
|
final c = video.codecs!;
|
||||||
cacheSecondDecode,
|
if (currentCodes.any(c.startsWith)) {
|
||||||
).codes;
|
return video;
|
||||||
|
}
|
||||||
VideoItem? video;
|
for (int i = 0; i < bestIndex; i++) {
|
||||||
for (final i in videoList) {
|
if (preferCodecs[i].codes.any(c.startsWith)) {
|
||||||
final codec = i.codecs!;
|
bestIndex = i;
|
||||||
if (currentDecodeFormats.any(codec.startsWith)) {
|
bestVideo = video;
|
||||||
video = i;
|
break;
|
||||||
break;
|
}
|
||||||
} else if (defaultDecodeFormats.any(codec.startsWith)) {
|
|
||||||
video = i;
|
|
||||||
} else if (video == null && secondDecodeFormats.any(codec.startsWith)) {
|
|
||||||
video = i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return video ?? videoList.first;
|
|
||||||
|
if (setCodecs) {
|
||||||
|
if (bestIndex < preferCodecs.length) {
|
||||||
|
currentDecodeFormats = preferCodecs[bestIndex];
|
||||||
|
} else {
|
||||||
|
currentDecodeFormats = VideoDecodeFormatType.fromString(
|
||||||
|
videoList.first.codecs!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestVideo ?? videoList.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 更新画质、音质
|
/// 更新画质、音质
|
||||||
@@ -706,11 +712,7 @@ class VideoDetailController extends GetxController
|
|||||||
..isBuffering.value = false
|
..isBuffering.value = false
|
||||||
..buffered.value = Duration.zero;
|
..buffered.value = Duration.zero;
|
||||||
|
|
||||||
final video = findVideoByQa(currentVideoQa.code);
|
firstVideo = findVideoByQa(currentVideoQa.code, setCodecs: true);
|
||||||
if (firstVideo.codecs != video.codecs) {
|
|
||||||
currentDecodeFormats = VideoDecodeFormatType.fromString(video.codecs!);
|
|
||||||
}
|
|
||||||
firstVideo = video;
|
|
||||||
videoUrl = VideoUtils.getCdnUrl(firstVideo.playUrls);
|
videoUrl = VideoUtils.getCdnUrl(firstVideo.playUrls);
|
||||||
|
|
||||||
/// 根据currentAudioQa 重新设置audioUrl
|
/// 根据currentAudioQa 重新设置audioUrl
|
||||||
@@ -814,9 +816,34 @@ class VideoDetailController extends GetxController
|
|||||||
queryVideoUrl(fromReset: true);
|
queryVideoUrl(fromReset: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VideoDecodeFormatType selectCodec(
|
||||||
|
Iterable<String> codecs,
|
||||||
|
List<VideoDecodeFormatType> preferCodecs,
|
||||||
|
) {
|
||||||
|
if (preferCodecs.isNotEmpty) {
|
||||||
|
int bestIndex = preferCodecs.length;
|
||||||
|
for (final e in codecs) {
|
||||||
|
for (int i = 0; i < bestIndex; i++) {
|
||||||
|
if (preferCodecs[i].codes.any(e.startsWith)) {
|
||||||
|
bestIndex = i;
|
||||||
|
if (bestIndex == 0) {
|
||||||
|
return preferCodecs[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestIndex < preferCodecs.length) {
|
||||||
|
return preferCodecs[bestIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VideoDecodeFormatType.fromString(codecs.first);
|
||||||
|
}
|
||||||
|
|
||||||
Volume? volume;
|
Volume? volume;
|
||||||
|
|
||||||
// 视频链接
|
// 视频链接
|
||||||
|
/// TODO: merge [DownloadHttp.getVideoUrl].
|
||||||
Future<void> queryVideoUrl({
|
Future<void> queryVideoUrl({
|
||||||
bool fromReset = false,
|
bool fromReset = false,
|
||||||
bool autoFullScreenFlag = false,
|
bool autoFullScreenFlag = false,
|
||||||
@@ -897,7 +924,7 @@ class VideoDetailController extends GetxController
|
|||||||
quality: videoQuality,
|
quality: videoQuality,
|
||||||
);
|
);
|
||||||
_setVideoHeight();
|
_setVideoHeight();
|
||||||
currentDecodeFormats = VideoDecodeFormatType.fromString('avc1');
|
currentDecodeFormats = VideoDecodeFormatType.AVC;
|
||||||
currentVideoQa.value = videoQuality;
|
currentVideoQa.value = videoQuality;
|
||||||
await _initPlayerIfNeeded(autoFullScreenFlag);
|
await _initPlayerIfNeeded(autoFullScreenFlag);
|
||||||
isQuerying = false;
|
isQuerying = false;
|
||||||
@@ -929,42 +956,25 @@ class VideoDetailController extends GetxController
|
|||||||
}
|
}
|
||||||
currentVideoQa.value = VideoQuality.fromCode(targetVideoQa);
|
currentVideoQa.value = VideoQuality.fromCode(targetVideoQa);
|
||||||
|
|
||||||
|
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
||||||
|
final supportFormats = data.supportFormats!;
|
||||||
|
|
||||||
|
// 根据画质选编码格式
|
||||||
|
currentDecodeFormats = selectCodec(
|
||||||
|
supportFormats
|
||||||
|
.firstWhere(
|
||||||
|
(e) => e.quality == targetVideoQa,
|
||||||
|
orElse: () => supportFormats.first,
|
||||||
|
)
|
||||||
|
.codecs!,
|
||||||
|
preferCodecs,
|
||||||
|
);
|
||||||
|
|
||||||
/// 取出符合当前画质的videoList
|
/// 取出符合当前画质的videoList
|
||||||
final List<VideoItem> videosList = videoList
|
final videosList = videoList
|
||||||
.where((e) => e.quality.code == targetVideoQa)
|
.where((e) => e.quality.code == targetVideoQa)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
|
||||||
final List<FormatItem> supportFormats = data.supportFormats!;
|
|
||||||
// 根据画质选编码格式
|
|
||||||
final List<String> supportDecodeFormats = supportFormats
|
|
||||||
.firstWhere(
|
|
||||||
(e) => e.quality == targetVideoQa,
|
|
||||||
orElse: () => supportFormats.first,
|
|
||||||
)
|
|
||||||
.codecs!;
|
|
||||||
// 默认从设置中取AV1
|
|
||||||
currentDecodeFormats = VideoDecodeFormatType.fromString(cacheDecode);
|
|
||||||
VideoDecodeFormatType secondDecodeFormats =
|
|
||||||
VideoDecodeFormatType.fromString(cacheSecondDecode);
|
|
||||||
// 当前视频没有对应格式返回第一个
|
|
||||||
int flag = 0;
|
|
||||||
for (final e in supportDecodeFormats) {
|
|
||||||
if (currentDecodeFormats.codes.any(e.startsWith)) {
|
|
||||||
flag = 1;
|
|
||||||
break;
|
|
||||||
} else if (secondDecodeFormats.codes.any(e.startsWith)) {
|
|
||||||
flag = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flag == 2) {
|
|
||||||
currentDecodeFormats = secondDecodeFormats;
|
|
||||||
} else if (flag == 0) {
|
|
||||||
currentDecodeFormats = VideoDecodeFormatType.fromString(
|
|
||||||
supportDecodeFormats.first,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 取出符合当前解码格式的videoItem
|
/// 取出符合当前解码格式的videoItem
|
||||||
firstVideo = videosList.firstWhere(
|
firstVideo = videosList.firstWhere(
|
||||||
(e) => currentDecodeFormats.codes.any(e.codecs!.startsWith),
|
(e) => currentDecodeFormats.codes.any(e.codecs!.startsWith),
|
||||||
|
|||||||
@@ -1069,28 +1069,26 @@ class HeaderControlState extends State<HeaderControl>
|
|||||||
|
|
||||||
// 选择解码格式
|
// 选择解码格式
|
||||||
void showSetDecodeFormats() {
|
void showSetDecodeFormats() {
|
||||||
final VideoItem firstVideo = videoDetailCtr.firstVideo;
|
final firstCode = videoDetailCtr.firstVideo.quality.code;
|
||||||
// 当前视频可用的解码格式
|
// 当前视频可用的解码格式
|
||||||
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
|
final videoFormat = videoInfo.supportFormats!;
|
||||||
final List<String>? list = videoFormat
|
|
||||||
.firstWhere((FormatItem e) => e.quality == firstVideo.quality.code)
|
final list = videoFormat.firstWhere((e) => e.quality == firstCode).codecs;
|
||||||
.codecs;
|
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
SmartDialog.showToast('当前视频不支持选择解码格式');
|
SmartDialog.showToast('当前视频不支持选择解码格式');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前选中的解码格式
|
// 当前选中的解码格式
|
||||||
final VideoDecodeFormatType currentDecodeFormats =
|
final curCodecs = videoDetailCtr.currentDecodeFormats.codes;
|
||||||
videoDetailCtr.currentDecodeFormats;
|
|
||||||
showBottomSheet(
|
showBottomSheet(
|
||||||
(context, setState) {
|
(context, setState) {
|
||||||
final theme = Theme.of(context);
|
final colorScheme = ColorScheme.of(context);
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
child: Material(
|
child: Material(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
color: theme.colorScheme.surface,
|
color: colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -1108,30 +1106,22 @@ class HeaderControlState extends State<HeaderControl>
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = list[index];
|
final item = list[index];
|
||||||
final format = VideoDecodeFormatType.fromString(item);
|
final format = VideoDecodeFormatType.fromString(item);
|
||||||
final isCurr = currentDecodeFormats.codes.any(
|
final isCurr = curCodecs.any(item.startsWith);
|
||||||
item.startsWith,
|
|
||||||
);
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (isCurr) {
|
if (isCurr) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
Get.back();
|
Get.back();
|
||||||
videoDetailCtr
|
videoDetailCtr
|
||||||
..currentDecodeFormats = format
|
..currentDecodeFormats = format
|
||||||
..updatePlayer();
|
..updatePlayer();
|
||||||
|
SmartDialog.showToast("解码已变为:${format.name}");
|
||||||
},
|
},
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
contentPadding: const .symmetric(horizontal: 20),
|
||||||
horizontal: 20,
|
|
||||||
),
|
|
||||||
title: Text(format.description),
|
title: Text(format.description),
|
||||||
subtitle: Text(item, style: subTitleStyle),
|
subtitle: Text(item, style: subTitleStyle),
|
||||||
trailing: isCurr
|
trailing: isCurr
|
||||||
? Icon(
|
? Icon(Icons.done, color: colorScheme.primary)
|
||||||
Icons.done,
|
|
||||||
color: theme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ abstract final class SettingBoxKey {
|
|||||||
defaultAudioQaCellular = 'defaultAudioQaCellular',
|
defaultAudioQaCellular = 'defaultAudioQaCellular',
|
||||||
autoPlayEnable = 'autoPlayEnable',
|
autoPlayEnable = 'autoPlayEnable',
|
||||||
fullScreenMode = 'fullScreenMode',
|
fullScreenMode = 'fullScreenMode',
|
||||||
defaultDecode = 'defaultDecode',
|
preferCodecs = 'preferCodecs',
|
||||||
secondDecode = 'secondDecode',
|
|
||||||
defaultToastOp = 'defaultToastOp',
|
defaultToastOp = 'defaultToastOp',
|
||||||
defaultPicQa = 'defaultPicQa',
|
defaultPicQa = 'defaultPicQa',
|
||||||
enableHA = 'enableHA',
|
enableHA = 'enableHA',
|
||||||
|
|||||||
@@ -245,15 +245,33 @@ abstract final class Pref {
|
|||||||
defaultValue: AudioQuality.k192.code,
|
defaultValue: AudioQuality.k192.code,
|
||||||
);
|
);
|
||||||
|
|
||||||
static String get defaultDecode => _setting.get(
|
static List<VideoDecodeFormatType> get preferCodecs {
|
||||||
SettingBoxKey.defaultDecode,
|
// TODO: remove next 2 version
|
||||||
defaultValue: VideoDecodeFormatType.AVC.codes.first,
|
if (_setting.get('defaultDecode') case String codecStr) {
|
||||||
);
|
String? codecStr2 = _setting.get('secondDecode');
|
||||||
|
_setting.deleteAll(const ['defaultDecode', 'secondDecode']);
|
||||||
|
final codecs = [
|
||||||
|
VideoDecodeFormatType.values.firstWhere(
|
||||||
|
(i) => i.codes.contains(codecStr),
|
||||||
|
),
|
||||||
|
if (codecStr2 != null && codecStr2 != codecStr)
|
||||||
|
VideoDecodeFormatType.values.firstWhere(
|
||||||
|
(i) => i.codes.contains(codecStr2),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
_setting.put(
|
||||||
|
SettingBoxKey.preferCodecs,
|
||||||
|
codecs.map((i) => i.name).toList(),
|
||||||
|
);
|
||||||
|
return codecs;
|
||||||
|
}
|
||||||
|
|
||||||
static String get secondDecode => _setting.get(
|
final codecs = _setting.get(SettingBoxKey.preferCodecs);
|
||||||
SettingBoxKey.secondDecode,
|
if (codecs is List && codecs.isNotEmpty) {
|
||||||
defaultValue: VideoDecodeFormatType.AV1.codes.first,
|
return codecs.map((i) => VideoDecodeFormatType.values.byName(i)).toList();
|
||||||
);
|
}
|
||||||
|
return const [];
|
||||||
|
}
|
||||||
|
|
||||||
static String get hardwareDecoding => _setting.get(
|
static String get hardwareDecoding => _setting.get(
|
||||||
SettingBoxKey.hardwareDecoding,
|
SettingBoxKey.hardwareDecoding,
|
||||||
|
|||||||
Reference in New Issue
Block a user