EBML: Start parsing \Ebml\Segments\Tracks

This commit is contained in:
Serial 2024-07-29 12:35:59 -04:00
parent 9f1d6325a3
commit 10c3e30ae8
No known key found for this signature in database
GPG key ID: DA95198DC17C4568
8 changed files with 158 additions and 47 deletions

View file

@ -169,11 +169,11 @@ ebml_master_elements! {
struct ElementReaderContext {
/// Previous master element
previous_master: Option<MasterElement>,
previous_master_length: u64,
previous_master_length: VInt,
/// Current master element
current_master: Option<MasterElement>,
/// Remaining length of the master element
master_length: u64,
master_length: VInt,
/// Maximum size in octets of all element IDs
max_id_length: u8,
/// Maximum size in octets of all element data sizes
@ -189,9 +189,9 @@ impl Default for ElementReaderContext {
fn default() -> Self {
Self {
previous_master: None,
previous_master_length: 0,
previous_master_length: VInt::ZERO,
current_master: None,
master_length: 0,
master_length: VInt::ZERO,
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxidlength-element
max_id_length: 4,
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxsizelength-element
@ -202,12 +202,32 @@ impl Default for ElementReaderContext {
}
pub(crate) enum ElementReaderYield {
Master((ElementIdent, u64)),
Child((ChildElementDescriptor, u64)),
Master((ElementIdent, VInt)),
Child((ChildElementDescriptor, VInt)),
Unknown(ElementHeader),
Eof,
}
impl ElementReaderYield {
pub fn ident(&self) -> Option<u64> {
match self {
ElementReaderYield::Master((ident, _)) => Some(*ident as u64),
ElementReaderYield::Child((child, _)) => Some(child.ident as u64),
ElementReaderYield::Unknown(header) => Some(header.id.value()),
_ => None,
}
}
pub fn size(&self) -> Option<u64> {
match self {
ElementReaderYield::Master((_, size)) => Some(size.value()),
ElementReaderYield::Child((_, size)) => Some(size.value()),
ElementReaderYield::Unknown(header) => Some(header.size.value()),
_ => None,
}
}
}
pub struct ElementReader<R> {
reader: R,
ctx: ElementReaderContext,
@ -250,7 +270,7 @@ where
fn goto_next_master(&mut self) -> Result<ElementReaderYield> {
if self.ctx.master_length != 0 {
self.skip(self.ctx.master_length)?;
self.skip(self.ctx.master_length.value())?;
}
let header = ElementHeader::read(
@ -265,7 +285,7 @@ where
self.store_previous_master();
self.ctx.current_master = Some(*master);
self.ctx.master_length = header.size.value();
self.ctx.master_length = header.size;
Ok(ElementReaderYield::Master((
master.id,
self.ctx.master_length,
@ -312,16 +332,13 @@ where
.get(&header.id)
.expect("Nested master elements should be defined at this level."),
);
self.ctx.master_length = header.size.value();
self.ctx.master_length = header.size;
// We encountered a nested master element
return Ok(ElementReaderYield::Master((
child.ident,
header.size.value(),
)));
return Ok(ElementReaderYield::Master((child.ident, header.size)));
}
Ok(ElementReaderYield::Child((*child, header.size.value())))
Ok(ElementReaderYield::Child((*child, header.size)))
}
fn lock(&mut self) {

View file

@ -92,13 +92,13 @@ where
}
if ident == ElementIdent::EBMLMaxIDLength {
properties.header.max_id_length = child_reader.read_unsigned_int(size)? as u8;
properties.header.max_id_length = child_reader.read_unsigned_int(size.value())? as u8;
child_reader.set_max_id_length(properties.header.max_id_length);
continue;
}
if ident == ElementIdent::EBMLMaxSizeLength {
properties.header.max_size_length = child_reader.read_unsigned_int(size)? as u8;
properties.header.max_size_length = child_reader.read_unsigned_int(size.value())? as u8;
child_reader.set_max_size_length(properties.header.max_size_length);
continue;
}
@ -106,22 +106,24 @@ where
// Anything else in the header is unnecessary, and only read for the properties
// struct
if !parse_options.read_properties {
child_reader.skip(size)?;
child_reader.skip(size.value())?;
continue;
}
match ident {
ElementIdent::EBMLVersion => {
properties.header.version = child_reader.read_unsigned_int(size)?
properties.header.version = child_reader.read_unsigned_int(size.value())?
},
ElementIdent::EBMLReadVersion => {
properties.header.read_version = child_reader.read_unsigned_int(size)?
properties.header.read_version = child_reader.read_unsigned_int(size.value())?
},
ElementIdent::DocType => {
properties.header.doc_type = child_reader.read_string(size.value())?
},
ElementIdent::DocType => properties.header.doc_type = child_reader.read_string(size)?,
ElementIdent::DocTypeVersion => {
properties.header.doc_type_version = child_reader.read_unsigned_int(size)?
properties.header.doc_type_version = child_reader.read_unsigned_int(size.value())?
},
_ => child_reader.skip(size)?,
_ => child_reader.skip(size.value())?,
}
}

View file

@ -34,17 +34,11 @@ where
ElementIdent::Tracks if parse_options.read_properties => {
segment_tracks::read_from(children_reader.inner(), parse_options, properties)?
},
ElementIdent::Tags | ElementIdent::Attachments | ElementIdent::Chapters => {
ElementIdent::Tags | ElementIdent::Chapters if parse_options.read_tags => {
let mut tag = tags.unwrap_or_default();
if id == ElementIdent::Tags {
segment_tags::read_from(children_reader.inner(), parse_options, &mut tag)?
} else if id == ElementIdent::Attachments {
segment_attachments::read_from(
children_reader.inner(),
parse_options,
&mut tag,
)?
} else {
segment_chapters::read_from(
children_reader.inner(),
@ -55,12 +49,23 @@ where
tags = Some(tag);
},
ElementIdent::Attachments if parse_options.read_cover_art => {
let mut tag = tags.unwrap_or_default();
segment_attachments::read_from(
children_reader.inner(),
parse_options,
&mut tag,
)?;
tags = Some(tag);
},
_ => {
// 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 master element: {:?}", id);
children_reader.skip(size)?;
children_reader.skip(size.value())?;
children_reader.goto_previous_master()?;
continue;
},

View file

@ -23,7 +23,7 @@ where
// elements, so we can just skip them.
log::debug!("Skipping EBML master element: {:?}", id);
children_reader.skip(size)?;
children_reader.skip(size.value())?;
children_reader.goto_previous_master()?;
continue;
},
@ -31,7 +31,7 @@ where
match child.ident {
ElementIdent::TimecodeScale => {
properties.segment_info.timestamp_scale =
children_reader.read_unsigned_int(size)?;
children_reader.read_unsigned_int(size.value())?;
if properties.segment_info.timestamp_scale == 0 {
log::warn!("Segment.Info.TimecodeScale is 0, which is invalid");
@ -41,17 +41,19 @@ where
}
},
ElementIdent::MuxingApp => {
properties.segment_info.muxing_app = children_reader.read_utf8(size)?
properties.segment_info.muxing_app =
children_reader.read_utf8(size.value())?
},
ElementIdent::WritingApp => {
properties.segment_info.writing_app = children_reader.read_utf8(size)?
properties.segment_info.writing_app =
children_reader.read_utf8(size.value())?
},
_ => {
// 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.ident);
children_reader.skip(size)?;
children_reader.skip(size.value())?;
continue;
},
}

View file

@ -1,5 +1,7 @@
use crate::config::ParseOptions;
use crate::ebml::element_reader::{ElementIdent, ElementReader, ElementReaderYield};
use crate::ebml::element_reader::{
ChildElementDescriptor, ElementHeader, ElementIdent, ElementReader, ElementReaderYield,
};
use crate::ebml::properties::EbmlProperties;
use crate::error::Result;
use crate::macros::decode_err;
@ -7,6 +9,43 @@ use crate::macros::decode_err;
use std::io::{Read, Seek};
pub(super) fn read_from<R>(
element_reader: &mut ElementReader<R>,
parse_options: ParseOptions,
properties: &mut EbmlProperties,
) -> Result<()>
where
R: Read + Seek,
{
let mut children_reader = element_reader.children();
while let Some(child) = children_reader.next()? {
match child {
ElementReaderYield::Master((ElementIdent::TrackEntry, size)) => {
read_track_entry(children_reader.inner(), parse_options, properties)?;
},
ElementReaderYield::Eof => {
break;
},
_ => {
let id = child
.ident()
.expect("Child element must have an identifier");
let size = child.size().expect("Child element must have a size");
log::warn!(
"Unexpected child element in \\EBML\\Segment\\Tracks: {:?}, skipping",
id
);
children_reader.skip(size)?;
continue;
},
}
}
Ok(())
}
fn read_track_entry<R>(
_element_reader: &mut ElementReader<R>,
_parse_options: ParseOptions,
_properties: &mut EbmlProperties,
@ -14,5 +53,5 @@ pub(super) fn read_from<R>(
where
R: Read + Seek,
{
unimplemented!("\\Ebml\\Segment\\Tracks")
Ok(())
}

View file

@ -2,6 +2,7 @@ use crate::error::Result;
use crate::macros::err;
use std::io::Read;
use std::ops::{Add, Sub};
use byteorder::{ReadBytesExt, WriteBytesExt};
@ -20,7 +21,12 @@ impl VInt {
const MAX_OCTET_LENGTH: u64 = 8;
const USABLE_BITS: u64 = Self::MAX_OCTET_LENGTH * Self::USABLE_BITS_PER_BYTE;
const MAX_VALUE: u64 = u64::MAX >> (u64::BITS as u64 - Self::USABLE_BITS);
/// The maximum value that can be represented by a `VInt`
pub const MAX: u64 = u64::MAX >> (u64::BITS as u64 - Self::USABLE_BITS);
/// The minimum value that can be represented by a `VInt`
pub const MIN: u64 = 0;
/// A `VInt` with a value of 0
pub const ZERO: Self = Self(0);
/// Create a signed `VInt` from a `u64`
///
@ -43,7 +49,7 @@ impl VInt {
/// # Ok(()) }
/// ```
pub fn from_u64(uint: u64) -> Result<Self> {
if uint > Self::MAX_VALUE {
if uint > Self::MAX {
err!(BadVintSize);
}
@ -249,6 +255,35 @@ impl VInt {
Ok(ret)
}
pub(crate) fn saturating_sub(&self, other: u64) -> Self {
Self(self.0.saturating_sub(other))
}
}
impl Sub for VInt {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self(self.0 - other.0)
}
}
impl Add for VInt {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
let val = self.0 + other.0;
assert!(val <= Self::MAX, "VInt overflow");
Self(val)
}
}
impl PartialEq<u64> for VInt {
fn eq(&self, other: &u64) -> bool {
self.0 == *other
}
}
#[cfg(test)]

View file

@ -1,9 +1,10 @@
use proc_macro::TokenStream;
use std::collections::HashSet;
use std::collections::HashMap;
use syn::parse::{Parse, Parser};
use syn::punctuated::Punctuated;
use syn::{braced, bracketed, Ident, Token};
#[derive(Debug)]
pub(crate) struct EbmlMasterElement {
pub(crate) readable_ident: Ident,
pub(crate) info: EbmlMasterInfo,
@ -24,6 +25,7 @@ impl Parse for EbmlMasterElement {
}
}
#[derive(Debug)]
pub(crate) struct EbmlMasterInfo {
pub(crate) id: u64,
pub(crate) children: Vec<EbmlChildElement>,
@ -54,6 +56,7 @@ impl Parse for EbmlMasterInfo {
}
}
#[derive(Debug)]
pub(crate) struct EbmlChildElement {
pub(crate) readable_ident: Ident,
pub(crate) info: EbmlChildInfo,
@ -74,6 +77,7 @@ impl Parse for EbmlChildElement {
}
}
#[derive(Debug)]
pub(crate) struct EbmlChildInfo {
pub(crate) id: u64,
pub(crate) data_type: Ident,
@ -90,17 +94,17 @@ impl Parse for EbmlChildInfo {
}
}
fn insert_element_identifiers(identifiers: &mut HashSet<Ident>, element: &EbmlMasterElement) {
identifiers.insert(element.readable_ident.clone());
fn insert_element_identifiers(identifiers: &mut HashMap<Ident, u64>, element: &EbmlMasterElement) {
identifiers.insert(element.readable_ident.clone(), element.info.id);
for child in &element.info.children {
identifiers.insert(child.readable_ident.clone());
identifiers.insert(child.readable_ident.clone(), child.info.id);
}
}
pub(crate) fn parse_ebml_master_elements(
input: TokenStream,
) -> syn::Result<(HashSet<Ident>, Vec<EbmlMasterElement>)> {
let mut element_identifiers = HashSet::new();
) -> syn::Result<(HashMap<Ident, u64>, Vec<EbmlMasterElement>)> {
let mut element_identifiers = HashMap::new();
let parser = Punctuated::<EbmlMasterElement, Token![,]>::parse_terminated;
let elements = parser.parse(input)?;

View file

@ -79,7 +79,6 @@ pub fn ebml_master_elements(input: TokenStream) -> TokenStream {
}
let (identifiers, elements) = ret.unwrap();
let identifiers_iter = identifiers.iter();
let elements_map_inserts = elements.iter().map(|element| {
let readable_ident = &element.readable_ident;
let id = element.info.id;
@ -106,10 +105,18 @@ pub fn ebml_master_elements(input: TokenStream) -> TokenStream {
}
});
let mut ident_variants = Vec::new();
for (ident, id) in &identifiers {
ident_variants.push(quote! {
#ident = #id,
});
}
TokenStream::from(quote! {
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[repr(u64)]
pub(crate) enum ElementIdent {
#( #identifiers_iter ),*
#( #ident_variants )*
}
fn master_elements() -> &'static ::std::collections::HashMap<VInt, MasterElement> {