From fb3a07fc4109970498d3463c569836b795af8169 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Thu, 26 Feb 2026 18:42:49 +0100 Subject: [PATCH] fix some PTS/DTS confusion --- nihav-codec-support/src/test/dec_video.rs | 4 +- nihav-commonfmt/src/demuxers/mov.rs | 48 +++++++++++------------ nihav-core/src/reorder.rs | 26 ++++++------ nihav-flash/src/demuxers/flv.rs | 4 +- nihav-flash/src/muxers/flv.rs | 7 ++-- nihav-itu/src/codecs/h264/decoder_mt.rs | 6 +-- nihav-itu/src/codecs/h264/decoder_st.rs | 10 ++--- 7 files changed, 53 insertions(+), 52 deletions(-) diff --git a/nihav-codec-support/src/test/dec_video.rs b/nihav-codec-support/src/test/dec_video.rs index 5fb46fb..8eb3ac2 100644 --- a/nihav-codec-support/src/test/dec_video.rs +++ b/nihav-codec-support/src/test/dec_video.rs @@ -467,10 +467,10 @@ const THREADS: usize = 3; fn check_frame(frm: NAFrameRef, test: &ExpectedTestResult, glbl_md5: &mut MD5, frameiter: &mut Option>, last_ts: &mut Option) -> bool { let frm_pts = frm.get_pts(); let frm_dts = frm.get_dts(); - if let (Some(lts), Some(cts)) = (*last_ts, frm_dts) { + if let (Some(lts), Some(cts)) = (*last_ts, frm_pts) { assert!(lts < cts); } - *last_ts = frm_dts; + *last_ts = frm_pts; match test { ExpectedTestResult::Decodes => {}, ExpectedTestResult::MD5(_) => { frame_checksum(glbl_md5, frm); }, diff --git a/nihav-commonfmt/src/demuxers/mov.rs b/nihav-commonfmt/src/demuxers/mov.rs index b587276..6c9d040 100644 --- a/nihav-commonfmt/src/demuxers/mov.rs +++ b/nihav-commonfmt/src/demuxers/mov.rs @@ -1425,22 +1425,22 @@ impl Track { self.cur_sample = self.chunk_sizes.len(); } fn get_next_chunk(&mut self) -> Option<(NATimeInfo, u64, usize)> { - let pts_val = self.timesearch.map_time(self.cur_sample as u32, &self.time_to_sample); - let dts = if let Some(dts_corr) = self.ctts_map.map(self.cur_sample as u64) { - let dts = match self.ctts_version { - 0 => pts_val.wrapping_add(u64::from(dts_corr)), - 1 => pts_val.wrapping_add(i64::from(dts_corr as i32) as u64), + let dts_val = self.timesearch.map_time(self.cur_sample as u32, &self.time_to_sample); + let pts = if let Some(dts_corr) = self.ctts_map.map(self.cur_sample as u64) { + let pts = match self.ctts_version { + 0 => dts_val.wrapping_add(u64::from(dts_corr)), + 1 => dts_val.wrapping_add(i64::from(dts_corr as i32) as u64), _ => unimplemented!(), }; - if (dts as i64) < 0 { + if (pts as i64) < 0 { None } else { - Some(dts) + Some(pts) } } else { - Some(pts_val) + Some(dts_val) }; - let mut pts = NATimeInfo::new(Some(pts_val), dts, None, self.tb_num, self.tb_den); + let mut ts = NATimeInfo::new(pts, Some(dts_val), None, self.tb_num, self.tb_den); if self.chunk_offsets.len() == self.chunk_sizes.len() { // simple one-to-one mapping if self.cur_sample >= self.chunk_sizes.len() { return None; @@ -1448,7 +1448,7 @@ impl Track { let offset = self.chunk_offsets[self.cur_sample]; let size = self.chunk_sizes[self.cur_sample] as usize; self.cur_sample += 1; - Some((pts, offset, size)) + Some((ts, offset, size)) } else { if self.samples_left == 0 { if self.cur_chunk >= self.chunk_offsets.len() { @@ -1472,8 +1472,8 @@ impl Track { } else if self.frame_samples != 0 && self.bsize != 0 { let nblocks = size / self.bsize; if self.raw_audio { - pts.pts = Some(self.raw_apos); - pts.duration = Some(nblocks as u64); + ts.pts = Some(self.raw_apos); + ts.duration = Some(nblocks as u64); self.raw_apos += nblocks as u64; } if nblocks > 0 { @@ -1499,7 +1499,7 @@ impl Track { self.cur_sample += self.samples_left; self.samples_left = 0; } - return Some((pts, offset + add_off, dsize)); + return Some((ts, offset + add_off, dsize)); } else { self.last_offset -= size as u64; let samples = self.samples_left.min(BLOCK_SAMPLES); @@ -1507,11 +1507,11 @@ impl Track { self.cur_sample += samples; self.samples_left -= samples; self.last_offset += cur_size as u64; - return Some((pts, offset, cur_size)); + return Some((ts, offset, cur_size)); } } self.cur_sample += 1; - Some((pts, offset, size)) + Some((ts, offset, size)) } } fn get_size(&self, sample_no: usize) -> usize { @@ -1720,10 +1720,10 @@ impl Track { } } -fn process_packet(src: &mut dyn ByteIO, strmgr: &StreamManager, track: &mut Track, pts: NATimeInfo, offset: u64, size: usize, first: bool) -> DemuxerResult { - if let Some(cpts) = pts.get_pts() { - let ts = NATimeInfo::rescale_ts(cpts, pts.tb_num, pts.tb_den, 1, 1000); - track.cur_ts = Some(ts); +fn process_packet(src: &mut dyn ByteIO, strmgr: &StreamManager, track: &mut Track, ts: NATimeInfo, offset: u64, size: usize, first: bool) -> DemuxerResult { + if let Some(cpts) = ts.get_pts() { + let cts = NATimeInfo::rescale_ts(cpts, ts.tb_num, ts.tb_den, 1, 1000); + track.cur_ts = Some(cts); } else { track.cur_ts = None; } @@ -1731,7 +1731,7 @@ fn process_packet(src: &mut dyn ByteIO, strmgr: &StreamManager, track: &mut Trac if stream.is_none() { return Err(DemuxerError::InvalidData); } let stream = stream.unwrap(); src.seek(SeekFrom::Start(offset))?; - let mut pkt = src.read_packet(stream, pts, false, size)?; + let mut pkt = src.read_packet(stream, ts, false, size)?; if let Some(ref pal) = track.pal { let side_data = NASideData::Palette(first, pal.clone()); pkt.add_side_data(side_data); @@ -1893,9 +1893,9 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { if let Some(ts) = track.cur_ts { if ts == min_ts { let first = track.cur_sample == 0; - if let Some((pts, offset, size)) = track.get_next_chunk() { + if let Some((cts, offset, size)) = track.get_next_chunk() { self.cur_track = trk_no + 1; - return process_packet(self.src, strmgr, track, pts, offset, size, first); + return process_packet(self.src, strmgr, track, cts, offset, size, first); } } } @@ -1912,8 +1912,8 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { continue; } let first = track.cur_sample == 0; - if let Some((pts, offset, size)) = track.get_next_chunk() { - return process_packet(self.src, strmgr, track, pts, offset, size, first); + if let Some((cts, offset, size)) = track.get_next_chunk() { + return process_packet(self.src, strmgr, track, cts, offset, size, first); } } Err(DemuxerError::EOF) diff --git a/nihav-core/src/reorder.rs b/nihav-core/src/reorder.rs index 9337b9a..119cd21 100644 --- a/nihav-core/src/reorder.rs +++ b/nihav-core/src/reorder.rs @@ -107,7 +107,7 @@ impl FrameReorderer for IPBReorderer { /// Frame reorderer for codecs with complex I/P/B frame structure like ITU H.26x. #[derive(Default)] pub struct ComplexReorderer { - last_ref_dts: Option, + last_ref_pts: Option, ready_idx: usize, frames: Vec, } @@ -124,14 +124,14 @@ impl FrameReorderer for ComplexReorderer { } let is_ref = fref.frame_type == FrameType::I || fref.frame_type == FrameType::P; if !is_ref { - if self.frames.is_empty() || fref.get_dts().is_none() { + if self.frames.is_empty() || fref.get_pts().is_none() { self.frames.push(fref); - } else if let Some(new_dts) = fref.get_dts() { + } else if let Some(new_pts) = fref.get_pts() { let mut idx = 0; for (i, frm) in self.frames.iter().enumerate() { idx = i; - if let Some(dts) = frm.get_dts() { - if dts > new_dts { + if let Some(pts) = frm.get_pts() { + if pts > new_pts { break; } } @@ -140,11 +140,11 @@ impl FrameReorderer for ComplexReorderer { } } else { for (i, frm) in self.frames.iter().enumerate() { - if frm.get_dts() == self.last_ref_dts { + if frm.get_pts() == self.last_ref_pts { self.ready_idx = i + 1; } } - self.last_ref_dts = fref.get_dts(); + self.last_ref_pts = fref.get_pts(); self.frames.push(fref); } true @@ -158,7 +158,7 @@ impl FrameReorderer for ComplexReorderer { } } fn flush(&mut self) { - self.last_ref_dts = None; + self.last_ref_pts = None; self.ready_idx = 0; self.frames.clear(); } @@ -198,10 +198,10 @@ impl MTFrameReorderer { /// Puts a newly decoded frame into the internal queue. pub fn add_frame(&mut self, frm: NAFrameRef, id: u32) { //let ftype = frm.get_frame_type(); - let frm_id = if let Some(ts) = frm.ts.dts { ts } else { u64::from(id) }; + let frm_id = if let Some(ts) = frm.ts.pts { ts } else { u64::from(id) }; let mut idx = 0; for (_, frm) in self.frames.iter() { - let cur_id = if let Some(ts) = frm.ts.dts { ts } else { frm.id as u64 }; + let cur_id = if let Some(ts) = frm.ts.pts { ts } else { frm.id as u64 }; if frm_id < cur_id { break; } @@ -221,7 +221,7 @@ impl MTFrameReorderer { fn get_first_frame(&mut self) -> Option { let (id, frm) = self.frames.pop_front().unwrap(); self.drop_frame(id); - self.last_ts = frm.get_dts(); + self.last_ts = frm.get_pts(); Some(frm) } /// Gets the next frame to be displayed (or `None` if that is not possible). @@ -230,9 +230,9 @@ impl MTFrameReorderer { pub fn get_frame(&mut self) -> Option { // check if we have consequent timestamps that we can output if !self.frames.is_empty() { - if let Some(dts) = self.frames[0].1.get_dts() { + if let Some(pts) = self.frames[0].1.get_pts() { let last_ts = self.last_ts.unwrap_or(0); - if self.last_ts.is_none() || (dts == last_ts + 1) { + if self.last_ts.is_none() || (pts == last_ts + 1) { self.output_to = None; return self.get_first_frame(); } diff --git a/nihav-flash/src/demuxers/flv.rs b/nihav-flash/src/demuxers/flv.rs index 75680a6..c3a9a1d 100644 --- a/nihav-flash/src/demuxers/flv.rs +++ b/nihav-flash/src/demuxers/flv.rs @@ -351,8 +351,8 @@ impl<'a> FLVDemuxer<'a> { if data_size > 0 { let stream = strmgr.get_stream(self.vstream).unwrap(); - let pts = (u64::from(ext_time) << 24) | u64::from(time); - let dts = ((pts as i64) + i64::from(cts)).max(0) as u64; + let dts = (u64::from(ext_time) << 24) | u64::from(time); + let pts = ((dts as i64) + i64::from(cts)).max(0) as u64; let ts = stream.make_ts(Some(pts), Some(dts), None); self.vpkts.push(self.src.read_packet(stream, ts, ftype == FrameType::I, data_size)?); } diff --git a/nihav-flash/src/muxers/flv.rs b/nihav-flash/src/muxers/flv.rs index 8efaae4..d130ab8 100644 --- a/nihav-flash/src/muxers/flv.rs +++ b/nihav-flash/src/muxers/flv.rs @@ -227,7 +227,8 @@ impl<'a> MuxCore<'a> for FLVMuxer<'a> { } fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> { let stream = pkt.get_stream(); - let pts = pkt.get_pts().unwrap_or(0); + let real_pts = pkt.get_pts().unwrap_or(0); + let pts = pkt.get_dts().unwrap_or(real_pts); let ms = NATimeInfo::rescale_ts(pts, pkt.ts.tb_num, pkt.ts.tb_den, 1, 1000) as u32; self.time = self.time.max(ms); match stream.get_media_type() { @@ -241,8 +242,8 @@ impl<'a> MuxCore<'a> for FLVMuxer<'a> { }, AVC_ID => { self.bw.write_byte(1)?; - let cms = NATimeInfo::rescale_ts(pkt.get_pts().unwrap_or(pts), pkt.ts.tb_num, pkt.ts.tb_den, 1, 1000) as u32; - let cts = cms.wrapping_sub(ms) << 8 >> 8; + let cms = NATimeInfo::rescale_ts(real_pts, pkt.ts.tb_num, pkt.ts.tb_den, 1, 1000) as u32; + let cts = ms.wrapping_sub(cms) << 8 >> 8; self.bw.write_u24be(cts)?; }, _ => {}, diff --git a/nihav-itu/src/codecs/h264/decoder_mt.rs b/nihav-itu/src/codecs/h264/decoder_mt.rs index 1c2cb52..032b281 100644 --- a/nihav-itu/src/codecs/h264/decoder_mt.rs +++ b/nihav-itu/src/codecs/h264/decoder_mt.rs @@ -934,10 +934,10 @@ impl NADecoderMT for H264MTDecoder { Ok(cpic) => { let bufinfo = NABufferType::Video(cpic.buf.clone()); let ftype = cpic.pic_type; - let dts = Some(u64::from(cpic.full_id)); + let pts = Some(u64::from(cpic.full_id)); let mut frm = NAFrame::new(cpic.time, ftype, cpic.is_idr, self.info.clone(), bufinfo); - if let (Some(mydts), None) = (dts, frm.get_dts()) { - frm.set_dts(Some(mydts)); + if let (Some(mypts), None) = (pts, frm.get_pts()) { + frm.set_pts(Some(mypts)); } frm.set_id(cpic.user_id as i64); (Ok(frm.into_ref()), cpic.user_id) diff --git a/nihav-itu/src/codecs/h264/decoder_st.rs b/nihav-itu/src/codecs/h264/decoder_st.rs index dd57832..447abcf 100644 --- a/nihav-itu/src/codecs/h264/decoder_st.rs +++ b/nihav-itu/src/codecs/h264/decoder_st.rs @@ -881,7 +881,7 @@ impl NADecoder for H264Decoder { unimplemented!(); } - let (bufinfo, ftype, dts) = if self.has_pic && self.cur_pic.is_some() { + let (bufinfo, ftype, pts) = if self.has_pic && self.cur_pic.is_some() { let mut npic = None; std::mem::swap(&mut self.cur_pic, &mut npic); let cpic = npic.unwrap(); @@ -899,11 +899,11 @@ impl NADecoder for H264Decoder { let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); frm.set_keyframe(ftype == FrameType::I); - if let (Some(mydts), None) = (dts, frm.get_dts()) { - frm.set_dts(Some(mydts)); + if let (Some(mypts), None) = (pts, frm.get_pts()) { + frm.set_pts(Some(mypts)); } - if let Some(dts) = dts { - frm.set_id(dts as i64); + if let Some(pts) = pts { + frm.set_id(pts as i64); } frm.set_frame_type(ftype); Ok(frm.into_ref()) -- 2.39.5