use crate::seek_index::get_seek_index; use anyhow::{anyhow, bail}; use jellycommon::LocalTrack; use jellymatroska::{block::Block, read::EbmlReader, unflatten::IterWithPos, Master, MatroskaTag}; use log::{debug, info}; use std::{fs::File, io::BufReader, path::PathBuf}; pub fn extract_track( path_base: PathBuf, track_info: LocalTrack, ) -> anyhow::Result)>> { let source_path = path_base.join(track_info.path); let file = File::open(&source_path)?; let mut reader = EbmlReader::new(BufReader::new(file)); let index = get_seek_index(&source_path)?; let index = index .get(&(track_info.track as u64)) .ok_or(anyhow!("track missing"))?; let mut out = Vec::new(); for b in &index.blocks { reader.seek(b.source_off, MatroskaTag::Cluster(Master::Start))?; let (duration, block) = read_group(&mut reader)?; out.push((b.pts, duration, block.data)) } Ok(out) } pub fn read_group(segment: &mut EbmlReader) -> anyhow::Result<(u64, Block)> { let (mut dur, mut block) = (None, None); loop { let item = segment.next().ok_or(anyhow!("eof"))??; match item { MatroskaTag::Void(_) => (), MatroskaTag::Crc32(_) => (), MatroskaTag::Cluster(_) => (), MatroskaTag::Timestamp(_) => (), MatroskaTag::SimpleBlock(_buf) => { // bail!("unexpected simpleblock, where a group was expected") } MatroskaTag::BlockGroup(Master::Start) => (), MatroskaTag::BlockGroup(Master::End) => return Ok((dur.unwrap(), block.unwrap())), MatroskaTag::BlockDuration(duration) => dur = Some(duration), MatroskaTag::Block(buf) => block = Some(Block::parse(&buf)?), MatroskaTag::Cues(_) => bail!("reached cues, this is the end"), MatroskaTag::Segment(Master::End) => info!("extractor reached segment end"), _ => debug!("(rs) tag ignored: {item:?}"), } } } // fn import_seek_index_segment( // segment: &mut Unflatten, // seek_index: &mut BTreeMap, // ) -> Result<()> { // while let Some(Ok(Unflat { children, item, .. })) = segment.n() { // match item { // MatroskaTag::SeekHead(_) => {} // MatroskaTag::Info(_) => {} // MatroskaTag::Tags(_) => {} // MatroskaTag::Cues(_) => {} // MatroskaTag::Chapters(_) => {} // MatroskaTag::Tracks(_) => {} // MatroskaTag::Void(_) => {} // MatroskaTag::Cluster(_) => { // let mut children = children.unwrap(); // let mut pts = 0; // let mut position = children.position(); // loop { // if let Some(Ok(Unflat { children, item, .. })) = children.n() { // match item { // MatroskaTag::Timestamp(ts) => pts = ts, // MatroskaTag::BlockGroup(_) => { // trace!("group"); // let mut children = children.unwrap(); // // let position = children.position(); //? TODO where should this point to? cluster or block? // probably block // while let Some(Ok(Unflat { // children: _, // item, // position, // })) = children.n() // { // match item { // MatroskaTag::Block(ref buf) => { // let block = Block::parse(buf)?; // debug!( // "block: track={} tso={}", // block.track, block.timestamp_off // ); // seek_index_add(seek_index, &block, position, pts); // } // _ => trace!("{item:?}"), // } // } // } // MatroskaTag::SimpleBlock(buf) => { // let block = Block::parse(&buf)?; // trace!( // "simple block: track={} tso={}", // block.track, // block.timestamp_off // ); // trace!("{pts} {}", block.timestamp_off); // seek_index_add(seek_index, &block, position, pts); // } // _ => trace!("(rsc) tag ignored: {item:?}"), // } // } else { // break; // } // position = children.position(); // } // } // _ => debug!("(rs) tag ignored: {item:?}"), // }; // } // Ok(()) // }