Skip to content

Commit 17debc7

Browse files
authored
Merge pull request mozilla#124 from alfredoyang/support_qt_audio_v2
support audio sample entry v2
2 parents cfeeab0 + 2e1b81c commit 17debc7

File tree

5 files changed

+77
-10
lines changed

5 files changed

+77
-10
lines changed

mp4parse/src/boxes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,6 @@ box_database!(
137137
OriginalFormatBox 0x66726d61, // "frma"
138138
MP3AudioSampleEntry 0x2e6d7033, // ".mp3" - from F4V.
139139
CompositionOffsetBox 0x63747473, // "ctts"
140+
AudioChannelLayoutAtom 0x6368616E, // "chan" - quicktime atom
141+
LPCMAudioSampleEntry 0x6C70636D, // "lpcm" - quicktime atom
140142
);

mp4parse/src/lib.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,15 @@ pub enum AudioCodecSpecific {
319319
FLACSpecificBox(FLACSpecificBox),
320320
OpusSpecificBox(OpusSpecificBox),
321321
MP3,
322+
LPCM,
322323
}
323324

324325
#[derive(Debug, Clone)]
325326
pub struct AudioSampleEntry {
326327
data_reference_index: u16,
327-
pub channelcount: u16,
328+
pub channelcount: u32,
328329
pub samplesize: u16,
329-
pub samplerate: u32,
330+
pub samplerate: f64,
330331
pub codec_specific: AudioCodecSpecific,
331332
pub protection_info: Vec<ProtectionSchemeInfoBox>,
332333
}
@@ -464,6 +465,7 @@ pub enum CodecType {
464465
VP8,
465466
EncryptedVideo,
466467
EncryptedAudio,
468+
LPCM, // QT
467469
}
468470

469471
impl Default for CodecType {
@@ -1836,13 +1838,13 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
18361838
// Skip uninteresting fields.
18371839
skip(src, 6)?;
18381840

1839-
let channelcount = be_u16(src)?;
1841+
let mut channelcount = be_u16(src)? as u32;
18401842
let samplesize = be_u16(src)?;
18411843

18421844
// Skip uninteresting fields.
18431845
skip(src, 4)?;
18441846

1845-
let samplerate = be_u32(src)?;
1847+
let mut samplerate = (be_u32(src)? >> 16) as f64; // 16.16 fixed point;
18461848

18471849
match version {
18481850
0 => (),
@@ -1851,10 +1853,16 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
18511853
// Skip uninteresting fields.
18521854
skip(src, 16)?;
18531855
},
1856+
2 => {
1857+
// Quicktime sound sample description version 2.
1858+
skip(src, 4)?;
1859+
samplerate = f64::from_bits(be_u64(src)?);
1860+
channelcount = be_u32(src)?;
1861+
skip(src, 20)?;
1862+
}
18541863
_ => return Err(Error::Unsupported("unsupported non-isom audio sample entry")),
18551864
}
18561865

