Skip to content

Commit c704999

Browse files
committed
EBML: Specify most properties we'll end up reading
Signed-off-by: Serial <69764315+Serial-ATA@users.noreply.github.com>
1 parent ce834ac commit c704999

File tree

2 files changed

+223
-5
lines changed

2 files changed

+223
-5
lines changed

src/ebml/properties.rs

Lines changed: 221 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,247 @@ pub struct EbmlHeaderProperties {
1111
pub(crate) doc_type_read_version: u64,
1212
}
1313

14+
impl EbmlHeaderProperties {
15+
/// The EBML version, should be `1`
16+
pub fn version(&self) -> u64 {
17+
self.version
18+
}
19+
20+
/// The minimum EBML version required to read the file, <= [`version`]
21+
pub fn read_version(&self) -> u64 {
22+
self.read_version
23+
}
24+
25+
/// The maximum length of an EBML element ID, in octets
26+
pub fn max_id_length(&self) -> u8 {
27+
self.max_id_length
28+
}
29+
30+
/// The maximum length of an EBML element size, in octets
31+
pub fn max_size_length(&self) -> u8 {
32+
self.max_size_length
33+
}
34+
35+
/// A string that describes the type of document
36+
pub fn doc_type(&self) -> &str {
37+
&self.doc_type
38+
}
39+
40+
/// The version of DocType interpreter used to create the EBML Document
41+
pub fn doc_type_version(&self) -> u64 {
42+
self.doc_type_version
43+
}
44+
45+
/// The minimum DocType interpreter version needed to read the EBML Document
46+
pub fn doc_type_read_version(&self) -> u64 {
47+
self.doc_type_read_version
48+
}
49+
}
50+
1451
#[derive(Debug, Clone, PartialEq, Default)]
1552
pub struct EbmlExtension {
1653
pub(crate) name: String,
1754
pub(crate) version: u64,
1855
}
1956

57+
impl EbmlExtension {
58+
/// The name of the extension
59+
pub fn name(&self) -> &str {
60+
&self.name
61+
}
62+
63+
/// The version of the extension
64+
pub fn version(&self) -> u64 {
65+
self.version
66+
}
67+
}
68+
2069
#[derive(Debug, Clone, PartialEq, Default)]
2170
pub struct SegmentInfo {
22-
pub(crate) timecode_scale: u64,
71+
pub(crate) timestamp_scale: u64,
2372
pub(crate) muxing_app: String,
2473
pub(crate) writing_app: String,
2574
}
2675

