|
1 | 1 | use crate::*; |
2 | 2 |
|
| 3 | +// https://www.webmproject.org/vp9/mp4/ |
3 | 4 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
4 | 5 | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
5 | 6 | pub struct Vp09 { |
6 | 7 | pub visual: Visual, |
7 | | - pub vpcc: Vpcc, |
| 8 | + pub vpcc: VpcC, |
8 | 9 | } |
9 | 10 |
|
10 | | -impl AtomExt for Vp09 { |
11 | | - type Ext = (); |
| 11 | +impl Atom for Vp09 { |
| 12 | + const KIND: FourCC = FourCC::new(b"vp09"); |
12 | 13 |
|
13 | | - const KIND_EXT: FourCC = FourCC::new(b"vp09"); |
14 | | - |
15 | | - fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> { |
| 14 | + fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> { |
16 | 15 | let visual = Visual::decode(buf)?; |
17 | | - let vpcc = Vpcc::decode(buf)?; |
18 | 16 |
|
19 | | - Ok(Self { visual, vpcc }) |
| 17 | + let mut vpcc = None; |
| 18 | + while let Some(atom) = Any::decode_maybe(buf)? { |
| 19 | + match atom { |
| 20 | + Any::VpcC(atom) => vpcc = atom.into(), |
| 21 | + _ => tracing::warn!("unknown atom: {:?}", atom), |
| 22 | + } |
| 23 | + } |
| 24 | + |
| 25 | + Ok(Self { |
| 26 | + visual, |
| 27 | + vpcc: vpcc.ok_or(Error::MissingBox(VpcC::KIND))?, |
| 28 | + }) |
20 | 29 | } |
21 | 30 |
|
22 | | - fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> { |
| 31 | + fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> { |
23 | 32 | self.visual.encode(buf)?; |
24 | 33 | self.vpcc.encode(buf)?; |
25 | 34 |
|
26 | 35 | Ok(()) |
27 | 36 | } |
28 | 37 | } |
29 | 38 |
|
| 39 | +ext! { |
| 40 | + name: Vpcc, |
| 41 | + versions: [1], |
| 42 | + flags: {} |
| 43 | +} |
| 44 | + |
| 45 | +#[derive(Debug, Clone, PartialEq, Eq, Default)] |
| 46 | +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
| 47 | +pub struct VpcC { |
| 48 | + pub profile: u8, |
| 49 | + pub level: u8, |
| 50 | + pub bit_depth: u8, |
| 51 | + pub chroma_subsampling: u8, |
| 52 | + pub video_full_range_flag: bool, |
| 53 | + pub color_primaries: u8, |
| 54 | + pub transfer_characteristics: u8, |
| 55 | + pub matrix_coefficients: u8, |
| 56 | + pub codec_initialization_data: Vec<u8>, |
| 57 | +} |
| 58 | + |
| 59 | +impl AtomExt for VpcC { |
| 60 | + const KIND_EXT: FourCC = FourCC::new(b"vpcC"); |
| 61 | + |
| 62 | + type Ext = VpccExt; |
| 63 | + |
| 64 | + fn decode_body_ext<B: Buf>(buf: &mut B, _ext: VpccExt) -> Result<Self> { |
| 65 | + let profile = u8::decode(buf)?; |
| 66 | + let level = u8::decode(buf)?; |
| 67 | + let (bit_depth, chroma_subsampling, video_full_range_flag) = { |
| 68 | + let b = u8::decode(buf)?; |
| 69 | + (b >> 4, (b >> 1) & 0x01, b & 0x01 == 1) |
| 70 | + }; |
| 71 | + let color_primaries = u8::decode(buf)?; |
| 72 | + let transfer_characteristics = u8::decode(buf)?; |
| 73 | + let matrix_coefficients = u8::decode(buf)?; |
| 74 | + let _codec_initialization_data_size = u16::decode(buf)?; |
| 75 | + let codec_initialization_data = Vec::decode(buf)?; // assert same as data_size |
| 76 | + |
| 77 | + Ok(Self { |
| 78 | + profile, |
| 79 | + level, |
| 80 | + bit_depth, |
| 81 | + chroma_subsampling, |
| 82 | + video_full_range_flag, |
| 83 | + color_primaries, |
| 84 | + transfer_characteristics, |
| 85 | + matrix_coefficients, |
| 86 | + codec_initialization_data, |
| 87 | + }) |
| 88 | + } |
| 89 | + |
| 90 | + fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<VpccExt> { |
| 91 | + self.profile.encode(buf)?; |
| 92 | + self.level.encode(buf)?; |
| 93 | + ((self.bit_depth << 4) |
| 94 | + | (self.chroma_subsampling << 1) |
| 95 | + | (self.video_full_range_flag as u8)) |
| 96 | + .encode(buf)?; |
| 97 | + self.color_primaries.encode(buf)?; |
| 98 | + self.transfer_characteristics.encode(buf)?; |
| 99 | + self.matrix_coefficients.encode(buf)?; |
| 100 | + (self.codec_initialization_data.len() as u16).encode(buf)?; |
| 101 | + self.codec_initialization_data.encode(buf)?; |
| 102 | + |
| 103 | + Ok(VpccVersion::V1.into()) |
| 104 | + } |
| 105 | +} |
| 106 | + |
30 | 107 | #[cfg(test)] |
31 | 108 | mod tests { |
32 | 109 | use super::*; |
33 | 110 |
|
34 | 111 | #[test] |
35 | 112 | fn test_vpcc() { |
| 113 | + let expected = VpcC { |
| 114 | + profile: 0, |
| 115 | + level: 0x1F, |
| 116 | + bit_depth: 8, |
| 117 | + chroma_subsampling: 0, |
| 118 | + video_full_range_flag: false, |
| 119 | + color_primaries: 0, |
| 120 | + transfer_characteristics: 0, |
| 121 | + matrix_coefficients: 0, |
| 122 | + codec_initialization_data: vec![], |
| 123 | + }; |
| 124 | + let mut buf = Vec::new(); |
| 125 | + expected.encode(&mut buf).unwrap(); |
| 126 | + |
| 127 | + let mut buf = buf.as_ref(); |
| 128 | + let decoded = VpcC::decode(&mut buf).unwrap(); |
| 129 | + assert_eq!(decoded, expected); |
| 130 | + } |
| 131 | + |
| 132 | + #[test] |
| 133 | + fn test_vp09() { |
36 | 134 | let expected = Vp09 { |
37 | 135 | visual: Visual { |
38 | 136 | width: 1920, |
39 | 137 | height: 1080, |
40 | 138 | ..Default::default() |
41 | 139 | }, |
42 | | - vpcc: Vpcc::default(), |
| 140 | + vpcc: VpcC::default(), |
43 | 141 | }; |
44 | 142 | let mut buf = Vec::new(); |
45 | 143 | expected.encode(&mut buf).unwrap(); |
|
0 commit comments