From: Kostya Shishkov Date: Sat, 31 Oct 2026 11:13:34 +0000 (+0100) Subject: mkv: support Block element X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=7ce77657b0d8e036ea9ee0d02ac56ff83839a6bb;p=nihav.git mkv: support Block element --- diff --git a/nihav-commonfmt/src/demuxers/mkv/mod.rs b/nihav-commonfmt/src/demuxers/mkv/mod.rs index 1b893d4..f9df82a 100644 --- a/nihav-commonfmt/src/demuxers/mkv/mod.rs +++ b/nihav-commonfmt/src/demuxers/mkv/mod.rs @@ -101,6 +101,14 @@ impl std::convert::From for MSeekInfo { } } +#[allow(dead_code)] +struct BlockHeader { + full_ts: u64, + keyframe: bool, + invisible: bool, + lacing: u8, +} + struct MatroskaDemuxer<'a> { src: &'a mut dyn ByteIO, segments: Vec, @@ -197,7 +205,54 @@ impl<'a> DemuxCore<'a> for MatroskaDemuxer<'a> { } self.clu_ts = Some(ts); }, - 0xA0 => return Err(DemuxerError::NotImplemented), // BlockGroup + 0xA0 => { + validate!(self.clu_ts.is_some()); + + let blk_end = end; + let mut has_block = false; + while self.src.tell() < blk_end { + let off = self.src.tell(); + let id = self.src.read_ebml_id()?; + let size = self.src.read_vint()?; + let end = self.src.tell() + size; + if self.print_chunks { + print_entry(3, off, id, size); + } + validate!(end <= blk_end); + if id == 0xA1 { + validate!(!has_block); + has_block = true; + + let trk_id = self.src.read_vint()?; + let timestamp = self.src.read_u16be()?; + let flags = self.src.read_byte()?; + let mut full_ts = self.clu_ts.unwrap() + u64::from(timestamp); + if (timestamp & 0x8000) != 0 { + full_ts = full_ts.wrapping_sub(0x10000); + } + validate!((flags & 0xF0) == 0); + let invisible = (flags & 0x08) != 0; + let lacing = (flags >> 1) & 3; + if self.print_chunks { + println!(" block - track {trk_id} ts {full_ts} ({timestamp}) {}{}", if invisible { " invisible" } else {""}, if lacing != 0 { " laced" } else {""}); + } + if trk_id > U32_MAX { return Err(DemuxerError::NotImplemented); } + let trk_id = trk_id as u32; + validate!(self.src.tell() < end); + let tfind = self.segments[self.cur_seg].tracks.iter().find(|x| x.id == trk_id); + if let (Some(trk), Some(stream)) = (tfind, strmgr.get_stream_by_id(trk_id)) { + let blk_hdr = BlockHeader { full_ts, keyframe: false, lacing, invisible }; + let first_pkt = Self::read_block(trk, stream, self.src, &blk_hdr, end, &mut self.queue)?; + self.queue.push_front(first_pkt); + } + } + validate!(self.src.tell() <= end); + self.src.seek(SeekFrom::Start(end))?; + } + if let Some(pkt) = self.queue.pop_front() { + return Ok(pkt); + } + }, 0xA3 => { validate!(self.clu_ts.is_some()); let trk_id = self.src.read_vint()?; @@ -220,70 +275,8 @@ impl<'a> DemuxCore<'a> for MatroskaDemuxer<'a> { validate!(self.src.tell() < end); let tfind = self.segments[self.cur_seg].tracks.iter().find(|x| x.id == trk_id); if let (Some(trk), Some(stream)) = (tfind, strmgr.get_stream_by_id(trk_id)) { - if lacing != 0 { - validate!(trk.lacing); - let nframes = usize::from(self.src.read_byte()?) + 1; - validate!(nframes > 1 && self.src.tell() < end); - let mut sizes = [0; 256]; - let mut tot_size = 0; - match lacing { - 1 => { // Xiph lacing - for dsize in sizes[..nframes - 1].iter_mut() { - let mut b = self.src.read_byte()?; - let mut size = usize::from(b); - while b == 255 { - b = self.src.read_byte()?; - size += usize::from(b); - } - *dsize = size; - tot_size += size; - } - validate!(self.src.tell() + (tot_size as u64) < end); - sizes[nframes - 1] = (end - self.src.tell()) as usize - tot_size; - }, - 3 => { // EBML lacing - let first_size = self.src.read_vint()?; - let mut prev = first_size as i64; - let fsize = first_size as usize; - sizes[0] = fsize; - tot_size += fsize; - for dsize in sizes[..nframes - 1].iter_mut().skip(1) { - let diff = self.src.read_vint_s()?; - let size = prev + diff; - validate!((1..=(U32_MAX as i64)).contains(&size)); - prev = size; - let size = size as usize; - *dsize = size; - tot_size += size; - } - validate!(self.src.tell() + (tot_size as u64) < end); - sizes[nframes - 1] = (end - self.src.tell()) as usize - tot_size; - }, - 2 => { // fixed-size lacing - let rest_size = (end - self.src.tell()) as usize; - validate!((rest_size > 0) && (rest_size % nframes == 0)); - let pkt_size = rest_size / nframes; - for el in sizes.iter_mut().take(nframes) { - *el = pkt_size; - } - }, - _ => unreachable!() - } - let mut ts = NATimeInfo::new(Some(full_ts), None, None, stream.tb_num, stream.tb_den); - let mut keyframe = keyframe; - for &pkt_size in sizes[..nframes].iter() { - let pkt = trk.read_packet(self.src, stream.clone(), ts, keyframe, pkt_size)?; - keyframe = false; - ts.pts = None; - self.queue.push_back(pkt); - } - validate!(self.src.tell() == end); - return Ok(self.queue.pop_front().unwrap()); - } else { - let pkt_size = (end - self.src.tell()) as usize; - let ts = NATimeInfo::new(Some(full_ts), None, None, stream.tb_num, stream.tb_den); - return trk.read_packet(self.src, stream, ts, keyframe, pkt_size); - } + let blk_hdr = BlockHeader { full_ts, keyframe, lacing, invisible }; + return Self::read_block(trk, stream, self.src, &blk_hdr, end, &mut self.queue); } }, _ => {}, @@ -439,6 +432,72 @@ impl<'a> MatroskaDemuxer<'a> { queue: VecDeque::new(), } } + fn read_block(trk: &Track, stream: NAStreamRef, br: &mut dyn ByteIO, blk_hdr: &BlockHeader, end: u64, queue: &mut VecDeque) -> DemuxerResult { + if blk_hdr.lacing != 0 { + validate!(trk.lacing); + let nframes = usize::from(br.read_byte()?) + 1; + validate!(nframes > 1 && br.tell() < end); + let mut sizes = [0; 256]; + let mut tot_size = 0; + match blk_hdr.lacing { + 1 => { // Xiph lacing + for dsize in sizes[..nframes - 1].iter_mut() { + let mut b = br.read_byte()?; + let mut size = usize::from(b); + while b == 255 { + b = br.read_byte()?; + size += usize::from(b); + } + *dsize = size; + tot_size += size; + } + validate!(br.tell() + (tot_size as u64) < end); + sizes[nframes - 1] = (end - br.tell()) as usize - tot_size; + }, + 3 => { // EBML lacing + let first_size = br.read_vint()?; + let mut prev = first_size as i64; + let fsize = first_size as usize; + sizes[0] = fsize; + tot_size += fsize; + for dsize in sizes[..nframes - 1].iter_mut().skip(1) { + let diff = br.read_vint_s()?; + let size = prev + diff; + validate!((1..=(U32_MAX as i64)).contains(&size)); + prev = size; + let size = size as usize; + *dsize = size; + tot_size += size; + } + validate!(br.tell() + (tot_size as u64) < end); + sizes[nframes - 1] = (end - br.tell()) as usize - tot_size; + }, + 2 => { // fixed-size lacing + let rest_size = (end - br.tell()) as usize; + validate!((rest_size > 0) && (rest_size % nframes == 0)); + let pkt_size = rest_size / nframes; + for el in sizes.iter_mut().take(nframes) { + *el = pkt_size; + } + }, + _ => unreachable!() + } + let mut ts = NATimeInfo::new(Some(blk_hdr.full_ts), None, None, stream.tb_num, stream.tb_den); + let mut keyframe = blk_hdr.keyframe; + for &pkt_size in sizes[..nframes].iter() { + let pkt = trk.read_packet(br, stream.clone(), ts, keyframe, pkt_size)?; + keyframe = false; + ts.pts = None; + queue.push_back(pkt); + } + validate!(br.tell() == end); + Ok(queue.pop_front().unwrap()) + } else { + let pkt_size = (end - br.tell()) as usize; + let ts = NATimeInfo::new(Some(blk_hdr.full_ts), None, None, stream.tb_num, stream.tb_den); + trk.read_packet(br, stream, ts, blk_hdr.keyframe, pkt_size) + } + } } pub struct MatroskaDemuxerCreator { }