Fix truncated rips on dual-layer discs, propagate read errors
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<bool> so read errors propagate instead of being silently treated as EOF.
This commit is contained in:
+11
-10
@@ -66,17 +66,18 @@ impl Disc {
|
|||||||
pkt_count = clip_info.source_packet_count;
|
pkt_count = clip_info.source_packet_count;
|
||||||
total_size += pkt_count as u64 * 192;
|
total_size += pkt_count as u64 * 192;
|
||||||
|
|
||||||
// Get m2ts file start LBA and compute extent from packet count.
|
// Get m2ts file extents from UDF allocation descriptors.
|
||||||
// BD-ROM m2ts files are contiguous on disc (mastering requirement).
|
// Dual-layer discs split files across layers — UDF knows the real layout.
|
||||||
let m2ts_path = format!("/BDMV/STREAM/{}.m2ts", play_item.clip_id);
|
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);
|
if let Ok(file_exts) = udf_fs.file_extents(reader, &m2ts_path) {
|
||||||
let total_bytes = pkt_count as u64 * 192;
|
for (lba, sectors) in file_exts {
|
||||||
let total_sectors = total_bytes.div_ceil(2048) as u32;
|
if sectors > 0 && lba > 0 {
|
||||||
if total_sectors > 0 && file_lba > 0 {
|
extents.push(Extent {
|
||||||
extents.push(Extent {
|
start_lba: lba,
|
||||||
start_lba: file_lba,
|
sector_count: sectors,
|
||||||
sector_count: total_sectors,
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-17
@@ -117,9 +117,9 @@ impl DiscStream {
|
|||||||
self.disc.as_ref()
|
self.disc.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_extents(&mut self) -> bool {
|
fn fill_extents(&mut self) -> io::Result<bool> {
|
||||||
if self.current_extent >= self.extents.len() {
|
if self.current_extent >= self.extents.len() {
|
||||||
return false;
|
return Ok(false);
|
||||||
}
|
}
|
||||||
let ext_start = self.extents[self.current_extent].start_lba;
|
let ext_start = self.extents[self.current_extent].start_lba;
|
||||||
let ext_sectors = self.extents[self.current_extent].sector_count;
|
let ext_sectors = self.extents[self.current_extent].sector_count;
|
||||||
@@ -137,21 +137,15 @@ impl DiscStream {
|
|||||||
let bytes = sectors as usize * 2048;
|
let bytes = sectors as usize * 2048;
|
||||||
self.read_buf.resize(bytes, 0);
|
self.read_buf.resize(bytes, 0);
|
||||||
|
|
||||||
match self
|
self.reader
|
||||||
.reader
|
.read_sectors(lba, sectors, &mut self.read_buf[..bytes])?;
|
||||||
.read_sectors(lba, sectors, &mut self.read_buf[..bytes])
|
self.buf_valid = bytes;
|
||||||
{
|
self.current_offset += sectors as u32;
|
||||||
Ok(_) => {
|
if self.current_offset >= ext_sectors {
|
||||||
self.buf_valid = bytes;
|
self.current_extent += 1;
|
||||||
self.current_offset += sectors as u32;
|
self.current_offset = 0;
|
||||||
if self.current_offset >= ext_sectors {
|
|
||||||
self.current_extent += 1;
|
|
||||||
self.current_offset = 0;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(_) => false,
|
|
||||||
}
|
}
|
||||||
|
Ok(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +160,7 @@ impl crate::pes::Stream for DiscStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if !self.fill_extents() {
|
if !self.fill_extents()? {
|
||||||
self.eof = true;
|
self.eof = true;
|
||||||
// Flush demuxer — last PES packet may still be in the assembler
|
// Flush demuxer — last PES packet may still be in the assembler
|
||||||
if let Some(ref mut demuxer) = self.ts_demuxer {
|
if let Some(ref mut demuxer) = self.ts_demuxer {
|
||||||
|
|||||||
Reference in New Issue
Block a user