scuffle_mp4/boxes/types/
hev1.rs

1use std::io;
2
3use bytes::{Buf, Bytes};
4
5use super::btrt::Btrt;
6use super::hvcc::HvcC;
7use super::stsd::{SampleEntry, VisualSampleEntry};
8use crate::boxes::DynBox;
9use crate::boxes::header::BoxHeader;
10use crate::boxes::traits::BoxType;
11use crate::codec::VideoCodec;
12
13#[derive(Debug, Clone, PartialEq)]
14/// HEVC (H.265) Codec Box
15/// ISO/IEC 14496-15:2022 - 8.4
16pub struct Hev1 {
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
24impl Hev1 {
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
47impl BoxType for Hev1 {
48    const NAME: [u8; 4] = *b"hev1";
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}