11use super :: Language ;
22use crate :: properties:: FileProperties ;
33
4+ use std:: time:: Duration ;
5+
46/// Properties from the EBML header
57///
68/// These are present for all EBML formats.
@@ -77,6 +79,7 @@ pub struct SegmentInfo {
7779 pub ( crate ) timestamp_scale : u64 ,
7880 pub ( crate ) muxing_app : String ,
7981 pub ( crate ) writing_app : String ,
82+ pub ( crate ) duration : Option < Duration > ,
8083}
8184
8285impl SegmentInfo {
@@ -100,6 +103,14 @@ impl SegmentInfo {
100103 pub fn writing_app ( & self ) -> & str {
101104 & self . writing_app
102105 }
106+
107+ /// The duration of the segment
108+ ///
109+ /// NOTE: This information is not always present in the segment, in which case
110+ /// [`EbmlProperties::duration`] should be used.
111+ pub fn duration ( & self ) -> Option < Duration > {
112+ self . duration
113+ }
103114}
104115
105116impl Default for SegmentInfo {
@@ -109,6 +120,7 @@ impl Default for SegmentInfo {
109120 timestamp_scale : 1_000_000 ,
110121 muxing_app : String :: new ( ) ,
111122 writing_app : String :: new ( ) ,
123+ duration : None ,
112124 }
113125 }
114126}
@@ -210,11 +222,15 @@ impl AudioTrackDescriptor {
210222/// Settings for an audio track
211223#[ derive( Debug , Clone , PartialEq , Default ) ]
212224pub struct AudioTrackSettings {
225+ // Provided to us for free
213226 pub ( crate ) sampling_frequency : f64 ,
214227 pub ( crate ) output_sampling_frequency : f64 ,
215228 pub ( crate ) channels : u8 ,
216229 pub ( crate ) bit_depth : Option < u8 > ,
217230 pub ( crate ) emphasis : Option < EbmlAudioTrackEmphasis > ,
231+
232+ // Need to be calculated
233+ pub ( crate ) bitrate : Option < u32 > ,
218234}
219235
220236impl AudioTrackSettings {
@@ -322,27 +338,67 @@ impl EbmlProperties {
322338
323339 /// Information about the default audio track
324340 ///
325- /// The information is extracted from the first audio track with its default flag set
326- /// in the `\Segment\Tracks` element.
341+ /// The "default" track is selected as:
342+ /// 1. The first audio track with its `default` flag set
343+ /// 2. If 1 fails, just grab the first audio track with its `enabled` flag set
327344 pub fn default_audio_track ( & self ) -> Option < & AudioTrackDescriptor > {
328- self . audio_tracks . iter ( ) . find ( |track| track. default )
345+ if let Some ( position) = self . default_audio_track_position ( ) {
346+ return self . audio_tracks . get ( position) ;
347+ }
348+
349+ None
350+ }
351+
352+ // TODO: Actually calculate from cluster
353+ /// The duration of the default audio track
354+ ///
355+ /// NOTE: see [`EbmlProperties::default_audio_track`]
356+ ///
357+ /// This will always use the duration written in `\Segment\Info` if present. Otherwise, it will
358+ /// be manually calculated using `\Segment\Cluster` data.
359+ pub fn duration ( & self ) -> Duration {
360+ self . segment_info . duration ( ) . unwrap ( )
361+ }
362+
363+ /// Audio bitrate (kbps)
364+ ///
365+ /// NOTE: This is the bitrate of the default audio track see [`EbmlProperties::default_audio_track`]
366+ /// for what this means.
367+ pub fn bitrate ( & self ) -> Option < u32 > {
368+ self . default_audio_track ( )
369+ . and_then ( |track| track. settings . bitrate )
370+ }
371+
372+ pub ( crate ) fn default_audio_track_position ( & self ) -> Option < usize > {
373+ self . audio_tracks
374+ . iter ( )
375+ . position ( |track| track. default )
376+ . or_else ( || {
377+ // Otherwise, it's normal to just pick the first enabled track
378+ self . audio_tracks . iter ( ) . position ( |track| track. enabled )
379+ } )
329380 }
330381}
331382
332383impl From < EbmlProperties > for FileProperties {
333384 fn from ( input : EbmlProperties ) -> Self {
334385 let Some ( default_audio_track) = input. default_audio_track ( ) else {
335- return FileProperties :: default ( ) ;
386+ let mut properties = FileProperties :: default ( ) ;
387+ if let Some ( duration) = input. segment_info . duration {
388+ properties. duration = duration;
389+ }
390+
391+ return properties;
336392 } ;
337393
338394 Self {
339- duration : todo ! ( "Support duration" ) ,
340- overall_bitrate : todo ! ( "Support bitrate" ) ,
341- audio_bitrate : todo ! ( "Support bitrate" ) ,
395+ duration : input . duration ( ) ,
396+ overall_bitrate : input . bitrate ( ) ,
397+ audio_bitrate : input . bitrate ( ) ,
342398 sample_rate : Some ( default_audio_track. settings . sampling_frequency as u32 ) ,
343399 bit_depth : default_audio_track. settings . bit_depth ,
344400 channels : Some ( default_audio_track. settings . channels ) ,
345- channel_mask : todo ! ( "Channel mask" ) ,
401+ channel_mask : None , // TODO: Will require reading into track data
346402 }
347403 }
348404}
0 commit comments