From 23990de768aa53539c4c4d25ffa9834f8a108127 Mon Sep 17 00:00:00 2001 From: Matt Jackson <1085847+MattJackson@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:08:34 +0000 Subject: [PATCH] Fix truncated rips on dual-layer discs, propagate read errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use UDF file_extents() to read actual allocation descriptors instead of assuming m2ts files are contiguous from file_start_lba. Dual-layer UHD discs split large files across 70+ extents (~1 GB each) — the old code created one extent from packet count which only covered the first chunk, causing silent truncation at ~37%. Also changed fill_extents() to return io::Result so read errors propagate instead of being silently treated as EOF. --- src/disc/bluray.rs | 21 +++++++++++---------- src/mux/disc.rs | 28 +++++++++++----------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/disc/bluray.rs b/src/disc/bluray.rs index a0edc02..728ba57 100644 --- a/src/disc/bluray.rs +++ b/src/disc/bluray.rs @@ -66,17 +66,18 @@ impl Disc { pkt_count = clip_info.source_packet_count; total_size += pkt_count as u64 * 192; - // Get m2ts file start LBA and compute extent from packet count. - // BD-ROM m2ts files are contiguous on disc (mastering requirement). + // Get m2ts file extents from UDF allocation descriptors. + // Dual-layer discs split files across layers — UDF knows the real layout. let m2ts_path = format!("/BDMV/STREAM/{}.m2ts", play_item.clip_id); - let file_lba = udf_fs.file_start_lba(reader, &m2ts_path).unwrap_or(0); - let total_bytes = pkt_count as u64 * 192; - let total_sectors = total_bytes.div_ceil(2048) as u32; - if total_sectors > 0 && file_lba > 0 { - extents.push(Extent { - start_lba: file_lba, - sector_count: total_sectors, - }); + if let Ok(file_exts) = udf_fs.file_extents(reader, &m2ts_path) { + for (lba, sectors) in file_exts { + if sectors > 0 && lba > 0 { + extents.push(Extent { + start_lba: lba, + sector_count: sectors, + }); + } + } } } } diff --git a/src/mux/disc.rs b/src/mux/disc.rs index c374d88..968f99a 100644 --- a/src/mux/disc.rs +++ b/src/mux/disc.rs @@ -117,9 +117,9 @@ impl DiscStream { self.disc.as_ref() } - fn fill_extents(&mut self) -> bool { + fn fill_extents(&mut self) -> io::Result { if self.current_extent >= self.extents.len() { - return false; + return Ok(false); } let ext_start = self.extents[self.current_extent].start_lba; let ext_sectors = self.extents[self.current_extent].sector_count; @@ -137,21 +137,15 @@ impl DiscStream { let bytes = sectors as usize * 2048; self.read_buf.resize(bytes, 0); - match self - .reader - .read_sectors(lba, sectors, &mut self.read_buf[..bytes]) - { - Ok(_) => { - self.buf_valid = bytes; - self.current_offset += sectors as u32; - if self.current_offset >= ext_sectors { - self.current_extent += 1; - self.current_offset = 0; - } - true - } - Err(_) => false, + self.reader + .read_sectors(lba, sectors, &mut self.read_buf[..bytes])?; + self.buf_valid = bytes; + self.current_offset += sectors as u32; + if self.current_offset >= ext_sectors { + self.current_extent += 1; + self.current_offset = 0; } + Ok(true) } } @@ -166,7 +160,7 @@ impl crate::pes::Stream for DiscStream { } loop { - if !self.fill_extents() { + if !self.fill_extents()? { self.eof = true; // Flush demuxer — last PES packet may still be in the assembler if let Some(ref mut demuxer) = self.ts_demuxer {