Skip to content

Commit 6ab66ad

Browse files
committed
MP4: Cleanup properties
1 parent f1fe219 commit 6ab66ad

File tree

1 file changed

+102
-86
lines changed

1 file changed

+102
-86
lines changed

lofty/src/mp4/properties.rs

Lines changed: 102 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,13 @@ impl Mp4Properties {
211211
}
212212
}
213213

214-
struct TrakChildren {
214+
struct AudioTrak {
215215
mdhd: AtomInfo,
216216
minf: Option<AtomInfo>,
217217
}
218218

219-
fn get_trak_children<R>(reader: &mut AtomReader<R>, traks: &[AtomInfo]) -> Result<TrakChildren>
219+
/// Search through all the traks to find the first one with audio
220+
fn find_audio_trak<R>(reader: &mut AtomReader<R>, traks: &[AtomInfo]) -> Result<AudioTrak>
220221
where
221222
R: Read + Seek,
222223
{
@@ -230,6 +231,9 @@ where
230231
break;
231232
}
232233

234+
mdhd = None;
235+
minf = None;
236+
233237
reader.seek(SeekFrom::Start(mdia.start + 8))?;
234238

235239
let mut read = 8;
@@ -284,44 +288,46 @@ where
284288
err!(BadAtom("Expected atom \"trak.mdia.mdhd\""));
285289
};
286290

287-
Ok(TrakChildren { mdhd, minf })
291+
Ok(AudioTrak { mdhd, minf })
288292
}
289293

290294
struct Mdhd {
291295
timescale: u32,
292296
duration: u64,
293297
}
294298

