Account for decrypt-time loss so partial AACS/CSS failures can't pass as a perfect rip
When a scrambled AACS unit fails to decrypt under every available key (a missing/wrong CPS sub-key, or a marginal unit that fails the TS-sync verify), decrypt_sectors restored the original encrypted bytes and returned Ok with no signal. Those still-encrypted bytes flowed to the TS assembler, which silently dropped the non-syncing packets with no loss counter. The only loss accounting was DiscStream's read-error zero-fill path, so mux reported lost_video_secs=0 for decrypt-dropped content and the abort gate accepted the rip even under abort_on_lost_secs=0. A rip missing real video/audio segments was published as a perfect success. decrypt_sectors now returns the number of bytes in scrambled units that no key could decrypt. DecryptingSectorSource accumulates that into a shared counter exposed via decrypt_loss(); both mux pipelines fold it into lost_bytes() — the inline DiscStream path directly, and the file-backed highway via PipelinedPesStream sharing the producer's counter. Restore-to-original is unchanged, so clear nav-files are never corrupted; metadata-probe callers that don't read the counter are unaffected. Adds regression tests at the decrypt and decorator layers.
This commit is contained in:
+10
-7
@@ -549,6 +549,12 @@ pub fn build_iso_pipeline<S: SectorSource + Send + 'static>(
|
||||
};
|
||||
let decrypting =
|
||||
crate::sector::DecryptingSectorSource::new(Box::new(reader) as Box<dyn SectorSource>, keys);
|
||||
// Grab the decrypt-loss counter before the decorator is moved into the
|
||||
// producer thread. It tracks bytes of scrambled AACS units no key could
|
||||
// decrypt — silent loss the demux drops; the consuming stream surfaces it
|
||||
// through `lost_bytes()` so the mux abort gate sees a partial decrypt
|
||||
// failure rather than a clean rip.
|
||||
let decrypt_loss = decrypting.decrypt_loss();
|
||||
let prefetched = crate::sector::PrefetchedSectorSource::new_with_events(
|
||||
decrypting,
|
||||
extents,
|
||||
@@ -564,13 +570,10 @@ pub fn build_iso_pipeline<S: SectorSource + Send + 'static>(
|
||||
let (demux_thread, demux_rx) =
|
||||
super::demux_thread::DemuxThread::spawn_zero_copy(rx, recycle_tx, shell, halt, ts, ps)
|
||||
.map_err(|e| -> io::Error { e.into() })?;
|
||||
Ok(PipelinedPesStream::new(
|
||||
demux_thread,
|
||||
demux_rx,
|
||||
title,
|
||||
parsers,
|
||||
pid_to_track,
|
||||
))
|
||||
Ok(
|
||||
PipelinedPesStream::new(demux_thread, demux_rx, title, parsers, pid_to_track)
|
||||
.with_decrypt_loss(decrypt_loss),
|
||||
)
|
||||
}
|
||||
|
||||
/// Assemble the M2TS file mux pipeline (read → demux → parse) for a
|
||||
|
||||
Reference in New Issue
Block a user