feat: 视频解码格式
This commit is contained in:
@ -89,3 +89,38 @@ extension AudioQualityDesc on AudioQuality {
|
|||||||
];
|
];
|
||||||
get description => _descList[index];
|
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 VideoQuality currentVideoQa;
|
||||||
// 当前音质
|
// 当前音质
|
||||||
late AudioQuality currentAudioQa;
|
late AudioQuality currentAudioQa;
|
||||||
|
// 当前解码格式
|
||||||
|
late VideoDecodeFormats currentDecodeFormats;
|
||||||
|
|
||||||
// 是否预渲染 骨架屏
|
// 是否预渲染 骨架屏
|
||||||
bool preRender = false;
|
bool preRender = false;
|
||||||
@ -114,9 +116,11 @@ class VideoDetailController extends GetxController
|
|||||||
|
|
||||||
/// 暂不匹配解码规则
|
/// 暂不匹配解码规则
|
||||||
|
|
||||||
/// 根据currentVideoQa 重新设置videoUrl
|
/// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl
|
||||||
VideoItem firstVideo =
|
List<VideoItem> videoList =
|
||||||
data.dash!.video!.firstWhere((i) => i.id == currentVideoQa.code);
|
data.dash!.video!.where((i) => i.id == currentVideoQa.code).toList();
|
||||||
|
VideoItem firstVideo = videoList
|
||||||
|
.firstWhere((i) => i.codecs!.startsWith(currentDecodeFormats.code));
|
||||||
// String videoUrl = firstVideo.baseUrl!;
|
// String videoUrl = firstVideo.baseUrl!;
|
||||||
|
|
||||||
/// 根据currentAudioQa 重新设置audioUrl
|
/// 根据currentAudioQa 重新设置audioUrl
|
||||||
@ -176,6 +180,13 @@ class VideoDetailController extends GetxController
|
|||||||
if (firstAudio.id != null) {
|
if (firstAudio.id != null) {
|
||||||
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;
|
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
||||||
|
List<FormatItem> supportFormats = data.supportFormats!;
|
||||||
|
List supportDecodeFormats = supportFormats.first.codecs!;
|
||||||
|
currentDecodeFormats =
|
||||||
|
VideoDecodeFormatsCode.fromString(supportDecodeFormats.first)!;
|
||||||
|
|
||||||
await playerInit(
|
await playerInit(
|
||||||
firstVideo,
|
firstVideo,
|
||||||
audioUrl,
|
audioUrl,
|
||||||
|
|||||||
@ -28,6 +28,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
late PlayUrlModel videoInfo;
|
late PlayUrlModel videoInfo;
|
||||||
List<PlaySpeed> playSpeed = PlaySpeed.values;
|
List<PlaySpeed> playSpeed = PlaySpeed.values;
|
||||||
TextStyle subTitleStyle = const TextStyle(fontSize: 12);
|
TextStyle subTitleStyle = const TextStyle(fontSize: 12);
|
||||||
|
TextStyle titleStyle = const TextStyle(fontSize: 14);
|
||||||
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -81,7 +82,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
leading:
|
leading:
|
||||||
const Icon(Icons.network_cell_outlined, size: 20),
|
const Icon(Icons.network_cell_outlined, size: 20),
|
||||||
title: const Text('省流模式'),
|
title: Text('省流模式', style: titleStyle),
|
||||||
subtitle: Text('低画质 | 减少视频缓存', style: subTitleStyle),
|
subtitle: Text('低画质 | 减少视频缓存', style: subTitleStyle),
|
||||||
trailing: Transform.scale(
|
trailing: Transform.scale(
|
||||||
scale: 0.75,
|
scale: 0.75,
|
||||||
@ -99,22 +100,22 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(
|
// Obx(
|
||||||
() => ListTile(
|
// () => ListTile(
|
||||||
onTap: () => {Get.back(), showSetSpeedSheet()},
|
// onTap: () => {Get.back(), showSetSpeedSheet()},
|
||||||
dense: true,
|
// dense: true,
|
||||||
leading: const Icon(Icons.speed_outlined, size: 20),
|
// leading: const Icon(Icons.speed_outlined, size: 20),
|
||||||
title: const Text('播放速度'),
|
// title: Text('播放速度', style: titleStyle),
|
||||||
subtitle: Text(
|
// subtitle: Text(
|
||||||
'当前倍速 x${widget.controller!.playbackSpeed}',
|
// '当前倍速 x${widget.controller!.playbackSpeed}',
|
||||||
style: subTitleStyle),
|
// style: subTitleStyle),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => {Get.back(), showSetVideoQa()},
|
onTap: () => {Get.back(), showSetVideoQa()},
|
||||||
dense: true,
|
dense: true,
|
||||||
leading: const Icon(Icons.play_circle_outline, size: 20),
|
leading: const Icon(Icons.play_circle_outline, size: 20),
|
||||||
title: const Text('选择画质'),
|
title: Text('选择画质', style: titleStyle),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'当前画质 ${widget.videoDetailCtr!.currentVideoQa.description}',
|
'当前画质 ${widget.videoDetailCtr!.currentVideoQa.description}',
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
@ -123,24 +124,33 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
onTap: () => {Get.back(), showSetAudioQa()},
|
onTap: () => {Get.back(), showSetAudioQa()},
|
||||||
dense: true,
|
dense: true,
|
||||||
leading: const Icon(Icons.album_outlined, size: 20),
|
leading: const Icon(Icons.album_outlined, size: 20),
|
||||||
title: const Text('选择音质'),
|
title: Text('选择音质', style: titleStyle),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'当前音质 ${widget.videoDetailCtr!.currentAudioQa.description}',
|
'当前音质 ${widget.videoDetailCtr!.currentAudioQa.description}',
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () {},
|
onTap: () => {Get.back(), showSetDecodeFormats()},
|
||||||
dense: true,
|
dense: true,
|
||||||
enabled: false,
|
leading: const Icon(Icons.av_timer_outlined, size: 20),
|
||||||
leading: const Icon(Icons.play_circle_outline, size: 20),
|
title: Text('解码格式', style: titleStyle),
|
||||||
title: const Text('播放设置'),
|
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(
|
ListTile(
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
dense: true,
|
dense: true,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
leading: const Icon(Icons.subtitles_outlined, size: 20),
|
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(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text('选择画质'),
|
Text('选择画质', style: titleStyle),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.info_outline,
|
Icons.info_outline,
|
||||||
@ -329,7 +339,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 45, child: Center(child: Text('选择音质'))),
|
SizedBox(
|
||||||
|
height: 45,
|
||||||
|
child: Center(child: Text('选择音质', style: titleStyle))),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
child: ListView(
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _ = widget.controller!;
|
final _ = widget.controller!;
|
||||||
|
|||||||
Reference in New Issue
Block a user