295-
fn read_mdhd<R>(reader: &mut AtomReader<R>) -> Result<Mdhd>
296-
where
297-
R: Read + Seek,
298-
{
299-
let version = reader.read_u8()?;
300-
let _flags = reader.read_uint(3)?;
299+
impl Mdhd {
300+
fn parse<R>(reader: &mut AtomReader<R>) -> Result<Self>
301+
where
302+
R: Read + Seek,
303+
{
304+
let version = reader.read_u8()?;
305+
let _flags = reader.read_uint(3)?;
301306

302-
let (timescale, duration) = if version == 1 {
303-
// We don't care about these two values
304-
let _creation_time = reader.read_u64()?;
305-
let _modification_time = reader.read_u64()?;
307+
let (timescale, duration) = if version == 1 {
308+
// We don't care about these two values
309+
let _creation_time = reader.read_u64()?;
310+
let _modification_time = reader.read_u64()?;
306311

307-
let timescale = reader.read_u32()?;
308-
let duration = reader.read_u64()?;
312+
let timescale = reader.read_u32()?;
313+
let duration = reader.read_u64()?;
309314

310-
(timescale, duration)
311-
} else {
312-
let _creation_time = reader.read_u32()?;
313-
let _modification_time = reader.read_u32()?;
315+
(timescale, duration)
316+
} else {
317+
let _creation_time = reader.read_u32()?;
318+
let _modification_time = reader.read_u32()?;
314319

315-
let timescale = reader.read_u32()?;
316-
let duration = reader.read_u32()?;
320+
let timescale = reader.read_u32()?;
321+
let duration = reader.read_u32()?;
317322

318-
(timescale, u64::from(duration))
319-
};
323+
(timescale, u64::from(duration))
324+
};
320325

321-
Ok(Mdhd {
322-
timescale,
323-
duration,
324-
})
326+
Ok(Mdhd {
327+
timescale,
328+
duration,
329+
})
330+
}
325331
}
326332

327333
// TODO: Estimate duration from stts?
@@ -334,76 +340,85 @@ struct SttsEntry {
334340
sample_duration: u32,
335341
}
336342

337-
fn read_stts<R>(reader: &mut R) -> Result<Vec<SttsEntry>>
338-
where
339-
R: Read,
340-
{
341-
let _version_and_flags = reader.read_uint::<BigEndian>(4)?;
343+
#[derive(Debug)]
344+
struct Stts {
345+
entries: Vec<SttsEntry>,
346+
}
342347

343-
let entry_count = reader.read_u32::<BigEndian>()?;
344-
let mut entries = Vec::try_with_capacity_stable(entry_count as usize)?;
348+
impl Stts {
349+
fn parse<R>(reader: &mut R) -> Result<Self>
350+
where
351+
R: Read,
352+
{
353+
let _version_and_flags = reader.read_uint::<BigEndian>(4)?;
345354

346-
for _ in 0..entry_count {
347-
let sample_count = reader.read_u32::<BigEndian>()?;
348-
let sample_duration = reader.read_u32::<BigEndian>()?;
355+
let entry_count = reader.read_u32::<BigEndian>()?;
356+
let mut entries = Vec::try_with_capacity_stable(entry_count as usize)?;
349357

350-
entries.push(SttsEntry {
351-
_sample_count: sample_count,
352-
sample_duration,
353-
});
354-
}
358+
for _ in 0..entry_count {
359+
let sample_count = reader.read_u32::<BigEndian>()?;
360+
let sample_duration = reader.read_u32::<BigEndian>()?;
355361

356-
Ok(entries)
362+
entries.push(SttsEntry {
363+
_sample_count: sample_count,
364+
sample_duration,
365+
});
366+
}
367+
368+
Ok(Self { entries })
369+
}
357370
}
358371

359372
struct Minf {
360373
stsd_data: Vec<u8>,
361-
stts: Option<Vec<SttsEntry>>,
374+
stts: Option<Stts>,
362375
}
363376

364-
fn read_minf<R>(
365-
reader: &mut AtomReader<R>,
366-
len: u64,
367-
parse_mode: ParsingMode,
368-
) -> Result<Option<Minf>>
369-
where
370-
R: Read + Seek,
371-
{
372-
let Some(stbl) = find_child_atom(reader, len, *b"stbl", parse_mode)? else {
373-
return Ok(None);
374-
};
377+
impl Minf {
378+
fn parse<R>(
379+
reader: &mut AtomReader<R>,
380+
len: u64,
381+
parse_mode: ParsingMode,
382+
) -> Result<Option<Self>>
383+
where
384+
R: Read + Seek,
385+
{
386+
let Some(stbl) = find_child_atom(reader, len, *b"stbl", parse_mode)? else {
387+
return Ok(None);
388+
};
375389

376-
let mut stsd_data = None;
377-
let mut stts = None;
378-
379-
let mut read = 8;
380-
while read < stbl.len {
381-
let Some(atom) = reader.next()? else { break };
382-
383-
read += atom.len;
384-
385-
if let AtomIdent::Fourcc(fourcc) = atom.ident {
386-
match &fourcc {
387-
b"stsd" => {
388-
let mut stsd = try_vec![0; (atom.len - 8) as usize];
389-
reader.read_exact(&mut stsd)?;
390-
stsd_data = Some(stsd);
391-
},
392-
b"stts" => stts = Some(read_stts(reader)?),
393-
_ => {
394-
skip_atom(reader, atom.extended, atom.len)?;
395-
},
396-
}
390+
let mut stsd_data = None;
391+
let mut stts = None;
392+
393+
let mut read = 8;
394+
while read < stbl.len {
395+
let Some(atom) = reader.next()? else { break };
396+
397+
read += atom.len;
398+
399+
if let AtomIdent::Fourcc(fourcc) = atom.ident {
400+
match &fourcc {
401+
b"stsd" => {
402+
let mut stsd = try_vec![0; (atom.len - 8) as usize];
403+
reader.read_exact(&mut stsd)?;
404+
stsd_data = Some(stsd);
405+
},
406+
b"stts" => stts = Some(Stts::parse(reader)?),
407+
_ => {
408+
skip_atom(reader, atom.extended, atom.len)?;
409+
},
410+
}
397411

398-
continue;
412+
continue;
413+
}
399414
}
400-
}
401415

402-
let Some(stsd_data) = stsd_data else {
403-
return Ok(None);
404-
};
416+
let Some(stsd_data) = stsd_data else {
417+
return Ok(None);
418+
};
405419

406-
Ok(Some(Minf { stsd_data, stts }))
420+
Ok(Some(Minf { stsd_data, stts }))
421+
}
407422
}
408423

409424
fn read_stsd<R>(reader: &mut AtomReader<R>, properties: &mut Mp4Properties) -> Result<()>
@@ -467,13 +482,13 @@ where
467482
R: Read + Seek,
468483
{
469484
// We need the mdhd and minf atoms from the audio track
470-
let TrakChildren { mdhd, minf } = get_trak_children(reader, traks)?;
485+
let AudioTrak { mdhd, minf } = find_audio_trak(reader, traks)?;
471486

472487
reader.seek(SeekFrom::Start(mdhd.start + 8))?;
473488
let Mdhd {
474489
timescale,
475490
duration,
476-
} = read_mdhd(reader)?;
491+
} = Mdhd::parse(reader)?;
477492

478493
// We create the properties here, since it is possible the other information isn't available
479494
let mut properties = Mp4Properties::default();
@@ -489,7 +504,7 @@ where
489504
};
490505

491506
reader.seek(SeekFrom::Start(minf_info.start + 8))?;
492-
let Some(Minf { stsd_data, stts }) = read_minf(reader, minf_info.len, parse_mode)? else {
507+
let Some(Minf { stsd_data, stts }) = Minf::parse(reader, minf_info.len, parse_mode)? else {
493508
return Ok(properties);
494509
};
495510

@@ -505,7 +520,8 @@ where
505520
let mdat_len = mdat_length(reader)?;
506521

507522
if let Some(stts) = stts {
508-
let stts_specifies_duration = !(stts.len() == 1 && stts[0].sample_duration == 1);
523+
let stts_specifies_duration =
524+
!(stts.entries.len() == 1 && stts.entries[0].sample_duration == 1);
509525
if stts_specifies_duration {
510526
// We do a basic audio bitrate calculation below for each stream type.
511527
// Up here, we can do a more accurate calculation if the duration is available.

0 commit comments

Comments
 (0)