use std::num::NonZero;
use crate::{
base::VInt64,
lacer::Lacer,
leaf::SimpleBlock,
master::{BlockGroup, Cluster},
*,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FrameData<'a> {
Single(&'a [u8]),
Multiple(Vec<&'a [u8]>),
}
impl<'a> FrameData<'a> {
fn single(data: &'a [u8]) -> Self {
FrameData::Single(data)
}
fn multiple(data: Vec<&'a [u8]>) -> Self {
FrameData::Multiple(data)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Frame<'a> {
pub data: FrameData<'a>,
pub is_keyframe: bool,
pub is_invisible: bool,
pub is_discardable: bool,
pub track_number: u64,
pub timestamp: i64,
pub duration: Option<NonZero<u64>>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClusterBlock {
Simple(SimpleBlock),
Group(BlockGroup),
}
impl ClusterBlock {
fn block_ref(&self) -> BlockRef<'_> {
match self {
ClusterBlock::Simple(b) => BlockRef::Simple(b),
ClusterBlock::Group(b) => BlockRef::Group(b),
}
}
}
impl From<SimpleBlock> for ClusterBlock {
fn from(b: SimpleBlock) -> Self {
ClusterBlock::Simple(b)
}
}
impl From<BlockGroup> for ClusterBlock {
fn from(b: BlockGroup) -> Self {
ClusterBlock::Group(b)
}
}
impl Encode for ClusterBlock {
fn encode<B: BufMut>(&self, buf: &mut B) -> crate::Result<()> {
match self {
ClusterBlock::Simple(b) => b.encode(buf),
ClusterBlock::Group(b) => b.encode(buf),
}
}
}
enum BlockRef<'a> {
Simple(&'a crate::leaf::SimpleBlock),
Group(&'a crate::master::BlockGroup),
}
impl<'a> BlockRef<'a> {
fn into_frame(self, cluster_ts: u64) -> crate::Result<Frame<'a>> {
match self {
BlockRef::Simple(block) => {
let body_buf = &mut &block[..];
let track_number = VInt64::decode(body_buf)?;
let relative_timestamp = body_buf.try_get_i16()?;
let flag = body_buf.try_get_u8()?;
let data = *body_buf;
let lacing = (flag >> 1) & 0x03;
Ok(Frame {
data: match lacing {
0 => FrameData::single(data),
0b01 => FrameData::multiple(Lacer::Xiph.delace(data)?),
0b11 => FrameData::multiple(Lacer::Ebml.delace(data)?),
_ => FrameData::multiple(Lacer::FixedSize.delace(data)?),
},
is_keyframe: (flag & 0x80) != 0,
is_invisible: (flag & 0x08) != 0,
is_discardable: (flag & 0x01) != 0,
track_number: *track_number,
timestamp: cluster_ts as i64 + relative_timestamp as i64,
duration: None,
})
}
BlockRef::Group(g) => {
let block = &g.block;
let body_buf = &mut &block[..];
let track_number = VInt64::decode(body_buf)?;
let relative_timestamp = body_buf.try_get_i16()?;
let flag = body_buf.try_get_u8()?;
let data = *body_buf;
let lacing = (flag >> 1) & 0x03;
Ok(Frame {
data: match lacing {
0 => FrameData::single(data),
0b01 => FrameData::multiple(Lacer::Xiph.delace(data)?),
0b11 => FrameData::multiple(Lacer::Ebml.delace(data)?),
_ => FrameData::multiple(Lacer::FixedSize.delace(data)?),
},
is_keyframe: g.reference_block.is_empty(),
is_invisible: flag & 0x08 != 0,
is_discardable: false,
track_number: *track_number,
timestamp: cluster_ts as i64 + relative_timestamp as i64,
duration: g.block_duration.and_then(|d| NonZero::new(*d)),
})
}
}
}
}
impl<'a> From<&'a crate::leaf::SimpleBlock> for BlockRef<'a> {
fn from(b: &'a crate::leaf::SimpleBlock) -> Self {
BlockRef::Simple(b)
}
}
impl<'a> From<&'a crate::master::BlockGroup> for BlockRef<'a> {
fn from(b: &'a crate::master::BlockGroup) -> Self {
BlockRef::Group(b)
}
}
impl Cluster {
pub fn frames(&self) -> impl Iterator<Item = crate::Result<Frame<'_>>> + '_ {
self.blocks
.iter()
.map(|b| b.block_ref().into_frame(*self.timestamp))
}
}