Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature media kit #7

Merged
merged 2 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions lib/models/video/play/quality.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
enum VideoQuality {
speed240,
flunt360,
clear480,
high720,
high72060,
high1080,
high1080plus,
high108060,
super4K,
hdr,
dolbyVision,
super8k
}

extension VideoQualityCode on VideoQuality {
static final List<int> _codeList = [
6,
16,
32,
64,
74,
80,
112,
116,
120,
125,
126,
127,
];
int get code => _codeList[index];

static VideoQuality? fromCode(int code) {
final index = _codeList.indexOf(code);
if (index != -1) {
return VideoQuality.values[index];
}
return null;
}
}

extension VideoQualityDesc on VideoQuality {
static final List<String> _descList = [
'240P 极速',
'360P 流畅',
'480P 清晰',
'720P 高清',
'720P60 高帧率',
'1080P 高清',
'1080P+ 高码率',
'1080P60 高帧率',
'4K 超清',
'HDR 真彩色',
'杜比视界',
'8K 超高清'
];
get description => _descList[index];
}

///
enum AudioQuality { k64, k132, k192, dolby, hiRes }

extension AudioQualityCode on AudioQuality {
static final List<int> _codeList = [
30216,
30232,
30280,
30250,
30251,
];
int get code => _codeList[index];

static AudioQuality? fromCode(int code) {
final index = _codeList.indexOf(code);
if (index != -1) {
return AudioQuality.values[index];
}
return null;
}
}

extension AudioQualityDesc on AudioQuality {
static final List<String> _descList = [
'64K',
'132K',
'192K',
'杜比全景声',
'Hi-Res无损',
];
get description => _descList[index];
}
41 changes: 39 additions & 2 deletions lib/models/video/play/url.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:pilipala/models/video/play/quality.dart';

