mirror of
https://github.com/amtoaer/bili-sync.git
synced 2026-09-04 23:18:02 +08:00
fix: 改进视频流编码判断逻辑 (#332)
* fix: 改进视频流编码判断逻辑 * test: 添加新的单元测试,确保 HDR、杜比视界获取正常
This commit is contained in:
@@ -64,6 +64,20 @@ pub enum VideoCodecs {
|
|||||||
AV1,
|
AV1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u64> for VideoCodecs {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
|
||||||
|
// https://socialsisteryi.github.io/bilibili-API-collect/docs/video/videostream_url.html#%E8%A7%86%E9%A2%91%E7%BC%96%E7%A0%81%E4%BB%A3%E7%A0%81
|
||||||
|
match value {
|
||||||
|
7 => Ok(Self::AVC),
|
||||||
|
12 => Ok(Self::HEV),
|
||||||
|
13 => Ok(Self::AV1),
|
||||||
|
_ => bail!("invalid video codecs id: {}", value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 视频流的筛选偏好
|
// 视频流的筛选偏好
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct FilterOption {
|
pub struct FilterOption {
|
||||||
@@ -207,20 +221,15 @@ impl PageAnalyzer {
|
|||||||
.ok_or(BiliError::RiskControlOccurred)?
|
.ok_or(BiliError::RiskControlOccurred)?
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
{
|
{
|
||||||
let (Some(url), Some(quality), Some(codecs)) = (
|
let (Some(url), Some(quality), Some(codecs_id)) = (
|
||||||
video["baseUrl"].as_str(),
|
video["baseUrl"].as_str(),
|
||||||
video["id"].as_u64(),
|
video["id"].as_u64(),
|
||||||
video["codecs"].as_str(),
|
video["codecid"].as_u64(),
|
||||||
) else {
|
) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let quality = VideoQuality::from_repr(quality as usize).context("invalid video stream quality")?;
|
let quality = VideoQuality::from_repr(quality as usize).context("invalid video stream quality")?;
|
||||||
// 从视频流的 codecs 字段中获取编码格式,此处并非精确匹配而是判断包含,比如 codecs 是 av1.42c01e,需要匹配为 av1
|
let Ok(codecs) = codecs_id.try_into() else {
|
||||||
let Some(codecs) = [VideoCodecs::HEV, VideoCodecs::AVC, VideoCodecs::AV1]
|
|
||||||
.into_iter()
|
|
||||||
.find(|c| codecs.contains(c.as_ref()))
|
|
||||||
else {
|
|
||||||
// 少数情况会走到此处,如 codecs 为 dvh1.08.09、hvc1.2.4.L123.90 等,直接跳过,不影响流程
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if !filter_option.codecs.contains(&codecs)
|
if !filter_option.codecs.contains(&codecs)
|
||||||
@@ -383,18 +392,41 @@ mod tests {
|
|||||||
(
|
(
|
||||||
"BV1xRChYUE2R",
|
"BV1xRChYUE2R",
|
||||||
VideoQuality::Quality8k,
|
VideoQuality::Quality8k,
|
||||||
|
VideoCodecs::HEV,
|
||||||
Some(AudioQuality::QualityHiRES),
|
Some(AudioQuality::QualityHiRES),
|
||||||
),
|
),
|
||||||
// 一个没有声音的纯视频
|
// 一个没有声音的纯视频
|
||||||
("BV1J7411H7KQ", VideoQuality::Quality720p, None),
|
("BV1J7411H7KQ", VideoQuality::Quality720p, VideoCodecs::HEV, None),
|
||||||
// 一个杜比全景声的演示片
|
// 一个杜比全景声的演示片
|
||||||
(
|
(
|
||||||
"BV1Mm4y1P7JV",
|
"BV1Mm4y1P7JV",
|
||||||
VideoQuality::Quality4k,
|
VideoQuality::QualityDolby,
|
||||||
|
VideoCodecs::HEV,
|
||||||
Some(AudioQuality::QualityDolby),
|
Some(AudioQuality::QualityDolby),
|
||||||
),
|
),
|
||||||
|
// 影视飓风的杜比视界视频
|
||||||
|
(
|
||||||
|
"BV1HEf2YWEvs",
|
||||||
|
VideoQuality::QualityDolby,
|
||||||
|
VideoCodecs::HEV,
|
||||||
|
Some(AudioQuality::QualityDolby),
|
||||||
|
),
|
||||||
|
// 孤独摇滚的杜比视界 + hires + 杜比全景声视频
|
||||||
|
(
|
||||||
|
"BV1YDVYzeE39",
|
||||||
|
VideoQuality::QualityDolby,
|
||||||
|
VideoCodecs::HEV,
|
||||||
|
Some(AudioQuality::QualityHiRES),
|
||||||
|
),
|
||||||
|
// 一个京紫的 HDR 视频
|
||||||
|
(
|
||||||
|
"BV1cZ4y1b7iB",
|
||||||
|
VideoQuality::QualityHdr,
|
||||||
|
VideoCodecs::HEV,
|
||||||
|
Some(AudioQuality::Quality192k),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
for (bvid, video_quality, audio_quality) in testcases.into_iter() {
|
for (bvid, video_quality, video_codec, audio_quality) in testcases.into_iter() {
|
||||||
let client = BiliClient::new();
|
let client = BiliClient::new();
|
||||||
let video = Video::new(&client, bvid.to_owned());
|
let video = Video::new(&client, bvid.to_owned());
|
||||||
let pages = video.get_pages().await.expect("failed to get pages");
|
let pages = video.get_pages().await.expect("failed to get pages");
|
||||||
@@ -408,10 +440,11 @@ mod tests {
|
|||||||
dbg!(bvid, &best_stream);
|
dbg!(bvid, &best_stream);
|
||||||
match best_stream {
|
match best_stream {
|
||||||
BestStream::VideoAudio {
|
BestStream::VideoAudio {
|
||||||
video: Stream::DashVideo { quality, .. },
|
video: Stream::DashVideo { quality, codecs, .. },
|
||||||
audio,
|
audio,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(quality, video_quality);
|
assert_eq!(quality, video_quality);
|
||||||
|
assert_eq!(codecs, video_codec);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
audio.map(|audio_stream| match audio_stream {
|
audio.map(|audio_stream| match audio_stream {
|
||||||
Stream::DashAudio { quality, .. } => quality,
|
Stream::DashAudio { quality, .. } => quality,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub use analyzer::VideoCodecs;
|
||||||
pub use analyzer::{BestStream, FilterOption};
|
pub use analyzer::{BestStream, FilterOption};
|
||||||
use anyhow::{Result, bail, ensure};
|
use anyhow::{Result, bail, ensure};
|
||||||
use arc_swap::ArcSwapOption;
|
use arc_swap::ArcSwapOption;
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ fn load_config() -> Config {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn load_config() -> Config {
|
fn load_config() -> Config {
|
||||||
|
use crate::bilibili::{FilterOption, VideoCodecs};
|
||||||
|
|
||||||
let credential = match (
|
let credential = match (
|
||||||
std::env::var("TEST_SESSDATA"),
|
std::env::var("TEST_SESSDATA"),
|
||||||
std::env::var("TEST_BILI_JCT"),
|
std::env::var("TEST_BILI_JCT"),
|
||||||
@@ -82,6 +84,10 @@ fn load_config() -> Config {
|
|||||||
Config {
|
Config {
|
||||||
credential: arc_swap::ArcSwapOption::from(credential),
|
credential: arc_swap::ArcSwapOption::from(credential),
|
||||||
cdn_sorting: true,
|
cdn_sorting: true,
|
||||||
|
filter_option: FilterOption {
|
||||||
|
codecs: vec![VideoCodecs::HEV, VideoCodecs::AV1, VideoCodecs::AVC],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user