Skip to main content

zvidlib_container/
container.rs

1//! Container detection and capability discovery across MP4 and WebM.
2
3use crate::api::{Capability, Support};
4use crate::audio::AudioTrackTiming;
5use crate::codec::TrackKind;
6use crate::io::ByteSource;
7use crate::media::Container;
8use crate::mp4_demux::{Mp4Demuxer, Mp4DemuxerOptions, Mp4Track, probe_mp4};
9use crate::webm_demux::{WebmDemuxer, WebmDemuxerOptions, probe_webm};
10use crate::{Error, ErrorKind, Limits, Result};
11
12/// Identifies a source's container from its leading bytes, never from a file
13/// name: an EBML header with a `webm` or `matroska` `DocType` is
14/// [`Container::WebM`], and an `ftyp` or `moov` box is [`Container::Mp4`].
15/// `None` when neither matches.
16pub async fn probe_container<S: ByteSource + ?Sized>(source: &S) -> Result<Option<Container>> {
17    if probe_webm(source).await? {
18        return Ok(Some(Container::WebM));
19    }
20    if probe_mp4(source).await? {
21        return Ok(Some(Container::Mp4));
22    }
23    Ok(None)
24}
25
26/// Every container zvidlib reads and writes, each named as
27/// [`Container::name`] spells it. Both are portable Rust and need no platform
28/// support, so each reports [`Support::Available`] on every target; whether a
29/// track inside can be decoded is a separate codec capability.
30pub fn container_capabilities() -> Vec<Capability> {
31    Container::ALL
32        .iter()
33        .map(|container| Capability {
34            name: container.name().to_owned(),
35            support: Support::Available,
36            transfer_mode: None,
37        })
38        .collect()
39}
40
41/// Indexes every track of an MP4 or WebM source, detected by signature. A
42/// source that is neither is read as MP4, whose demuxer reports what is wrong.
43#[doc(hidden)]
44pub async fn open_tracks<S: ByteSource + ?Sized>(
45    source: &S,
46    limits: &Limits,
47) -> Result<Vec<Mp4Track>> {
48    if probe_container(source).await? == Some(Container::WebM) {
49        let demuxer = WebmDemuxer::open(
50            source,
51            WebmDemuxerOptions {
52                limits: *limits,
53                ..WebmDemuxerOptions::default()
54            },
55        )
56        .await?;
57        return Ok(demuxer.tracks);
58    }
59    let demuxer = Mp4Demuxer::open(
60        source,
61        Mp4DemuxerOptions {
62            limits: *limits,
63            ..Mp4DemuxerOptions::default()
64        },
65    )
66    .await?;
67    Ok(demuxer.tracks)
68}
69
70/// Indexes the `index`th audio track of an MP4 or WebM source, detected by
71/// signature, together with its timing on the decoded sample clock: an MP4
72/// track's edit list, or a WebM track's `CodecDelay` and `DiscardPadding`.
73#[doc(hidden)]
74pub async fn open_audio_track<S: ByteSource + ?Sized>(
75    source: &S,
76    index: usize,
77    limits: &Limits,
78) -> Result<(Mp4Track, AudioTrackTiming)> {
79    let no_track = || Error::new(ErrorKind::InvalidInput, "no such audio track");
80    if probe_container(source).await? == Some(Container::WebM) {
81        let demuxer = WebmDemuxer::open(
82            source,
83            WebmDemuxerOptions {
84                limits: *limits,
85                ..WebmDemuxerOptions::default()
86            },
87        )
88        .await?;
89        let track = demuxer
90            .tracks
91            .iter()
92            .filter(|track| track.kind == TrackKind::Audio)
93            .nth(index)
94            .ok_or_else(no_track)?;
95        let timing = demuxer.audio_timing(track.id)?;
96        return Ok((track.clone(), timing));
97    }
98    let demuxer = Mp4Demuxer::open(
99        source,
100        Mp4DemuxerOptions {
101            limits: *limits,
102            ..Mp4DemuxerOptions::default()
103        },
104    )
105    .await?;
106    let track = demuxer
107        .tracks
108        .into_iter()
109        .filter(|track| track.kind == TrackKind::Audio)
110        .nth(index)
111        .ok_or_else(no_track)?;
112    let timing = track.audio_timing(demuxer.movie_timescale)?;
113    Ok((track, timing))
114}