-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlib.rs
More file actions
220 lines (211 loc) · 9.81 KB
/
Copy pathlib.rs
File metadata and controls
220 lines (211 loc) · 9.81 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
pub mod aac_asc;
pub mod ac3_sync;
pub mod dts_sync;
pub(crate) mod annexb;
pub mod avi;
pub mod cmaf;
pub mod demux;
pub mod hls;
pub mod mp4_sanitize;
pub mod mux;
pub mod nal_mux;
pub mod sniff;
pub mod streaming;
pub mod ts;
pub use sniff::{ContainerKind, sniff_container};
/// Parameters required to bolt an audio track onto `Av1Mp4Muxer`.
///
/// Four codec families are supported:
/// - **AAC-LC** (Squad-18, task #63 v1): mono or stereo, sample_rate as the
/// mdhd timescale per ISO/IEC 14496-14 standard practice, and the
/// AudioSpecificConfig surfaced verbatim from the demuxer (see
/// `demux::AudioTrack::asc`) so HE-AAC / xHE-AAC signalling bits survive
/// the passthrough intact. Sample entry: `mp4a` + `esds`.
/// - **Opus** (Squad-23): mono or stereo, sample_rate is the source's
/// `InputSampleRate` (typically 48000), `mdhd` timescale is pinned at
/// 48000 per RFC 7845 §3 (Opus internally always operates at 48 kHz).
/// Sample entry: `Opus` (4cc per RFC 7845 §4.4 — capital O) + `dOps`
/// (Opus-Specific Box per §4.5). The `OpusHead` body bytes are carried
/// in `codec_private` and emitted verbatim inside `dOps`.
/// - **AC-3** / Dolby Digital (Squad-26): up to 5.1 channels, sample_rate
/// from the source's syncframe (32 / 44.1 / 48 kHz). Sample entry:
/// `ac-3` + `dac3` (ETSI TS 102 366 §F.4 / Annex F). The 3-byte `dac3`
/// body is carried in `codec_private` and emitted verbatim.
/// - **E-AC-3** / Dolby Digital Plus (Squad-26): up to 5.1 channels in v1
/// scope (single independent substream). Sample entry: `ec-3` + `dec3`
/// (ETSI TS 102 366 §F.6). The `dec3` body is carried in `codec_private`
/// and emitted verbatim.
///
/// Discriminator: `codec` field. `"aac"` → AAC path; `"opus"` → Opus path;
/// `"ac3"` → AC-3 path; `"eac3"` → E-AC-3 path. Anything else is rejected
/// at `with_audio()` time.
#[derive(Debug, Clone)]
pub struct AudioInfo {
/// Human-readable codec tag. Muxer accepts `"aac"` (case-insensitive)
/// and `"opus"` (case-insensitive). Anything else is rejected with a
/// clear error — this is intentional (no stubs).
pub codec: String,
/// Audio sample rate in Hz. For AAC: typically 44100 / 48000; doubles as
/// the `mdhd` timescale. For Opus: the source's `InputSampleRate`
/// (informational; the mdhd timescale is pinned to 48000 per RFC 7845
/// regardless of this value).
pub sample_rate: u32,
/// Channel count. Both codecs support 1 (mono) and 2 (stereo) only;
/// the muxer bails on other values.
pub channels: u16,
/// Audio timescale in ticks per second. AAC: equals `sample_rate`.
/// Opus: caller should pass 48000 (RFC 7845); the muxer additionally
/// validates this for the Opus path.
pub timescale: u32,
/// AudioSpecificConfig bytes verbatim from the demuxer (AAC only).
/// Embedded into the `esds` box's DecoderSpecificInfo (tag 0x05)
/// payload. Empty for non-AAC codecs.
pub asc_bytes: Vec<u8>,
/// Codec-private body bytes (Opus / AC-3 / E-AC-3). For Opus this MUST
/// be the RFC 7845 §5.1 `OpusHead` payload (the same bytes a WebM/MKV
/// `CodecPrivate` element would carry; see RFC 7845 §5.2 for the
/// MKV mapping). Emitted verbatim as the body of the `dOps` box
/// inside the `Opus` sample entry. For AC-3 this carries the 3-byte
/// `dac3` body (ETSI TS 102 366 §F.4); for E-AC-3 the variable-size
/// `dec3` body (§F.6). Empty for AAC.
///
/// Layout (RFC 7845 §5.1, 19 bytes minimum for ChannelMappingFamily=0
/// with the 8-byte 'OpusHead' magic prefix; the magic is NOT carried
/// in `dOps` — only the post-magic body, which is 11 bytes minimum):
/// - `Version` u8 = 1 (in OpusHead; mapped to 0 in dOps per §4.5)
/// - `OutputChannelCount` u8
/// - `PreSkip` u16 LE (in OpusHead; converted to BE for dOps per §4.5)
/// - `InputSampleRate` u32 LE (LE in OpusHead, BE in dOps)
/// - `OutputGain` i16 LE (LE in OpusHead, BE in dOps)
/// - `ChannelMappingFamily` u8
/// - (if family != 0: 1 + 1 + N additional bytes)
///
/// The byte-order conversion between OpusHead (Ogg LE convention) and
/// dOps (ISOBMFF BE convention) is handled by `build_dops` in mux.rs.
/// Callers should pass the OpusHead bytes (LE numeric fields) — that's
/// the form the MKV / WebM demuxer surfaces directly out of CodecPrivate.
pub codec_private: Vec<u8>,
}
impl AudioInfo {
/// Convenience constructor for the AAC-LC path. Mirrors Squad-18's
/// original API surface so existing AAC call sites stay terse.
pub fn aac_lc(sample_rate: u32, channels: u16, asc_bytes: Vec<u8>) -> Self {
Self {
codec: "aac".into(),
sample_rate,
channels,
timescale: sample_rate,
asc_bytes,
codec_private: Vec::new(),
}
}
/// Convenience constructor for the Opus path. Pins timescale to 48000
/// per RFC 7845 §3 — Opus is internally always 48 kHz so the mdhd
/// timescale, not the source's nominal `InputSampleRate`, is what
/// drives sample-duration math on every player.
pub fn opus(input_sample_rate: u32, channels: u16, codec_private: Vec<u8>) -> Self {
Self {
codec: "opus".into(),
sample_rate: input_sample_rate,
channels,
timescale: 48_000,
asc_bytes: Vec::new(),
codec_private,
}
}
/// Convenience constructor for the AC-3 (Dolby Digital) passthrough
/// path (Squad-26). `codec_private` carries the 3-byte `dac3` body
/// payload (ETSI TS 102 366 §F.4) the muxer writes verbatim into the
/// `dac3` box. mdhd timescale = sample_rate (48000 / 44100 / 32000) —
/// AC-3 doesn't have Opus's "internally fixed at 48 kHz" rule.
pub fn ac3(sample_rate: u32, channels: u16, dac3_body: Vec<u8>) -> Self {
Self {
codec: "ac3".into(),
sample_rate,
channels,
timescale: sample_rate,
asc_bytes: Vec::new(),
codec_private: dac3_body,
}
}
/// Convenience constructor for the E-AC-3 (Dolby Digital Plus) passthrough
/// path (Squad-26). `codec_private` carries the `dec3` body payload
/// (ETSI TS 102 366 §F.6) — variable size based on substream count;
/// minimum ~5 bytes for the single-independent-substream case.
pub fn eac3(sample_rate: u32, channels: u16, dec3_body: Vec<u8>) -> Self {
Self {
codec: "eac3".into(),
sample_rate,
channels,
timescale: sample_rate,
asc_bytes: Vec::new(),
codec_private: dec3_body,
}
}
/// Convenience constructor for the **DTS passthrough** path.
/// `codec_private` carries the 20-byte `ddts` body, built by
/// [`crate::mux::ddts_body_from_sync`] from the first frame's core header.
/// rivet has no DTS decoder, so passthrough is the only handling — a DTS
/// track can be copied, but not re-encoded or filtered.
pub fn dts(sample_rate: u32, channels: u16, ddts_body: Vec<u8>) -> Self {
Self {
codec: "dts".into(),
sample_rate,
channels,
timescale: sample_rate,
asc_bytes: Vec::new(),
codec_private: ddts_body,
}
}
}
/// Extended MKV colour/mastering metadata parsed from `Segment → Tracks →
/// TrackEntry → Video → Colour` and its nested `MasteringMetadata`. The
/// core H.273-equivalent fields (matrix / primaries / transfer /
/// full-range) round-trip through `StreamInfo.color_metadata` on
/// `DemuxResult`; this struct exists to carry the rest (bits_per_channel,
/// chroma siting / subsampling offsets, MaxCLL/MaxFALL, SMPTE-2086
/// mastering chromaticities) without requiring a breaking extension of
/// the shared `StreamInfo` type in the `codec` crate.
///
/// Populated by `demux::probe_mkv_color_info` for callers that need it
/// (mux HDR signalling, future SEI passthrough). Returns `None` for
/// non-MKV containers and for MKVs with no `Colour` element.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct MkvColorInfo {
/// MatroskaElement 0x55B2 — decoded bits per channel (e.g. 10 for
/// HDR10 sources).
pub bits_per_channel: Option<u8>,
/// MatroskaElement 0x55B3 — Cb/Cr horizontal subsampling ratio.
pub chroma_subsampling_horz: Option<u8>,
/// MatroskaElement 0x55B4 — Cb/Cr vertical subsampling ratio.
pub chroma_subsampling_vert: Option<u8>,
/// MatroskaElement 0x55B7 — horizontal chroma siting (0=unspecified,
/// 1=left-collocated, 2=half).
pub chroma_siting_horz: Option<u8>,
/// MatroskaElement 0x55B8 — vertical chroma siting.
pub chroma_siting_vert: Option<u8>,
/// MatroskaElement 0x55BC — MaxCLL in cd/m².
pub max_cll: Option<u32>,
/// MatroskaElement 0x55BD — MaxFALL in cd/m².
pub max_fall: Option<u32>,
/// MatroskaElement 0x55D0 nested — SMPTE ST 2086 mastering display
/// primaries + luminance. Emitted when any sub-element is present.
pub mastering: Option<MkvMasteringMetadata>,
}
/// SMPTE ST 2086 mastering display metadata, carried verbatim from the
/// MKV `MasteringMetadata` sub-element. Used by HDR10 mux and by future
/// SEI-passthrough paths to preserve the creator-intended display gamut
/// and min/max luminance.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct MkvMasteringMetadata {
pub primary_r_chromaticity_x: Option<f64>,
pub primary_r_chromaticity_y: Option<f64>,
pub primary_g_chromaticity_x: Option<f64>,
pub primary_g_chromaticity_y: Option<f64>,
pub primary_b_chromaticity_x: Option<f64>,
pub primary_b_chromaticity_y: Option<f64>,
pub white_point_chromaticity_x: Option<f64>,
pub white_point_chromaticity_y: Option<f64>,
pub luminance_max: Option<f64>,
pub luminance_min: Option<f64>,
}