1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! [`ContainerFormat`] — what libavformat decided the bytes are wrapped
//! in, surfaced as the demuxer's own word.
//!
//! Read once from `AVFormatContext.iformat` while the session is opened
//! and kept for its life: libavformat picks the demuxer during
//! `avformat_open_input` and never changes it, so re-reading could only
//! answer the same thing more expensively.
use SmolStr;
/// Upper bound on the NUL search over an `AVInputFormat`'s strings.
///
/// The longest name in FFmpeg's demuxer table is a comma list a few
/// dozen bytes long and the longest description a couple of hundred;
/// the cap is generous for both and exists only so that a
/// version-skewed table cannot turn the walk into an unbounded read.
const FORMAT_TEXT_MAX_BYTES: usize = 1024;
/// The container identification libavformat made for a session.
///
/// # This is the DEMUXER's identity, not a filename's
///
/// It is `AVInputFormat`'s own words — what libavformat concluded from
/// the *bytes*, having probed them. That is precisely what a
/// content-addressed row wants and what an extension cannot give: the
/// same bytes at `movie.mov` and `movie.mp4` are one content, and this
/// answers identically for both because it never looked at the path.
///
/// # One demuxer, several words — and [`name`](Self::name) is the list
///
/// FFmpeg registers one demuxer per *family*, so its name is a
/// comma-separated list of the short names that family handles:
/// `"mov,mp4,m4a,3gp,3g2,mj2"` for the ISOBMFF demuxer, `"matroska,webm"`
/// for Matroska. [`name`](Self::name) is that string verbatim and
/// [`names`](Self::names) walks it.
///
/// **The list does not narrow to one word, and this type does not
/// pretend it does.** libavformat identified the *demuxer*; which brand
/// inside that family a file is — an `.mp4` against an `.m4a` — is a
/// question it did not answer and one nothing here can answer for it.
/// A door that returned a single word would have had to pick, and a
/// pick is the guess this whole seat exists to avoid.
///
/// # Crossing into a typed vocabulary
///
/// The words are FFmpeg's own slugs, which is what makes them
/// crossable: a consumer that wants
/// [`mediaframe::container::Format`](https://docs.rs/mediaframe) tries
/// [`names`](Self::names) against its `FromStr` and takes what it
/// recognises, deciding for itself what to do when a family offers
/// several. This crate stays out of that decision — the fold belongs to
/// whoever owns the vocabulary, and doing it here would put a second
/// one somewhere a caller cannot see it.
///
/// # An open vocabulary
///
/// Never an enum. A container FFmpeg learns to demux in its next
/// release names itself here with nothing to change on this side, which
/// is the whole reason the identity is carried as text.