|
| 1 | +use std::io; |
| 2 | + |
| 3 | +use bytes::{Buf, Bytes}; |
| 4 | + |
| 5 | +use super::btrt::Btrt; |
| 6 | +use super::hvcc::HvcC; |
| 7 | +use super::stsd::{SampleEntry, VisualSampleEntry}; |
| 8 | +use crate::boxes::DynBox; |
| 9 | +use crate::boxes::header::BoxHeader; |
| 10 | +use crate::boxes::traits::BoxType; |
| 11 | +use crate::codec::VideoCodec; |
| 12 | + |
| 13 | +#[derive(Debug, Clone, PartialEq)] |
| 14 | +/// HEVC (H.265) Codec Box |
| 15 | +/// ISO/IEC 14496-15:2022 - 8.4 |
| 16 | +pub struct Hvc1 { |
| 17 | + pub header: BoxHeader, |
| 18 | + pub visual_sample_entry: SampleEntry<VisualSampleEntry>, |
| 19 | + pub hvcc: HvcC, |
| 20 | + pub btrt: Option<Btrt>, |
| 21 | + pub unknown: Vec<DynBox>, |
| 22 | +} |
| 23 | + |
| 24 | +impl Hvc1 { |
| 25 | + pub fn new(visual_sample_entry: SampleEntry<VisualSampleEntry>, hvcc: HvcC, btrt: Option<Btrt>) -> Self { |
| 26 | + Self { |
| 27 | + header: BoxHeader::new(Self::NAME), |
| 28 | + visual_sample_entry, |
| 29 | + hvcc, |
| 30 | + btrt, |
| 31 | + unknown: Vec::new(), |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + pub fn codec(&self) -> io::Result<VideoCodec> { |
| 36 | + Ok(VideoCodec::Hevc { |
| 37 | + constraint_indicator: self.hvcc.hevc_config.general_constraint_indicator_flags, |
| 38 | + level: self.hvcc.hevc_config.general_level_idc, |
| 39 | + profile: self.hvcc.hevc_config.general_profile_idc, |
| 40 | + profile_compatibility: self.hvcc.hevc_config.general_profile_compatibility_flags, |
| 41 | + tier: self.hvcc.hevc_config.general_tier_flag, |
| 42 | + general_profile_space: self.hvcc.hevc_config.general_profile_space, |
| 43 | + }) |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +impl BoxType for Hvc1 { |
| 48 | + const NAME: [u8; 4] = *b"hvc1"; |
| 49 | + |
| 50 | + fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> { |
| 51 | + let mut reader = io::Cursor::new(data); |
| 52 | + |
| 53 | + let mut visual_sample_entry = SampleEntry::<VisualSampleEntry>::demux(&mut reader)?; |
| 54 | + |
| 55 | + let mut hvcc = None; |
| 56 | + let mut btrt = None; |
| 57 | + let mut unknown = Vec::new(); |
| 58 | + |
| 59 | + while reader.has_remaining() { |
| 60 | + let dyn_box = DynBox::demux(&mut reader)?; |
| 61 | + match dyn_box { |
| 62 | + DynBox::HvcC(b) => { |
| 63 | + hvcc = Some(*b); |
| 64 | + } |
| 65 | + DynBox::Btrt(b) => { |
| 66 | + btrt = Some(*b); |
| 67 | + } |
| 68 | + DynBox::Clap(b) => { |
| 69 | + visual_sample_entry.extension.clap = Some(*b); |
| 70 | + } |
| 71 | + DynBox::Pasp(b) => { |
| 72 | + visual_sample_entry.extension.pasp = Some(*b); |
| 73 | + } |
| 74 | + DynBox::Colr(b) => { |
| 75 | + visual_sample_entry.extension.colr = Some(*b); |
| 76 | + } |
| 77 | + _ => { |
| 78 | + unknown.push(dyn_box); |
| 79 | + } |
| 80 | + } |
| 81 | + } |
| 82 | + |
| 83 | + let hvcc = hvcc.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "trak box is missing tkhd box"))?; |
| 84 | + |
| 85 | + Ok(Self { |
| 86 | + header, |
| 87 | + visual_sample_entry, |
| 88 | + hvcc, |
| 89 | + btrt, |
| 90 | + unknown, |
| 91 | + }) |
| 92 | + } |
| 93 | + |
| 94 | + fn primitive_size(&self) -> u64 { |
| 95 | + self.visual_sample_entry.size() |
| 96 | + + self.hvcc.size() |
| 97 | + + self.btrt.as_ref().map(|b| b.size()).unwrap_or(0) |
| 98 | + + self.unknown.iter().map(|b| b.size()).sum::<u64>() |
| 99 | + } |
| 100 | + |
| 101 | + fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> { |
| 102 | + self.visual_sample_entry.mux(writer)?; |
| 103 | + self.hvcc.mux(writer)?; |
| 104 | + if let Some(btrt) = &self.btrt { |
| 105 | + btrt.mux(writer)?; |
| 106 | + } |
| 107 | + for unknown in &self.unknown { |
| 108 | + unknown.mux(writer)?; |
| 109 | + } |
| 110 | + Ok(()) |
| 111 | + } |
| 112 | +} |
0 commit comments