76+
impl SegmentInfo {
77+
/// Base unit for Segment Ticks and Track Ticks, in nanoseconds.
78+
///
79+
/// A TimestampScale value of 1000000 means scaled timestamps in the Segment are expressed in milliseconds.
80+
pub fn timestamp_scale(&self) -> u64 {
81+
self.timestamp_scale
82+
}
83+
84+
/// Muxing application or library (example: "libmatroska-0.4.3").
85+
///
86+
/// Includes the full name of the application or library followed by the version number.
87+
pub fn muxing_app(&self) -> &str {
88+
&self.muxing_app
89+
}
90+
91+
/// Writing application (example: "mkvmerge-0.3.3").
92+
///
93+
/// Includes the full name of the application followed by the version number.
94+
pub fn writing_app(&self) -> &str {
95+
&self.writing_app
96+
}
97+
}
98+
99+
#[derive(Debug, Clone, PartialEq, Default)]
100+
pub struct AudioTrackDescriptor {
101+
pub(crate) number: u64,
102+
pub(crate) uid: u64,
103+
pub(crate) language: String,
104+
pub(crate) default_duration: u64,
105+
pub(crate) codec_id: String,
106+
pub(crate) codec_private: Vec<u8>,
107+
pub(crate) settings: AudioTrackSettings,
108+
}
109+
110+
impl AudioTrackDescriptor {
111+
/// The track number
112+
pub fn number(&self) -> u64 {
113+
self.number
114+
}
115+
116+
/// A unique ID to identify the track
117+
pub fn uid(&self) -> u64 {
118+
self.uid
119+
}
120+
121+
/// The language of the track, in the Matroska languages form
122+
///
123+
/// NOTE: See [basics](https://matroska.org/technical/basics.html#language-codes) on language codes.
124+
pub fn language(&self) -> &str {
125+
&self.language
126+
}
127+
128+
/// The default duration of the track
129+
pub fn default_duration(&self) -> u64 {
130+
self.default_duration
131+
}
132+
133+
/// The codec ID of the track
134+
///
135+
/// NOTE: See [Matroska codec RFC] for more info.
136+
///
137+
/// [Matroska codec RFC]: https://matroska.org/technical/codec_specs.html
138+
pub fn codec_id(&self) -> &str {
139+
&self.codec_id
140+
}
141+
142+
/// Private data only known to the codec
143+
pub fn codec_private(&self) -> &[u8] {
144+
&self.codec_private
145+
}
146+
147+
/// The audio settings of the track
148+
pub fn settings(&self) -> &AudioTrackSettings {
149+
&self.settings
150+
}
151+
}
152+
153+
#[derive(Debug, Clone, PartialEq, Default)]
154+
pub struct AudioTrackSettings {
155+
pub(crate) sampling_frequency: u32,
156+
pub(crate) output_sampling_frequency: u32,
157+
pub(crate) channels: u8,
158+
pub(crate) bit_depth: Option<u8>,
159+
pub(crate) emphasis: Option<EbmlAudioTrackEmphasis>,
160+
}
161+
162+
impl AudioTrackSettings {
163+
/// The sampling frequency of the track
164+
pub fn sampling_frequency(&self) -> u32 {
165+
self.sampling_frequency
166+
}
167+
168+
/// Real output sampling frequency in Hz (used for SBR techniques).
169+
///
170+
/// The default value for `output_sampling_frequency` of the same TrackEntry is equal to the [`Self::sampling_frequency`].
171+
pub fn output_sampling_frequency(&self) -> u32 {
172+
self.output_sampling_frequency
173+
}
174+
175+
/// The number of channels in the track
176+
pub fn channels(&self) -> u8 {
177+
self.channels
178+
}
179+
180+
/// The bit depth of the track
181+
pub fn bit_depth(&self) -> Option<u8> {
182+
self.bit_depth
183+
}
184+
185+
/// Audio emphasis applied on audio samples
186+
pub fn emphasis(&self) -> Option<EbmlAudioTrackEmphasis> {
187+
self.emphasis
188+
}
189+
}
190+
191+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
192+
pub enum EbmlAudioTrackEmphasis {
193+
None = 0,
194+
CdAudio = 1,
195+
Reserved = 2,
196+
CcitJ17 = 3,
197+
Fm50 = 4,
198+
Fm75 = 5,
199+
PhonoRiaa = 10,
200+
PhonoIecN78 = 11,
201+
PhonoTeldec = 12,
202+
PhonoEmi = 13,
203+
PhonoColumbiaLp = 14,
204+
PhonoLondon = 15,
205+
PhonoNartb = 16,
206+
}
207+
27208
/// EBML audio properties
28209
#[derive(Debug, Clone, PartialEq, Default)]
29210
pub struct EbmlProperties {
30211
pub(crate) header: EbmlHeaderProperties,
31212
pub(crate) extensions: Vec<EbmlExtension>,
32213
pub(crate) segment_info: SegmentInfo,
214+
pub(crate) default_audio_track: AudioTrackDescriptor,
215+
}
216+
217+
impl EbmlProperties {
218+
/// The EBML header properties
219+
///
220+
/// This includes the properties that are part of the EBML base specification.
221+
/// All Matroska-specific properties are in [`Self::segment_info`] and [`Self::default_audio_track`].
222+
pub fn header(&self) -> &EbmlHeaderProperties {
223+
&self.header
224+
}
225+
226+
/// The DocType extensions
227+
pub fn extensions(&self) -> &[EbmlExtension] {
228+
&self.extensions
229+
}
230+
231+
/// Information from the Matroska `\EBML\Segment\Info` element
232+
pub fn segment_info(&self) -> &SegmentInfo {
233+
&self.segment_info
234+
}
235+
236+
/// Information about the default audio track
237+
///
238+
/// The information is extracted from the first audio track with its default flag set
239+
/// in the Matroska `\EBML\Segment\Tracks` element.
240+
pub fn default_audio_track(&self) -> &AudioTrackDescriptor {
241+
&self.default_audio_track
242+
}
33243
}
34244

35245
impl From<EbmlProperties> for FileProperties {
36-
fn from(_input: EbmlProperties) -> Self {
37-
todo!()
246+
fn from(input: EbmlProperties) -> Self {
247+
Self {
248+
duration: todo!("Support duration"),
249+
overall_bitrate: todo!("Support bitrate"),
250+
audio_bitrate: todo!("Support bitrate"),
251+
sample_rate: Some(input.default_audio_track.settings.sampling_frequency),
252+
bit_depth: input.default_audio_track.settings.bit_depth,
253+
channels: Some(input.default_audio_track.settings.channels),
254+
channel_mask: todo!("Channel mask"),
255+
}
38256
}
39257
}

src/ebml/read/segment_info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ where
3131
ElementReaderYield::Child((child, size)) => {
3232
match child.ident {
3333
ElementIdent::TimecodeScale => {
34-
properties.segment_info.timecode_scale =
34+
properties.segment_info.timestamp_scale =
3535
element_reader.read_unsigned_int(size)?;
3636

37-
if properties.segment_info.timecode_scale == 0 {
37+
if properties.segment_info.timestamp_scale == 0 {
3838
log::warn!("Segment.Info.TimecodeScale is 0, which is invalid");
3939
if parse_options.parsing_mode == crate::probe::ParsingMode::Strict {
4040
decode_err!(@BAIL Ebml, "Segment.Info.TimecodeScale must be nonzero");

0 commit comments

Comments
 (0)