class PlayUrlModel {
PlayUrlModel({
this.from,
Expand Down Expand Up @@ -32,7 +34,7 @@ class PlayUrlModel {
String? seekParam;
String? seekType;
Dash? dash;
List? supportFormats;
List<FormatItem>? supportFormats;
// String? highFormat;
int? lastPlayTime;
int? lastPlayCid;
Expand All @@ -51,7 +53,11 @@ class PlayUrlModel {
seekParam = json['seek_param'];
seekType = json['seek_type'];
dash = Dash.fromJson(json['dash']);
supportFormats = json['support_formats'];
supportFormats = json['support_formats'] != null
? json['support_formats']
.map<FormatItem>((e) => FormatItem.fromJson(e))
.toList()
: [];
lastPlayTime = json['last_play_time'];
lastPlayCid = json['last_play_cid'];
}
Expand Down Expand Up @@ -101,6 +107,7 @@ class VideoItem {
this.startWithSap,
this.segmentBase,
this.codecid,
this.quality,
});

int? id;
Expand All @@ -116,6 +123,7 @@ class VideoItem {
int? startWithSap;
Map? segmentBase;
int? codecid;
VideoQuality? quality;

VideoItem.fromJson(Map<String, dynamic> json) {
id = json['id'];
Expand All @@ -131,6 +139,7 @@ class VideoItem {
startWithSap = json['startWithSap'];
segmentBase = json['segmentBase'];
codecid = json['codecid'];
quality = VideoQuality.values.firstWhere((i) => i.code == json['id']);
}
}

Expand All @@ -149,6 +158,7 @@ class AudioItem {
this.startWithSap,
this.segmentBase,
this.codecid,
this.quality,
});

int? id;
Expand All @@ -164,6 +174,7 @@ class AudioItem {
int? startWithSap;
Map? segmentBase;
int? codecid;
String? quality;

AudioItem.fromJson(Map<String, dynamic> json) {
id = json['id'];
Expand All @@ -179,5 +190,31 @@ class AudioItem {
startWithSap = json['startWithSap'];
segmentBase = json['segmentBase'];
codecid = json['codecid'];
quality =
AudioQuality.values.firstWhere((i) => i.code == json['id']).description;
}
}

class FormatItem {
FormatItem({
this.quality,
this.format,
this.newDesc,
this.displayDesc,
this.codecs,
});

int? quality;
String? format;
String? newDesc;
String? displayDesc;
List? codecs;

FormatItem.fromJson(Map<String, dynamic> json) {
quality = json['quality'];
format = json['format'];
newDesc = json['new_description'];
displayDesc = json['display_desc'];
codecs = json['codecs'];
}
}
69 changes: 60 additions & 9 deletions lib/pages/video/detail/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:hive/hive.dart';
import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/play/quality.dart';
import 'package:pilipala/models/video/play/url.dart';
import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
Expand All @@ -21,6 +22,11 @@ class VideoDetailController extends GetxController
// 视频aid
String bvid = Get.parameters['bvid']!;
int cid = int.parse(Get.parameters['cid']!);
late PlayUrlModel data;
// 当前画质
late VideoQuality currentVideoQa;
// 当前音质
late AudioQuality currentAudioQa;

// 是否预渲染 骨架屏
bool preRender = false;
Expand All @@ -44,6 +50,10 @@ class VideoDetailController extends GetxController
Box user = GStrorage.user;
Box localCache = GStrorage.localCache;
PlPlayerController plPlayerController = PlPlayerController();
// 是否开始自动播放 存在多p的情况下,第二p需要为true
RxBool autoPlay = true.obs;
// 视频资源是否有效
RxBool isEffective = true.obs;

@override
void onInit() {
Expand Down Expand Up @@ -86,6 +96,29 @@ class VideoDetailController extends GetxController
});
}

/// 更新画质、音质
/// TODO 继续进度播放
updatePlayer() {
Duration position = plPlayerController.position.value;
plPlayerController.removeListeners();
plPlayerController.isBuffering.value = false;
plPlayerController.buffered.value = Duration.zero;

/// 暂不匹配解码规则

/// 根据currentVideoQa 重新设置videoUrl
VideoItem firstVideo =
data.dash!.video!.firstWhere((i) => i.id == currentVideoQa.code);
String videoUrl = firstVideo.baseUrl!;

/// 根据currentAudioQa 重新设置audioUrl
AudioItem firstAudio =
data.dash!.audio!.firstWhere((i) => i.id == currentAudioQa.code);
String audioUrl = firstAudio.baseUrl ?? '';

playerInit(videoUrl, audioUrl, defaultST: position);
}

playerInit(source, audioSource,
{Duration defaultST = Duration.zero, int duration = 0}) async {
plPlayerController.setDataSource(
Expand All @@ -101,24 +134,42 @@ class VideoDetailController extends GetxController
),
// 硬解
enableHA: true,
autoplay: true,
autoplay: autoPlay.value,
seekTo: defaultST,
duration: Duration(milliseconds: duration),
);
}

// 手动点击播放
handlePlay() {
plPlayerController.togglePlay();
}

// 视频链接
queryVideoUrl() async {
var result = await VideoHttp.videoUrl(cid: cid, bvid: bvid);
if (result['status']) {
PlayUrlModel data = result['data'];
// 指定质量的视频 -> 最高质量的视频
String videoUrl = data.dash!.video!.first.baseUrl!;
String audioUrl =
data.dash!.audio!.isNotEmpty ? data.dash!.audio!.first.baseUrl! : '';
playerInit(videoUrl, audioUrl,
defaultST: Duration(milliseconds: data.lastPlayTime!),
duration: data.timeLength ?? 0);
data = result['data'];

/// 优先顺序 省流模式 -> 设置中指定质量 -> 当前可选的最高质量
VideoItem firstVideo = data.dash!.video!.first;
String videoUrl = firstVideo.baseUrl!;
//
currentVideoQa = VideoQualityCode.fromCode(firstVideo.id!)!;

/// 优先顺序 设置中指定质量 -> 当前可选的最高质量
AudioItem firstAudio =
data.dash!.audio!.isNotEmpty ? data.dash!.audio!.first : AudioItem();
String audioUrl = firstAudio.baseUrl ?? '';
//
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;

playerInit(
videoUrl,
audioUrl,
defaultST: Duration(milliseconds: data.lastPlayTime!),
duration: data.timeLength ?? 0,
);
}
}

Expand Down
Loading