scuffle_transmuxer/codecs/
aac.rs

1use bytes::Bytes;
2use fixed::FixedU32;
3use isobmff::boxes::{AudioSampleEntry, SampleEntry, SampleFlags, TrackRunBoxSample};
4use scuffle_aac::PartialAudioSpecificConfig;
5use scuffle_bytes_util::zero_copy::U24Be;
6use scuffle_flv::audio::header::legacy::{SoundSize, SoundType};
7use scuffle_mp4::boxes::{ESDBox, MP4AudioSampleEntry};
8use scuffle_mp4::object_description::{
9    DecoderConfigDescriptor, DescriptorTag, ESDescriptor, ObjectTypeIndication, StreamType, UnknownDescriptor,
10};
11
12use crate::TransmuxError;
13
14pub(crate) fn stsd_entry<'a>(
15    sound_size: SoundSize,
16    sound_type: SoundType,
17    data: Bytes,
18) -> Result<(MP4AudioSampleEntry<'a>, PartialAudioSpecificConfig), TransmuxError> {
19    let aac_config = scuffle_aac::PartialAudioSpecificConfig::parse(&data)?;
20
21    let channelcount = match sound_type {
22        SoundType::Mono => 1,
23        SoundType::Stereo => 2,
24        _ => return Err(TransmuxError::InvalidAudioChannels),
25    };
26
27    let samplesize = match sound_size {
28        SoundSize::Bit8 => 8,
29        SoundSize::Bit16 => 16,
30        _ => return Err(TransmuxError::InvalidAudioSampleSize),
31    };
32
33    let es = ESDescriptor {
34        es_id: 2,
35        stream_priority: 0,
36        depends_on_es_id: Some(0),
37        url_string: None,
38        ocr_es_id: Some(0),
39        dec_config_descr: DecoderConfigDescriptor {
40            object_type_indication: ObjectTypeIndication::Audio14496_3, // AAC
41            stream_type: StreamType::AudioStream,
42            up_stream: false,
43            reserved: true,
44            buffer_size_db: U24Be(0),
45            max_bitrate: 0,
46            avg_bitrate: 0,
47            dec_specific_info: Some(UnknownDescriptor::new(DescriptorTag::DecSpecificInfoTag, data.into())),
48            profile_level_indication_index_descr: vec![],
49            unknown_descriptors: vec![],
50        },
51        sl_config_descr: None,
52        unknown_descriptors: vec![],
53    };
54    let mp4a = MP4AudioSampleEntry {
55        sample_entry: AudioSampleEntry::new(
56            SampleEntry::default(),
57            channelcount,
58            samplesize,
59            FixedU32::from_num(aac_config.sampling_frequency),
60        ),
61        es: ESDBox::new(es),
62    };
63
64    Ok((mp4a, aac_config))
65}
66
67pub(crate) fn trun_sample(data: &Bytes) -> Result<(TrackRunBoxSample, u32), TransmuxError> {
68    Ok((
69        TrackRunBoxSample {
70            sample_duration: Some(1024),
71            sample_composition_time_offset: None,
72            sample_flags: Some(SampleFlags {
73                reserved: 0,
74                is_leading: 0,
75                sample_degradation_priority: 0,
76                sample_depends_on: 2,
77                sample_has_redundancy: 0,
78                sample_is_depended_on: 0,
79                sample_is_non_sync_sample: false,
80                sample_padding_value: 0,
81            }),
82            sample_size: Some(data.len() as u32),
83        },
84        1024,
85    ))
86}