1857-
// Skip chan/etc. for now.
18581866
let mut codec_type = CodecType::Unknown;
18591867
let mut codec_specific = None;
18601868
if name == BoxType::MP3AudioSampleEntry {
@@ -1908,6 +1916,15 @@ fn read_audio_sample_entry<T: Read>(src: &mut BMFFBox<T>) -> Result<(CodecType,
19081916
codec_type = CodecType::EncryptedAudio;
19091917
vec_push(&mut protection_info, sinf)?;
19101918
}
1919+
BoxType::AudioChannelLayoutAtom => {
1920+
if name != BoxType::LPCMAudioSampleEntry {
1921+
return Err(Error::InvalidData("malformed audio sample entry"));
1922+
}
1923+
// skip 'chan' for now.
1924+
skip_box_content(&mut b)?;
1925+
codec_type = CodecType::LPCM;
1926+
codec_specific = Some(AudioCodecSpecific::LPCM);
1927+
}
19111928
_ => {
19121929
log!("Unsupported audio codec, box {:?} found", b.head.name);
19131930
skip_box_content(&mut b)?;

mp4parse/src/tests.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,3 +1128,48 @@ fn read_invalid_pssh() {
11281128
_ => panic!("unexpected result with invalid descriptor"),
11291129
}
11301130
}
1131+
1132+
#[test]
1133+
fn read_stsd_lpcm() {
1134+
// Extract from sample converted by ffmpeg.
1135+
// "ffmpeg -i ./gizmo-short.mp4 -acodec pcm_s16le -ar 96000 -vcodec copy -f mov gizmo-short.mov"
1136+
let lpcm =
1137+
vec![
1138+
0x00, 0x00, 0x00, 0x00, 0x00,
1139+
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
1140+
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0xff,
1141+
0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1142+
0x00, 0x00, 0x48, 0x40, 0xf7, 0x70, 0x00, 0x00,
1143+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
1144+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
1145+
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00,
1146+
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x63,
1147+
0x68, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
1148+
0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
1149+
0x00, 0x00, 0x00,
1150+
];
1151+
1152+
let mut stream = make_box(BoxSize::Auto, b"lpcm", |s| {
1153+
s.append_bytes(lpcm.as_slice())
1154+
});
1155+
let mut iter = super::BoxIter::new(&mut stream);
1156+
let mut stream = iter.next_box().unwrap().unwrap();
1157+
1158+
let (codec_type, sample_entry) = super::read_audio_sample_entry(&mut stream).unwrap();
1159+
1160+
assert_eq!(codec_type, super::CodecType::LPCM);
1161+
1162+
match sample_entry {
1163+
super::SampleEntry::Audio(a) => {
1164+
assert_eq!(a.samplerate, 96000.0);
1165+
assert_eq!(a.channelcount, 1);
1166+
match a.codec_specific {
1167+
super::AudioCodecSpecific::LPCM => (),
1168+
_ => panic!("it should be LPCM!"),
1169+
}
1170+
},
1171+
_ => panic!("it should be a audio sample entry!"),
1172+
}
1173+
1174+
}
1175+

mp4parse/tests/public.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,12 @@ fn public_api() {
9999
mp4::AudioCodecSpecific::MP3 => {
100100
"MP3"
101101
}
102+
mp4::AudioCodecSpecific::LPCM => {
103+
"LPCM"
104+
}
102105
}, "ES");
103106
assert!(a.samplesize > 0);
104-
assert!(a.samplerate > 0);
107+
assert!(a.samplerate > 0.0);
105108
}
106109
Some(mp4::SampleEntry::Unknown) | None => {}
107110
}

mp4parse_capi/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ pub unsafe extern fn mp4parse_get_track_info(parser: *mut mp4parse_parser, track
432432
mp4parse_codec::AAC,
433433
AudioCodecSpecific::ES_Descriptor(ref esds) if esds.audio_codec == CodecType::MP3 =>
434434
mp4parse_codec::MP3,
435-
AudioCodecSpecific::ES_Descriptor(_) =>
435+
AudioCodecSpecific::ES_Descriptor(_) | AudioCodecSpecific::LPCM =>
436436
mp4parse_codec::UNKNOWN,
437437
AudioCodecSpecific::MP3 =>
438438
mp4parse_codec::MP3,
@@ -521,9 +521,9 @@ pub unsafe extern fn mp4parse_get_track_audio_info(parser: *mut mp4parse_parser,
521521
_ => return mp4parse_status::INVALID,
522522
};
523523

524-
(*info).channels = audio.channelcount;
524+
(*info).channels = audio.channelcount as u16;
525525
(*info).bit_depth = audio.samplesize;
526-
(*info).sample_rate = audio.samplerate >> 16; // 16.16 fixed point
526+
(*info).sample_rate = audio.samplerate as u32;
527527

528528
match audio.codec_specific {
529529
AudioCodecSpecific::ES_Descriptor(ref v) => {
@@ -572,7 +572,7 @@ pub unsafe extern fn mp4parse_get_track_audio_info(parser: *mut mp4parse_parser,
572572
}
573573
}
574574
}
575-
AudioCodecSpecific::MP3 => (),
575+
AudioCodecSpecific::MP3 | AudioCodecSpecific::LPCM => (),
576576
}
577577

578578
if let Some(p) = audio.protection_info.iter().find(|sinf| sinf.tenc.is_some()) {

0 commit comments

Comments
 (0)