scuffle_transmuxer/codecs/
av1.rs1use bytes::Bytes;
2use isobmff::UnknownBox;
3use isobmff::boxes::{
4 ColourInformation, ColourInformationBox, NclxColourInformation, PixelAspectRatioBox, SampleEntry, SampleFlags,
5 TrackRunBoxSample, VisualSampleEntry,
6};
7use scuffle_av1::boxes::{AV1CodecConfigurationBox, AV1SampleEntry};
8use scuffle_av1::seq::SequenceHeaderObu;
9use scuffle_av1::{AV1CodecConfigurationRecord, ObuHeader, ObuType};
10use scuffle_bytes_util::zero_copy::ZeroCopyReader;
11use scuffle_flv::video::header::VideoFrameType;
12
13use crate::TransmuxError;
14
15pub(crate) fn stsd_entry(config: AV1CodecConfigurationRecord) -> Result<(AV1SampleEntry, SequenceHeaderObu), TransmuxError> {
16 let mut config_obu_reader = scuffle_bytes_util::zero_copy::Slice::from(config.config_obu.as_bytes());
17 let header = ObuHeader::parse(&mut config_obu_reader.as_std())?;
18 let data = if let Some(size) = header.size {
19 config_obu_reader.try_read(size as usize)?
20 } else {
21 config_obu_reader.try_read_to_end()?
22 };
23
24 if header.obu_type != ObuType::SequenceHeader {
25 return Err(TransmuxError::InvalidAv1DecoderConfigurationRecord);
26 }
27
28 let seq_obu = SequenceHeaderObu::parse(header, &mut std::io::Cursor::new(data))?;
29
30 let colr = ColourInformationBox {
36 colour_info: ColourInformation::Nclx(NclxColourInformation {
37 colour_primaries: seq_obu.color_config.color_primaries as u16,
38 matrix_coefficients: seq_obu.color_config.matrix_coefficients as u16,
39 transfer_characteristics: seq_obu.color_config.transfer_characteristics as u16,
40 full_range_flag: seq_obu.color_config.full_color_range,
41 }),
42 };
43
44 let visual_sample_entry = VisualSampleEntry::new(
45 SampleEntry::default(),
46 seq_obu.max_frame_width as u16,
47 seq_obu.max_frame_height as u16,
48 [0; 32],
49 );
50
51 let av01 = AV1SampleEntry {
52 sample_entry: visual_sample_entry,
53 av1c: AV1CodecConfigurationBox::new(config),
54 sub_boxes: vec![
55 UnknownBox::try_from_box(PixelAspectRatioBox::default())?,
56 UnknownBox::try_from_box(colr)?,
57 ],
58 };
59
60 Ok((av01, seq_obu))
61}
62
63pub(crate) fn trun_sample(
64 frame_type: VideoFrameType,
65 duration: u32,
66 data: &Bytes,
67) -> Result<TrackRunBoxSample, TransmuxError> {
68 Ok(TrackRunBoxSample {
69 sample_composition_time_offset: None,
70 sample_duration: Some(duration),
71 sample_flags: Some(SampleFlags {
72 reserved: 0,
73 is_leading: 0,
74 sample_degradation_priority: 0,
75 sample_depends_on: if frame_type == VideoFrameType::KeyFrame { 2 } else { 1 },
76 sample_has_redundancy: 0,
77 sample_is_depended_on: 0,
78 sample_is_non_sync_sample: frame_type != VideoFrameType::KeyFrame,
79 sample_padding_value: 0,
80 }),
81 sample_size: Some(data.len() as u32),
82 })
83}