aboutsummaryrefslogtreecommitdiff
path: root/remuxer/src
diff options
context:
space:
mode:
Diffstat (limited to 'remuxer/src')
-rw-r--r--remuxer/src/codec_param/av1.rs17
-rw-r--r--remuxer/src/codec_param/hevc.rs46
-rw-r--r--remuxer/src/codec_param/mod.rs20
-rw-r--r--remuxer/src/lib.rs4
4 files changed, 69 insertions, 18 deletions
diff --git a/remuxer/src/codec_param/av1.rs b/remuxer/src/codec_param/av1.rs
index 5641e77..1ecbb8f 100644
--- a/remuxer/src/codec_param/av1.rs
+++ b/remuxer/src/codec_param/av1.rs
@@ -4,7 +4,9 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
-pub fn av1_codec_param(cp: &[u8]) -> String {
+use crate::codec_param::CodecParam;
+
+pub fn av1_codec_param(cp: &[u8]) -> CodecParam {
let profile = (cp[1] >> 5) & 0b111;
let level = cp[1] & 0b11111;
let tier = (cp[2] >> 7) & 0b1;
@@ -23,16 +25,19 @@ pub fn av1_codec_param(cp: &[u8]) -> String {
} else {
0
};
- format!(
- "av01.{profile}.{level:02}{tier_char}.{bit_depth:02}" // .{monochrome}.{css_x}{css_y}{css_pos}
- )
+ CodecParam {
+ string: format!(
+ "av01.{profile}.{level:02}{tier_char}.{bit_depth:02}" // .{monochrome}.{css_x}{css_y}{css_pos}
+ ),
+ bit_depth: Some(bit_depth),
+ }
}
#[test]
fn sample1() {
- assert_eq!(av1_codec_param(&[0x81, 0x04, 0x4E]), "av01.0.04M.10");
+ assert_eq!(av1_codec_param(&[0x81, 0x04, 0x4E]).string, "av01.0.04M.10");
}
#[test]
fn sample2() {
- assert_eq!(av1_codec_param(&[0x81, 0x35, 0xF4]), "av01.1.21H.12");
+ assert_eq!(av1_codec_param(&[0x81, 0x35, 0xF4]).string, "av01.1.21H.12");
}
diff --git a/remuxer/src/codec_param/hevc.rs b/remuxer/src/codec_param/hevc.rs
index 3459258..8bff081 100644
--- a/remuxer/src/codec_param/hevc.rs
+++ b/remuxer/src/codec_param/hevc.rs
@@ -4,21 +4,33 @@
Copyright (C) 2026 metamuffin <metamuffin.org>
*/
+use crate::codec_param::CodecParam;
use std::fmt::Write;
-pub(super) fn hevc_codec_param(cp: &[u8]) -> String {
+pub(super) fn hevc_codec_param(cp: &[u8]) -> CodecParam {
let general_profile_space = cp[1] >> 6;
let general_tier_flag = (cp[1] >> 5) & 0b1;
let general_profile_idc = cp[1] & 0b11111;
let general_level_idc = cp[12];
let general_profile_compatibility_flag =
u32::from_be_bytes([cp[2], cp[3], cp[4], cp[5]]).reverse_bits();
+ let general_constraint_indicator_flags = &cp[6..12];
+ let _min_spatial_segmentation_idc = u16::from_be_bytes([cp[13], cp[14]]) & 0b111111111111;
+ let _parallelism_type = cp[15] & 0b11;
+ let _chroma_format_idc = cp[16] & 0b11;
+ let bit_depth_luma = (cp[17] & 0b111) + 8;
+ let _bit_depth_chroma = (cp[18] & 0b111) + 8;
+
let mut d = String::new();
- let trailing_zeroes = cp[6..12].iter().rev().take_while(|x| **x == 0).count();
+ let trailing_zeroes = general_constraint_indicator_flags
+ .iter()
+ .rev()
+ .take_while(|x| **x == 0)
+ .count();
for &flag in &cp[6..12 - trailing_zeroes] {
write!(d, ".{flag:02x}").unwrap();
}
- format!(
+ let string = format!(
"hvc1.{}{}.{:x}.{}{}{d}",
match general_profile_space {
0 => "",
@@ -35,21 +47,39 @@ pub(super) fn hevc_codec_param(cp: &[u8]) -> String {
_ => unreachable!(),
},
general_level_idc,
- )
+ );
+ CodecParam {
+ string,
+ bit_depth: Some(bit_depth_luma),
+ }
}
#[test]
fn sample1() {
let cp = [
- 0x01, 0x02, 0x20, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+ 0x01, 0x02, 0x20, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00,
+ 0xFC, 0xFD, 0xFA, 0xFA, 0x00, 0x00, 0x0F,
];
- assert_eq!(hevc_codec_param(&cp), "hvc1.2.4.L63.90")
+ assert_eq!(
+ hevc_codec_param(&cp),
+ CodecParam {
+ string: "hvc1.2.4.L63.90".to_string(),
+ bit_depth: Some(10)
+ }
+ )
}
#[test]
fn sample2() {
let cp = [
- 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78,
+ 0x01, 0x01, 0x60, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0xF0, 0x00,
+ 0xFC, 0xFD, 0xF8, 0xF8, 0x00, 0x00, 0x0B,
];
- assert_eq!(hevc_codec_param(&cp), "hvc1.1.6.L120.b0")
+ assert_eq!(
+ hevc_codec_param(&cp),
+ CodecParam {
+ string: "hvc1.1.6.L120.b0".to_string(),
+ bit_depth: Some(8)
+ }
+ );
}
diff --git a/remuxer/src/codec_param/mod.rs b/remuxer/src/codec_param/mod.rs
index 4fdb181..4613c88 100644
--- a/remuxer/src/codec_param/mod.rs
+++ b/remuxer/src/codec_param/mod.rs
@@ -11,6 +11,12 @@ mod av1;
mod hevc;
mod vp9;
+#[derive(Debug, PartialEq, Eq)]
+struct CodecParam {
+ bit_depth: Option<u8>,
+ string: String,
+}
+
pub fn codec_param(te: &TrackEntry) -> String {
let empty_cp = vec![];
let cp = te.codec_private.as_ref().unwrap_or(&empty_cp);
@@ -20,9 +26,9 @@ pub fn codec_param(te: &TrackEntry) -> String {
"A_OPUS" => "opus".to_string(),
"A_VORBIS" => "vorbis".to_string(),
- "V_AV1" => av1_codec_param(cp),
+ "V_AV1" => av1_codec_param(cp).string,
"V_MPEG4/ISO/AVC" => format!("avc1.{:02x}{:02x}{:02x}", cp[1], cp[2], cp[3]),
- "V_MPEGH/ISO/HEVC" => hevc_codec_param(cp),
+ "V_MPEGH/ISO/HEVC" => hevc_codec_param(cp).string,
"V_VP9" => vp9_codec_param(te),
"D_WEBVTT/SUBTITLES" => "webvtt".to_string(),
@@ -31,3 +37,13 @@ pub fn codec_param(te: &TrackEntry) -> String {
x => todo!("{x:?}"),
}
}
+
+pub fn codec_param_bit_depth(te: &TrackEntry) -> Option<u8> {
+ let empty_cp = vec![];
+ let cp = te.codec_private.as_ref().unwrap_or(&empty_cp);
+ match te.codec_id.as_str() {
+ "V_AV1" => av1_codec_param(cp).bit_depth,
+ "V_MPEGH/ISO/HEVC" => hevc_codec_param(cp).bit_depth,
+ _ => None,
+ }
+}
diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs
index 8a78fec..d68f695 100644
--- a/remuxer/src/lib.rs
+++ b/remuxer/src/lib.rs
@@ -7,11 +7,11 @@
mod codec_param;
pub mod demuxers;
+pub mod kf_detect;
pub mod magic;
pub mod muxers;
-pub mod kf_detect;
-pub use codec_param::codec_param;
+pub use codec_param::{codec_param, codec_param_bit_depth};
pub use winter_matroska as matroska;
#[derive(Debug, Clone, Copy, PartialEq)]