diff options
Diffstat (limited to 'remuxer/src')
| -rw-r--r-- | remuxer/src/codec_param/av1.rs | 17 | ||||
| -rw-r--r-- | remuxer/src/codec_param/hevc.rs | 46 | ||||
| -rw-r--r-- | remuxer/src/codec_param/mod.rs | 20 | ||||
| -rw-r--r-- | remuxer/src/lib.rs | 4 |
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)] |