diff --git a/src/ebml/element_reader.rs b/src/ebml/element_reader.rs index 4d33a4c3..27552b41 100644 --- a/src/ebml/element_reader.rs +++ b/src/ebml/element_reader.rs @@ -224,6 +224,11 @@ where self.ctx.max_size_length = len } + fn store_previous_master(&mut self) { + self.ctx.previous_master = self.ctx.current_master; + self.ctx.previous_master_length = self.ctx.master_length; + } + fn next_master(&mut self) -> Result { let header = ElementHeader::read( &mut self.reader, @@ -235,8 +240,7 @@ where return Ok(ElementReaderYield::Unknown(header)); }; - self.ctx.previous_master = self.ctx.current_master; - self.ctx.previous_master_length = self.ctx.master_length; + self.store_previous_master(); self.ctx.current_master = Some(*master); self.ctx.master_length = header.size.value(); Ok(ElementReaderYield::Master(( @@ -288,6 +292,7 @@ where }; if child.data_type == ElementDataType::Master { + self.store_previous_master(); self.ctx.current_master = Some( *MASTER_ELEMENTS .get(&header.id) diff --git a/src/ebml/properties.rs b/src/ebml/properties.rs index 27f3acb9..b060c0c5 100644 --- a/src/ebml/properties.rs +++ b/src/ebml/properties.rs @@ -17,11 +17,19 @@ pub struct EbmlExtension { pub(crate) version: u64, } +#[derive(Debug, Clone, PartialEq, Default)] +pub struct SegmentInfo { + pub(crate) timecode_scale: u64, + pub(crate) muxing_app: String, + pub(crate) writing_app: String, +} + /// EBML audio properties #[derive(Debug, Clone, PartialEq, Default)] pub struct EbmlProperties { pub(crate) header: EbmlHeaderProperties, pub(crate) extensions: Vec, + pub(crate) segment_info: SegmentInfo, } impl From for FileProperties { diff --git a/src/ebml/read.rs b/src/ebml/read.rs index c35f88f7..9510ffed 100644 --- a/src/ebml/read.rs +++ b/src/ebml/read.rs @@ -1,4 +1,5 @@ mod segment; +mod segment_info; use super::EbmlFile; use crate::ebml::element_reader::{ElementHeader, ElementIdent, ElementReader, ElementReaderYield}; diff --git a/src/ebml/read/segment.rs b/src/ebml/read/segment.rs index 04e56618..98a99a27 100644 --- a/src/ebml/read/segment.rs +++ b/src/ebml/read/segment.rs @@ -1,3 +1,4 @@ +use super::segment_info; use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield}; use crate::ebml::properties::EbmlProperties; use crate::ebml::tag::EbmlTag; @@ -9,8 +10,8 @@ use std::io::{Read, Seek}; pub(super) fn read_from( element_reader: &mut ElementReader, - _parse_options: ParseOptions, - _properties: &mut EbmlProperties, + parse_options: ParseOptions, + properties: &mut EbmlProperties, ) -> Result> where R: Read + Seek, @@ -23,7 +24,9 @@ where let res = element_reader.next()?; match res { ElementReaderYield::Master((id, size)) => match id { - ElementIdent::Info => todo!("Support segment.Info"), + ElementIdent::Info => { + segment_info::read_from(element_reader, parse_options, properties)? + }, ElementIdent::Cluster => todo!("Support segment.Cluster"), ElementIdent::Tracks => todo!("Support segment.Tracks"), ElementIdent::Tags => todo!("Support segment.Tags"), diff --git a/src/ebml/read/segment_info.rs b/src/ebml/read/segment_info.rs new file mode 100644 index 00000000..55115a4f --- /dev/null +++ b/src/ebml/read/segment_info.rs @@ -0,0 +1,59 @@ +use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield}; +use crate::ebml::properties::EbmlProperties; +use crate::error::Result; +use crate::probe::ParseOptions; + +use std::io::{Read, Seek}; + +pub(super) fn read_from( + element_reader: &mut ElementReader, + _parse_options: ParseOptions, + _properties: &mut EbmlProperties, +) -> Result<()> +where + R: Read + Seek, +{ + element_reader.lock(); + + loop { + let res = element_reader.next()?; + match res { + ElementReaderYield::Master((id, size)) => { + // We do not end up using information from any of the nested master + // elements, so we can just skip them. + + log::debug!("Skipping EBML master element: {:?}", id); + element_reader.skip(size)?; + element_reader.goto_previous_master()?; + continue; + }, + ElementReaderYield::Child((child, size)) => { + match child.ident { + ElementIdent::TimecodeScale => todo!("Support segment.Info.TimecodeScale"), + ElementIdent::MuxingApp => todo!("Support segment.Info.MuxingApp"), + ElementIdent::WritingApp => todo!("Support segment.Info.WritingApp"), + _ => { + // We do not end up using information from all of the segment + // elements, so we can just skip any useless ones. + + log::debug!("Skipping EBML child element: {:?}", child); + element_reader.skip(size)?; + continue; + }, + } + }, + ElementReaderYield::Unknown(element) => { + log::debug!("Skipping unknown EBML element: {:X}", element.id.0); + element_reader.skip(element.size.value())?; + continue; + }, + ElementReaderYield::Eof => { + element_reader.unlock(); + break; + }, + } + } + + element_reader.goto_previous_master()?; + Ok(()) +}