feat: 视频解码格式
This commit is contained in:
@ -89,3 +89,38 @@ extension AudioQualityDesc on AudioQuality {
|
||||
];
|
||||
get description => _descList[index];
|
||||
}
|
||||
|
||||
enum VideoDecodeFormats {
|
||||
AV1,
|
||||
HEVC,
|
||||
AVC,
|
||||
}
|
||||
|
||||
extension VideoDecodeFormatsDesc on VideoDecodeFormats {
|
||||
static final List<String> _descList = [
|
||||
'AV1',
|
||||
'HEVC',
|
||||
'AVC',
|
||||
];
|
||||
get description => _descList[index];
|
||||
}
|
||||
|
||||
extension VideoDecodeFormatsCode on VideoDecodeFormats {
|
||||
static final List<String> _codeList = [
|
||||
'av01',
|
||||
'hev1',
|
||||
'avc1',
|
||||
];
|
||||
get code => _codeList[index];
|
||||
|
||||
static VideoDecodeFormats? fromString(String val) {
|
||||
var result = VideoDecodeFormats.values.first;
|
||||
for (var i in _codeList) {
|
||||
if (val.startsWith(i)) {
|
||||
result = VideoDecodeFormats.values[_codeList.indexOf(i)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ class VideoDetailController extends GetxController
|
||||
late VideoQuality currentVideoQa;
|
||||
// 当前音质
|
||||
late AudioQuality currentAudioQa;
|
||||
// 当前解码格式
|
||||
late VideoDecodeFormats currentDecodeFormats;
|
||||
|
||||
// 是否预渲染 骨架屏
|
||||
bool preRender = false;
|
||||
@ -114,9 +116,11 @@ class VideoDetailController extends GetxController
|
||||
|
||||
/// 暂不匹配解码规则
|
||||
|
||||
/// 根据currentVideoQa 重新设置videoUrl
|
||||
VideoItem firstVideo =
|
||||
data.dash!.video!.firstWhere((i) => i.id == currentVideoQa.code);
|
||||
/// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl
|
||||
List<VideoItem> videoList =
|
||||
data.dash!.video!.where((i) => i.id == currentVideoQa.code).toList();
|
||||
VideoItem firstVideo = videoList
|
||||
.firstWhere((i) => i.codecs!.startsWith(currentDecodeFormats.code));
|
||||
// String videoUrl = firstVideo.baseUrl!;
|
||||
|
||||
/// 根据currentAudioQa 重新设置audioUrl
|
||||
@ -176,6 +180,13 @@ class VideoDetailController extends GetxController
|
||||
if (firstAudio.id != null) {
|
||||
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;
|
||||
}
|
||||
|
||||
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
||||
List<FormatItem> supportFormats = data.supportFormats!;
|
||||
List supportDecodeFormats = supportFormats.first.codecs!;
|
||||
currentDecodeFormats =
|
||||
VideoDecodeFormatsCode.fromString(supportDecodeFormats.first)!;
|
||||
|
||||
await playerInit(
|
||||
firstVideo,
|
||||
audioUrl,
|
||||
|
@ -28,6 +28,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
late PlayUrlModel videoInfo;
|
||||
List<PlaySpeed> playSpeed = PlaySpeed.values;
|
||||
TextStyle subTitleStyle = const TextStyle(fontSize: 12);
|
||||
TextStyle titleStyle = const TextStyle(fontSize: 14);
|
||||
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
||||
|
||||
@override
|
||||
@ -81,7 +82,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
enabled: false,
|
||||
leading:
|
||||
const Icon(Icons.network_cell_outlined, size: 20),
|
||||
title: const Text('省流模式'),
|
||||
title: Text('省流模式', style: titleStyle),
|
||||
subtitle: Text('低画质 | 减少视频缓存', style: subTitleStyle),
|
||||
trailing: Transform.scale(
|
||||
scale: 0.75,
|
||||
@ -99,22 +100,22 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => ListTile(
|
||||
onTap: () => {Get.back(), showSetSpeedSheet()},
|
||||
dense: true,
|
||||
leading: const Icon(Icons.speed_outlined, size: 20),
|
||||
title: const Text('播放速度'),
|
||||
subtitle: Text(
|
||||
'当前倍速 x${widget.controller!.playbackSpeed}',
|
||||
style: subTitleStyle),
|
||||
),
|
||||
),
|
||||
// Obx(
|
||||
// () => ListTile(
|
||||
// onTap: () => {Get.back(), showSetSpeedSheet()},
|
||||
// dense: true,
|
||||
// leading: const Icon(Icons.speed_outlined, size: 20),
|
||||
// title: Text('播放速度', style: titleStyle),
|
||||
// subtitle: Text(
|
||||
// '当前倍速 x${widget.controller!.playbackSpeed}',
|
||||
// style: subTitleStyle),
|
||||
// ),
|
||||
// ),
|
||||
ListTile(
|
||||
onTap: () => {Get.back(), showSetVideoQa()},
|
||||
dense: true,
|
||||
leading: const Icon(Icons.play_circle_outline, size: 20),
|
||||
title: const Text('选择画质'),
|
||||
title: Text('选择画质', style: titleStyle),
|
||||
subtitle: Text(
|
||||
'当前画质 ${widget.videoDetailCtr!.currentVideoQa.description}',
|
||||
style: subTitleStyle),
|
||||
@ -123,24 +124,33 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
onTap: () => {Get.back(), showSetAudioQa()},
|
||||
dense: true,
|
||||
leading: const Icon(Icons.album_outlined, size: 20),
|
||||
title: const Text('选择音质'),
|
||||
title: Text('选择音质', style: titleStyle),
|
||||
subtitle: Text(
|
||||
'当前音质 ${widget.videoDetailCtr!.currentAudioQa.description}',
|
||||
style: subTitleStyle),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {},
|
||||
onTap: () => {Get.back(), showSetDecodeFormats()},
|
||||
dense: true,
|
||||
enabled: false,
|
||||
leading: const Icon(Icons.play_circle_outline, size: 20),
|
||||
title: const Text('播放设置'),
|
||||
leading: const Icon(Icons.av_timer_outlined, size: 20),
|
||||
title: Text('解码格式', style: titleStyle),
|
||||
subtitle: Text(
|
||||
'当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}',
|
||||
style: subTitleStyle),
|
||||
),
|
||||
// ListTile(
|
||||
// onTap: () {},
|
||||
// dense: true,
|
||||
// enabled: false,
|
||||
// leading: const Icon(Icons.play_circle_outline, size: 20),
|
||||
// title: Text('播放设置', style: titleStyle),
|
||||
// ),
|
||||
ListTile(
|
||||
onTap: () {},
|
||||
dense: true,
|
||||
enabled: false,
|
||||
leading: const Icon(Icons.subtitles_outlined, size: 20),
|
||||
title: const Text('弹幕设置'),
|
||||
title: Text('弹幕设置', style: titleStyle),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -250,7 +260,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text('选择画质'),
|
||||
Text('选择画质', style: titleStyle),
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
@ -329,7 +339,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
margin: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 45, child: Center(child: Text('选择音质'))),
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: Center(child: Text('选择音质', style: titleStyle))),
|
||||
Expanded(
|
||||
child: Material(
|
||||
child: ListView(
|
||||
@ -370,6 +382,74 @@ class _HeaderControlState extends State<HeaderControl> {
|
||||
);
|
||||
}
|
||||
|
||||
// 选择解码格式
|
||||
void showSetDecodeFormats() {
|
||||
// 当前选中的解码格式
|
||||
VideoDecodeFormats currentDecodeFormats =
|
||||
widget.videoDetailCtr!.currentDecodeFormats;
|
||||
// 当前视频可用的解码格式
|
||||
List<FormatItem> videoFormat = videoInfo.supportFormats!;
|
||||
List list = videoFormat.first.codecs!;
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: 250,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
margin: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 45,
|
||||
child: Center(child: Text('选择解码格式', style: titleStyle))),
|
||||
Expanded(
|
||||
child: Material(
|
||||
child: ListView(
|
||||
children: [
|
||||
for (var i in list) ...[
|
||||
ListTile(
|
||||
onTap: () {
|
||||
widget.videoDetailCtr!.currentDecodeFormats =
|
||||
VideoDecodeFormatsCode.fromString(i)!;
|
||||
widget.videoDetailCtr!.updatePlayer();
|
||||
Get.back();
|
||||
},
|
||||
dense: true,
|
||||
contentPadding:
|
||||
const EdgeInsets.only(left: 20, right: 20),
|
||||
title: Text(VideoDecodeFormatsCode.fromString(i)!
|
||||
.description!),
|
||||
subtitle: Text(
|
||||
i!,
|
||||
style: subTitleStyle,
|
||||
),
|
||||
trailing: i.startsWith(currentDecodeFormats.code)
|
||||
? Icon(
|
||||
Icons.done,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _ = widget.controller!;
|
||||
|
Reference in New Issue
Block a user