From 308aef7aa13712b78e1ee68d2bc58ad072be7339 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 4 Nov 2026 04:49:00 +0100 Subject: [PATCH] mov: support version 1 of common boxes (with 64-bit time and duration) --- nihav-commonfmt/src/demuxers/mov/mod.rs | 26 +++++++---- nihav-commonfmt/src/demuxers/mov/pktread.rs | 4 +- nihav-commonfmt/src/demuxers/mov/track.rs | 50 ++++++++++++++------- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/nihav-commonfmt/src/demuxers/mov/mod.rs b/nihav-commonfmt/src/demuxers/mov/mod.rs index 7742be9..826746a 100644 --- a/nihav-commonfmt/src/demuxers/mov/mod.rs +++ b/nihav-commonfmt/src/demuxers/mov/mod.rs @@ -252,16 +252,26 @@ const MOOV_CHUNK_HANDLERS: &[RootChunkHandler] = &[ fn read_mvhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult { const KNOWN_MVHD_SIZE: u64 = 100; + const KNOWN_MVHD_SIZE1: u64 = 112; let br = &mut dmx.src; - validate!(size >= KNOWN_MVHD_SIZE); let version = br.read_byte()?; - validate!(version == 0 || version == 0xFF); + validate!(matches!(version, 0 | 1 | 0xFF)); + if version != 1 { + validate!(size >= KNOWN_MVHD_SIZE); + } else { + validate!(size >= KNOWN_MVHD_SIZE1); + } dmx.ver_m1 = version == 0xFF; let _flags = br.read_u24be()?; - let _ctime = br.read_u32be()?; - let _mtime = br.read_u32be()?; + if version != 1 { + let _ctime = br.read_u32be()?; + let _mtime = br.read_u32be()?; + } else { + let _ctime = br.read_u64be()?; + let _mtime = br.read_u64be()?; + } let tscale = br.read_u32be()?; - let duration = br.read_u32be()?; + let duration = if version != 1 { u64::from(br.read_u32be()?) } else { br.read_u64be()? }; let _pref_rate = br.read_u32be()?; let _pref_volume = br.read_u16be()?; br.read_skip(10)?; @@ -276,7 +286,7 @@ fn read_mvhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> De dmx.duration = duration; dmx.tb_den = tscale; - Ok(KNOWN_MVHD_SIZE) + Ok(if version != 1 { KNOWN_MVHD_SIZE } else { KNOWN_MVHD_SIZE1 }) } fn read_cmov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult { @@ -417,7 +427,7 @@ struct MOVDemuxer<'a> { tracks: Vec, cur_track: usize, tb_den: u32, - duration: u32, + duration: u64, pal: Option>, ver_m1: bool, file_size: u64, @@ -696,7 +706,7 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { } fn get_duration(&self) -> u64 { if self.tb_den != 0 { - u64::from(self.duration) * 1000 / u64::from(self.tb_den) + self.duration * 1000 / u64::from(self.tb_den) } else { 0 } diff --git a/nihav-commonfmt/src/demuxers/mov/pktread.rs b/nihav-commonfmt/src/demuxers/mov/pktread.rs index 68c887a..cd534a0 100644 --- a/nihav-commonfmt/src/demuxers/mov/pktread.rs +++ b/nihav-commonfmt/src/demuxers/mov/pktread.rs @@ -131,7 +131,7 @@ pub struct QTPacketDemuxer { pub cur_ts: Option, pub samples_left: usize, pub last_offset: u64, - pub duration: u32, + pub duration: u64, pub channels: usize, pub bits: usize, pub bsize: usize, @@ -447,7 +447,7 @@ impl QTPacketDemuxer { }, PacketMode::AudioCBR | PacketMode::AudioVBR => { if self.chunk_offsets.len() == self.chunk_sizes.len() && self.duration != 0 { - let new_sample = (self.chunk_sizes.len() as u64 * tgt_pts / u64::from(self.duration)) as usize; + let new_sample = (self.chunk_sizes.len() as u64 * tgt_pts / self.duration) as usize; self.cur_sample = new_sample; self.cur_chunk = self.cur_sample; } else { diff --git a/nihav-commonfmt/src/demuxers/mov/track.rs b/nihav-commonfmt/src/demuxers/mov/track.rs index 7d7a15d..7e7672e 100644 --- a/nihav-commonfmt/src/demuxers/mov/track.rs +++ b/nihav-commonfmt/src/demuxers/mov/track.rs @@ -53,15 +53,25 @@ const TRAK_CHUNK_HANDLERS: &[TrackChunkHandler] = &[ fn read_tkhd(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult { const KNOWN_TKHD_SIZE: u64 = 84; - validate!(size >= KNOWN_TKHD_SIZE); + const KNOWN_TKHD_SIZE1: u64 = 96; let version = br.read_byte()?; - validate!(version == 0); + validate!(version == 0 || version == 1); + if version != 1 { + validate!(size >= KNOWN_TKHD_SIZE); + } else { + validate!(size >= KNOWN_TKHD_SIZE1); + } let _flags = br.read_u24be()?; - let _ctime = br.read_u32be()?; - let _mtime = br.read_u32be()?; + if version != 1 { + let _ctime = br.read_u32be()?; + let _mtime = br.read_u32be()?; + } else { + let _ctime = br.read_u64be()?; + let _mtime = br.read_u64be()?; + } let track_id = br.read_u32be()?; br.read_skip(4)?; - let duration = br.read_u32be()?; + let duration = if version == 0 { u64::from(br.read_u32be()?) } else { br.read_u64be()? }; br.read_skip(8)?; let _layer = br.read_u16be()?; let _alt_group = br.read_u16be()?; @@ -76,7 +86,7 @@ fn read_tkhd(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult track.pkt_demux.duration = duration; track.tkhd_found = true; - Ok(KNOWN_TKHD_SIZE) + Ok(if version == 0 { KNOWN_TKHD_SIZE } else { KNOWN_TKHD_SIZE1 }) } fn read_mdia(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult { @@ -94,21 +104,31 @@ const MDIA_CHUNK_HANDLERS: &[TrackChunkHandler] = &[ fn read_mdhd(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult { const KNOWN_MDHD_SIZE: u64 = 24; - validate!(size >= KNOWN_MDHD_SIZE); + const KNOWN_MDHD_SIZE1: u64 = 36; let version = br.read_byte()?; - validate!(version == 0); + validate!(version == 0 || version == 1); + if version != 1 { + validate!(size >= KNOWN_MDHD_SIZE); + } else { + validate!(size >= KNOWN_MDHD_SIZE1); + } let flags = br.read_u24be()?; validate!(flags == 0); - let _ctime = br.read_u32be()?; - let _mtime = br.read_u32be()?; + if version != 1 { + let _ctime = br.read_u32be()?; + let _mtime = br.read_u32be()?; + } else { + let _ctime = br.read_u64be()?; + let _mtime = br.read_u64be()?; + } track.tb_den = br.read_u32be()?; validate!(track.tb_den != 0); track.pkt_demux.tb_den = track.tb_den; - track.pkt_demux.duration = br.read_u32be()?; + track.pkt_demux.duration = if version == 0 { u64::from(br.read_u32be()?) } else { br.read_u64be()? }; let _language = br.read_u16be()?; let _quality = br.read_u16be()?; - Ok(KNOWN_MDHD_SIZE) + Ok(if version == 0 { KNOWN_MDHD_SIZE } else { KNOWN_MDHD_SIZE1 }) } fn read_hdlr(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult { @@ -163,7 +183,7 @@ fn read_udta_mdia(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerR let info = ref_info.get_properties(); let cinfo = NACodecInfo::new(name, info, Some(edata)); let strm_id = ref_strm.get_id(); - track.streams[0] = NAStream::new(track.stream_type, strm_id, cinfo, track.tb_num, track.tb_den, u64::from(track.pkt_demux.duration)); + track.streams[0] = NAStream::new(track.stream_type, strm_id, cinfo, track.tb_num, track.tb_den, track.pkt_demux.duration); return Ok(size); } } @@ -614,7 +634,7 @@ fn read_stsd(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult track.pkt_demux.tb_den = track.tb_den; validate!(br.tell() <= end_pos); br.seek(SeekFrom::Start(end_pos))?; - track.streams.push(NAStream::new(track.stream_type, track.track_no | ((desc_no as u32) << 16), codec_info, track.tb_num, track.tb_den, u64::from(track.pkt_demux.duration))); + track.streams.push(NAStream::new(track.stream_type, track.track_no | ((desc_no as u32) << 16), codec_info, track.tb_num, track.tb_den, track.pkt_demux.duration)); } let read_size = br.tell() - start_pos; track.stsd_found = true; @@ -1050,7 +1070,7 @@ impl Track { self.tb_den = tb_den; self.pkt_demux.tb_num = tb_num; self.pkt_demux.tb_den = tb_den; - self.pkt_demux.duration /= self.tb_div; + self.pkt_demux.duration /= u64::from(self.tb_div); } } } -- 2.47.3