style: cargo fmt
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
//! AACS content decryption — AES primitives, unit decryption, bus encryption.
|
||||
|
||||
use aes::cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit};
|
||||
use aes::Aes128;
|
||||
use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit, generic_array::GenericArray};
|
||||
|
||||
// ── AACS constants ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -674,8 +674,8 @@ fn generate_host_key_pair() -> ([u8; 20], [u8; 20], [u8; 20]) {
|
||||
|
||||
/// AES-128-CMAC over 16 bytes of data.
|
||||
fn aes_cmac_16(data: &[u8; 16], key: &[u8; 16]) -> [u8; 16] {
|
||||
use aes::cipher::{generic_array::GenericArray, BlockEncrypt, KeyInit};
|
||||
use aes::Aes128;
|
||||
use aes::cipher::{BlockEncrypt, KeyInit, generic_array::GenericArray};
|
||||
|
||||
let cipher = Aes128::new(GenericArray::from_slice(key));
|
||||
|
||||
|
||||
+1
-5
@@ -361,11 +361,7 @@ mod tests {
|
||||
/// Get KEYDB path from KEYDB_PATH environment variable. Returns None if not set or not found.
|
||||
fn keydb_path() -> Option<std::path::PathBuf> {
|
||||
let path = std::path::PathBuf::from(std::env::var("KEYDB_PATH").ok()?);
|
||||
if path.exists() {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if path.exists() { Some(path) } else { None }
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+3
-7
@@ -661,18 +661,14 @@ pub fn resolve_keys(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::decrypt::{aes_ecb_encrypt, ALIGNED_UNIT_LEN};
|
||||
use super::super::decrypt::{ALIGNED_UNIT_LEN, aes_ecb_encrypt};
|
||||
use super::super::keydb::{DiscEntry, KeyDb};
|
||||
use super::*;
|
||||
|
||||
/// Get KEYDB path from KEYDB_PATH environment variable. Returns None if not set or not found.
|
||||
fn keydb_path() -> Option<std::path::PathBuf> {
|
||||
let path = std::path::PathBuf::from(std::env::var("KEYDB_PATH").ok()?);
|
||||
if path.exists() {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
if path.exists() { Some(path) } else { None }
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -849,7 +845,7 @@ mod tests {
|
||||
data[23] = 1; // top_menu = CPS unit 1
|
||||
data[24] = 0;
|
||||
data[25] = 1; // num_titles = 1
|
||||
// Title 0 entry: 2 bytes pad + CPS unit
|
||||
// Title 0 entry: 2 bytes pad + CPS unit
|
||||
data[28] = 0;
|
||||
data[29] = 1; // CPS unit 1
|
||||
|
||||
|
||||
+5
-5
@@ -21,12 +21,12 @@ pub mod keys;
|
||||
// Explicit re-exports — only items needed by external consumers and sibling crate modules.
|
||||
// AES primitives (aes_ecb_encrypt, aes_ecb_decrypt, aes_cbc_decrypt) are pub(crate) in decrypt.rs.
|
||||
pub use decrypt::{
|
||||
decrypt_bus, decrypt_unit, decrypt_unit_full, decrypt_unit_try_keys, is_unit_encrypted,
|
||||
ALIGNED_UNIT_LEN,
|
||||
ALIGNED_UNIT_LEN, decrypt_bus, decrypt_unit, decrypt_unit_full, decrypt_unit_try_keys,
|
||||
is_unit_encrypted,
|
||||
};
|
||||
pub use keydb::{DeviceKey, DiscEntry, HostCert, KeyDb};
|
||||
pub use keys::{
|
||||
decrypt_unit_key, derive_media_key_from_dk, derive_media_key_from_pk, derive_vuk, disc_hash,
|
||||
disc_hash_hex, mkb_version, parse_content_cert, parse_unit_key_ro, read_mkb_from_drive,
|
||||
resolve_keys, ContentCert, ResolvedKeys, UnitKeyFile,
|
||||
ContentCert, ResolvedKeys, UnitKeyFile, decrypt_unit_key, derive_media_key_from_dk,
|
||||
derive_media_key_from_pk, derive_vuk, disc_hash, disc_hash_hex, mkb_version,
|
||||
parse_content_cert, parse_unit_key_ro, read_mkb_from_drive, resolve_keys,
|
||||
};
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@ mod tests {
|
||||
let key = [0x01, 0x02, 0x03, 0x04, 0x05];
|
||||
let mut sector = vec![0xAA; 2048];
|
||||
sector[0x14] = 0x30; // scramble flag set
|
||||
// Set a sector seed
|
||||
// Set a sector seed
|
||||
sector[0x54..0x59].copy_from_slice(&[0x11, 0x22, 0x33, 0x44, 0x55]);
|
||||
let original = sector.clone();
|
||||
descramble_sector(&key, &mut sector);
|
||||
|
||||
+31
-7
@@ -170,7 +170,9 @@ impl Mapfile {
|
||||
pub fn open_or_create(path: &Path, total_size: u64, version: &str) -> io::Result<Self> {
|
||||
match Self::load(path) {
|
||||
Ok(mf) => Ok(mf),
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => Self::create(path, total_size, version),
|
||||
Err(e) if e.kind() == io::ErrorKind::NotFound => {
|
||||
Self::create(path, total_size, version)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
@@ -290,12 +292,22 @@ impl Mapfile {
|
||||
{
|
||||
let file = std::fs::File::create(&tmp)?;
|
||||
let mut w = std::io::BufWriter::new(file);
|
||||
writeln!(w, "# Rescue Logfile. Created by libfreemkv v{}", self.version)?;
|
||||
writeln!(
|
||||
w,
|
||||
"# Rescue Logfile. Created by libfreemkv v{}",
|
||||
self.version
|
||||
)?;
|
||||
writeln!(w, "# Current pos / status / pass / pass_time")?;
|
||||
writeln!(w, "0x000000000 ? 1 0")?;
|
||||
writeln!(w, "# pos size status")?;
|
||||
for e in &self.entries {
|
||||
writeln!(w, "0x{:09x} 0x{:09x} {}", e.pos, e.size, e.status.to_char())?;
|
||||
writeln!(
|
||||
w,
|
||||
"0x{:09x} 0x{:09x} {}",
|
||||
e.pos,
|
||||
e.size,
|
||||
e.status.to_char()
|
||||
)?;
|
||||
}
|
||||
w.flush()?;
|
||||
}
|
||||
@@ -347,9 +359,18 @@ mod tests {
|
||||
mf.record(200, 100, SectorStatus::Finished).unwrap();
|
||||
let es = mf.entries();
|
||||
assert_eq!(es.len(), 3);
|
||||
assert_eq!((es[0].pos, es[0].size, es[0].status), (0, 200, SectorStatus::NonTried));
|
||||
assert_eq!((es[1].pos, es[1].size, es[1].status), (200, 100, SectorStatus::Finished));
|
||||
assert_eq!((es[2].pos, es[2].size, es[2].status), (300, 700, SectorStatus::NonTried));
|
||||
assert_eq!(
|
||||
(es[0].pos, es[0].size, es[0].status),
|
||||
(0, 200, SectorStatus::NonTried)
|
||||
);
|
||||
assert_eq!(
|
||||
(es[1].pos, es[1].size, es[1].status),
|
||||
(200, 100, SectorStatus::Finished)
|
||||
);
|
||||
assert_eq!(
|
||||
(es[2].pos, es[2].size, es[2].status),
|
||||
(300, 700, SectorStatus::NonTried)
|
||||
);
|
||||
let _ = std::fs::remove_file(&p);
|
||||
}
|
||||
|
||||
@@ -363,7 +384,10 @@ mod tests {
|
||||
// Entries: [0..100 NonTried, 100..300 Finished (merged), 300..1000 NonTried]
|
||||
let es = mf.entries();
|
||||
assert_eq!(es.len(), 3);
|
||||
assert_eq!((es[1].pos, es[1].size, es[1].status), (100, 200, SectorStatus::Finished));
|
||||
assert_eq!(
|
||||
(es[1].pos, es[1].size, es[1].status),
|
||||
(100, 200, SectorStatus::Finished)
|
||||
);
|
||||
let _ = std::fs::remove_file(&p);
|
||||
}
|
||||
|
||||
|
||||
+25
-13
@@ -1243,20 +1243,26 @@ impl Disc {
|
||||
if !opts.resume {
|
||||
let _ = std::fs::remove_file(&mapfile_path);
|
||||
}
|
||||
let mut map = mapfile::Mapfile::open_or_create(&mapfile_path, total_bytes, env!("CARGO_PKG_VERSION"))
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
let mut map =
|
||||
mapfile::Mapfile::open_or_create(&mapfile_path, total_bytes, env!("CARGO_PKG_VERSION"))
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
|
||||
// ISO file: if resuming and mapfile has Finished ranges, open existing;
|
||||
// otherwise create fresh and pre-size to total_bytes (sparse holes for
|
||||
// non-tried regions).
|
||||
let file = if opts.resume && std::fs::metadata(path).map(|m| m.len() > 0).unwrap_or(false) {
|
||||
let file = if opts.resume
|
||||
&& std::fs::metadata(path)
|
||||
.map(|m| m.len() > 0)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open(path)
|
||||
.map_err(|e| Error::IoError { source: e })?
|
||||
} else {
|
||||
let f = std::fs::File::create(path).map_err(|e| Error::IoError { source: e })?;
|
||||
f.set_len(total_bytes).map_err(|e| Error::IoError { source: e })?;
|
||||
f.set_len(total_bytes)
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
f
|
||||
};
|
||||
|
||||
@@ -1290,8 +1296,7 @@ impl Disc {
|
||||
// Only process the first NonTried range per outer pass; skip_forward
|
||||
// may turn others into NonTrimmed which we DO NOT re-enter here —
|
||||
// Disc::patch handles those.
|
||||
let Some((region_pos, region_size)) = map
|
||||
.next_with(0, mapfile::SectorStatus::NonTried)
|
||||
let Some((region_pos, region_size)) = map.next_with(0, mapfile::SectorStatus::NonTried)
|
||||
else {
|
||||
break;
|
||||
};
|
||||
@@ -1319,8 +1324,10 @@ impl Disc {
|
||||
if opts.decrypt {
|
||||
crate::decrypt::decrypt_sectors(&mut buf[..bytes], &keys, 0)?;
|
||||
}
|
||||
file.seek(SeekFrom::Start(pos)).map_err(|e| Error::IoError { source: e })?;
|
||||
file.write_all(&buf[..bytes]).map_err(|e| Error::IoError { source: e })?;
|
||||
file.seek(SeekFrom::Start(pos))
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
file.write_all(&buf[..bytes])
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
map.record(pos, block_bytes, mapfile::SectorStatus::Finished)
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
bytes_done = bytes_done.saturating_add(block_bytes);
|
||||
@@ -1329,8 +1336,10 @@ impl Disc {
|
||||
} else if opts.skip_on_error {
|
||||
// Zero-fill this block, mark non-trimmed for later patch trim.
|
||||
buf[..bytes].fill(0);
|
||||
file.seek(SeekFrom::Start(pos)).map_err(|e| Error::IoError { source: e })?;
|
||||
file.write_all(&buf[..bytes]).map_err(|e| Error::IoError { source: e })?;
|
||||
file.seek(SeekFrom::Start(pos))
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
file.write_all(&buf[..bytes])
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
map.record(pos, block_bytes, mapfile::SectorStatus::NonTrimmed)
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
pos += block_bytes;
|
||||
@@ -1453,7 +1462,8 @@ impl Disc {
|
||||
use std::io::{Seek, SeekFrom, Write};
|
||||
|
||||
let mapfile_path = mapfile_path_for(path);
|
||||
let mut map = mapfile::Mapfile::load(&mapfile_path).map_err(|e| Error::IoError { source: e })?;
|
||||
let mut map =
|
||||
mapfile::Mapfile::load(&mapfile_path).map_err(|e| Error::IoError { source: e })?;
|
||||
let total_bytes = map.total_size();
|
||||
let keys = if opts.decrypt {
|
||||
self.decrypt_keys()
|
||||
@@ -1507,8 +1517,10 @@ impl Disc {
|
||||
if opts.decrypt {
|
||||
crate::decrypt::decrypt_sectors(&mut buf[..bytes], &keys, 0)?;
|
||||
}
|
||||
file.seek(SeekFrom::Start(pos)).map_err(|e| Error::IoError { source: e })?;
|
||||
file.write_all(&buf[..bytes]).map_err(|e| Error::IoError { source: e })?;
|
||||
file.seek(SeekFrom::Start(pos))
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
file.write_all(&buf[..bytes])
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
map.record(pos, block_bytes, mapfile::SectorStatus::Finished)
|
||||
.map_err(|e| Error::IoError { source: e })?;
|
||||
} else {
|
||||
|
||||
+2
-2
@@ -18,14 +18,14 @@ mod windows;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::event::{Event, EventKind};
|
||||
use crate::identity::DriveId;
|
||||
use crate::platform::mt1959::Mt1959;
|
||||
use crate::platform::PlatformDriver;
|
||||
use crate::platform::mt1959::Mt1959;
|
||||
use crate::profile::{self, DriveProfile};
|
||||
use crate::scsi::ScsiTransport;
|
||||
use crate::sector::SectorReader;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
/// Physical state of the drive tray and disc.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
|
||||
+3
-3
@@ -734,12 +734,12 @@ mod tests {
|
||||
let mut pgc = vec![0u8; 0xEA];
|
||||
pgc[0x02] = 1; // 1 program
|
||||
pgc[0x03] = 2; // 2 cells
|
||||
// 1h 59m 30s at 29.97fps, 0 frames
|
||||
// 1h 59m 30s at 29.97fps, 0 frames
|
||||
pgc[0x04] = 0x01; // hours BCD
|
||||
pgc[0x05] = 0x59; // minutes BCD
|
||||
pgc[0x06] = 0x30; // seconds BCD
|
||||
pgc[0x07] = 0b11_000000; // 29.97fps, 0 frames
|
||||
// Cell playback info offset at PGC+0xE8
|
||||
// Cell playback info offset at PGC+0xE8
|
||||
let cell_offset: u16 = 0xEA; // right after minimum header
|
||||
pgc[0xE8] = (cell_offset >> 8) as u8;
|
||||
pgc[0xE9] = cell_offset as u8;
|
||||
@@ -755,7 +755,7 @@ mod tests {
|
||||
pgc[co + 21] = 0;
|
||||
pgc[co + 22] = 0;
|
||||
pgc[co + 23] = 200; // last sector
|
||||
// Cell 1: sectors 300-400
|
||||
// Cell 1: sectors 300-400
|
||||
let co = 0xEA + 24;
|
||||
pgc[co + 8] = 0;
|
||||
pgc[co + 9] = 0;
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
//! When both exist, language_streams.txt provides structured types while
|
||||
//! menu_base.prop provides stream number → button name mapping.
|
||||
|
||||
use super::{vocab, LabelPurpose, LabelQualifier, StreamLabel, StreamLabelType};
|
||||
use super::{LabelPurpose, LabelQualifier, StreamLabel, StreamLabelType, vocab};
|
||||
use crate::sector::SectorReader;
|
||||
use crate::udf::UdfFs;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//!
|
||||
//! Token format: `{lang}_{codec?}_{purpose?}_{region?}_`
|
||||
|
||||
use super::{vocab, LabelPurpose, LabelQualifier, StreamLabel, StreamLabelType};
|
||||
use super::{LabelPurpose, LabelQualifier, StreamLabel, StreamLabelType, vocab};
|
||||
use crate::sector::SectorReader;
|
||||
use crate::udf::UdfFs;
|
||||
|
||||
|
||||
+5
-5
@@ -95,15 +95,15 @@ pub(crate) mod udf;
|
||||
pub mod verify;
|
||||
|
||||
pub use drive::capture::{
|
||||
capture_drive_data, mask_bytes, mask_string, CapturedFeature, DriveCapture,
|
||||
CapturedFeature, DriveCapture, capture_drive_data, mask_bytes, mask_string,
|
||||
};
|
||||
pub use drive::{find_drive, find_drives, Drive, DriveStatus};
|
||||
pub use drive::{Drive, DriveStatus, find_drive, find_drives};
|
||||
pub use error::{Error, Result};
|
||||
pub use event::{Event, EventKind};
|
||||
pub use identity::DriveId;
|
||||
pub use profile::DriveProfile;
|
||||
// Platform trait is pub(crate) -- callers use Drive, not Platform directly
|
||||
pub use decrypt::{decrypt_sectors, DecryptKeys};
|
||||
pub use decrypt::{DecryptKeys, decrypt_sectors};
|
||||
pub use disc::{
|
||||
AacsState, AudioChannels, AudioStream, Clip, Codec, ColorSpace, ContentFormat, Disc,
|
||||
DiscFormat, DiscId, DiscTitle, Extent, FrameRate, HdrFormat, KeySource, Resolution, SampleRate,
|
||||
@@ -115,8 +115,8 @@ pub use mux::MkvStream;
|
||||
pub use mux::NetworkStream;
|
||||
pub use mux::NullStream;
|
||||
pub use mux::StdioStream;
|
||||
pub use mux::{input, output, parse_url, InputOptions, StreamUrl};
|
||||
pub use mux::{InputOptions, StreamUrl, input, output, parse_url};
|
||||
pub use scsi::ScsiTransport;
|
||||
pub use sector::{FileSectorReader, SectorReader};
|
||||
pub use speed::DriveSpeed;
|
||||
pub use udf::{read_filesystem, UdfFs};
|
||||
pub use udf::{UdfFs, read_filesystem};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! Buffers across PES boundaries so frames that span two PES packets
|
||||
//! are emitted complete, not truncated.
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
pub struct Ac3Parser {
|
||||
/// Leftover bytes from previous PES (incomplete frame at end).
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! Buffers across PES boundaries so frames spanning two PES packets
|
||||
//! are emitted complete.
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
const DTS_CORE_SYNC: [u8; 4] = [0x7F, 0xFE, 0x80, 0x01];
|
||||
const DTS_HD_EXT_SYNC: [u8; 4] = [0x64, 0x58, 0x20, 0x25];
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//! For MKV: codec ID "S_VOBSUB".
|
||||
//! All frames are keyframes (each is a complete bitmap).
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
pub struct DvdSubParser {
|
||||
/// Pre-formatted VobSub .idx palette header for codec_private.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! Detects keyframes (IDR slices).
|
||||
//! Each PES packet = one access unit = one frame.
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
/// H.264 NAL unit types we care about.
|
||||
const NAL_SLICE_IDR: u8 = 5;
|
||||
@@ -263,7 +263,7 @@ mod tests {
|
||||
data.extend_from_slice(&[0x00, 0x00, 0x01]);
|
||||
data.push(0x67); // SPS
|
||||
data.extend_from_slice(&[0x42, 0x00, 0x1E, 0xAB, 0xCD]); // profile=0x42, compat=0x00, level=0x1E
|
||||
// PPS: 00 00 01 [68 <payload>]
|
||||
// PPS: 00 00 01 [68 <payload>]
|
||||
data.extend_from_slice(&[0x00, 0x00, 0x01]);
|
||||
data.push(0x68); // PPS
|
||||
data.extend_from_slice(&[0xCE, 0x01]);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! Each PES packet = one access unit = one frame.
|
||||
|
||||
use super::h264::{find_start_code, skip_start_code};
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
// HEVC NAL unit types
|
||||
const NAL_VPS: u8 = 32;
|
||||
@@ -122,7 +122,7 @@ impl CodecParser for HevcParser {
|
||||
|
||||
// Minimal HEVCDecoderConfigurationRecord header
|
||||
record.push(1); // configurationVersion
|
||||
// General profile space, tier flag, profile IDC from SPS
|
||||
// General profile space, tier flag, profile IDC from SPS
|
||||
if sps.len() > 3 {
|
||||
record.push(sps[1]); // general_profile_space + general_tier_flag + general_profile_idc
|
||||
} else {
|
||||
@@ -154,7 +154,7 @@ impl CodecParser for HevcParser {
|
||||
record.push(0xFC);
|
||||
// chromaFormat (6 + 2 bits)
|
||||
record.push(0xFC | 1); // 4:2:0
|
||||
// bitDepthLumaMinus8 (5 + 3 bits)
|
||||
// bitDepthLumaMinus8 (5 + 3 bits)
|
||||
record.push(0xF8);
|
||||
// bitDepthChromaMinus8 (5 + 3 bits)
|
||||
record.push(0xF8);
|
||||
@@ -162,7 +162,7 @@ impl CodecParser for HevcParser {
|
||||
record.extend_from_slice(&[0, 0]);
|
||||
// constantFrameRate + numTemporalLayers + temporalIdNested + lengthSizeMinusOne
|
||||
record.push(0x03); // lengthSizeMinusOne = 3 (4 bytes)
|
||||
// numOfArrays
|
||||
// numOfArrays
|
||||
record.push(3); // VPS, SPS, PPS
|
||||
|
||||
// VPS array
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//! For MKV: codec ID "A_PCM/INT/BIG" (BD) or "A_PCM/INT/LIT" (DVD).
|
||||
//! All frames are keyframes (uncompressed audio).
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
/// BD LPCM header size in bytes.
|
||||
const BD_LPCM_HEADER_SIZE: usize = 4;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//! - Sequence extension: 00 00 01 B5
|
||||
//! - Picture header: 00 00 01 00
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame};
|
||||
use super::{CodecParser, Frame, pts_to_ns};
|
||||
use crate::mux::ts::PesPacket;
|
||||
|
||||
/// Sequence header start code suffix.
|
||||
@@ -415,7 +415,7 @@ mod tests {
|
||||
// Sequence extension: 00 00 01 B5 [ext data]
|
||||
data.extend_from_slice(&[0x00, 0x00, 0x01, SEQ_EXT_CODE]);
|
||||
data.extend_from_slice(&[0x14, 0x8A, 0x00, 0x01, 0x00, 0x00]); // ext payload
|
||||
// Picture header follows.
|
||||
// Picture header follows.
|
||||
data.extend_from_slice(&make_picture_header(PICTURE_TYPE_I));
|
||||
data.extend_from_slice(&[0xFF; 4]);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! Each PES packet contains one or more segments.
|
||||
//! All segments are keyframes (no inter-segment dependencies).
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
pub struct PgsParser;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//! AC-3 frames (interleaved, same PID): start with sync word 0x0B77.
|
||||
//! We skip AC-3 frames and only emit TrueHD access units.
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
/// Duration of one TrueHD access unit in nanoseconds (1/1200 second).
|
||||
const AU_DURATION_NS: i64 = 833_333;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! Frame start = Frame header start code (0x0D).
|
||||
//! I-frames (keyframes) are identified from the frame header.
|
||||
|
||||
use super::{pts_to_ns, CodecParser, Frame, PesPacket};
|
||||
use super::{CodecParser, Frame, PesPacket, pts_to_ns};
|
||||
|
||||
const SC_SEQUENCE_HEADER: u8 = 0x0F;
|
||||
const SC_ENTRY_POINT: u8 = 0x0E;
|
||||
|
||||
+3
-11
@@ -9,8 +9,8 @@ use crate::disc::{Disc, DiscTitle, Extent};
|
||||
use crate::event::{BatchSizeReason, Event, EventKind};
|
||||
use crate::sector::SectorReader;
|
||||
use std::io;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
/// Ramp back up to the preferred batch size after this many sectors
|
||||
/// of clean reading at the current (reduced) size. 100 MiB = 51,200 sectors.
|
||||
@@ -26,22 +26,14 @@ const PROBE_THRESHOLD_SECTORS: u32 = 100 * 1024 * 1024 / 2048;
|
||||
/// through 3 → 1 without intermediate unaligned sizes.
|
||||
fn halve_batch_size(size: u16) -> u16 {
|
||||
let h = (size / 2).max(1);
|
||||
if h >= 6 {
|
||||
h - (h % 3)
|
||||
} else {
|
||||
h
|
||||
}
|
||||
if h >= 6 { h - (h % 3) } else { h }
|
||||
}
|
||||
|
||||
/// Double a batch size toward a preferred max, keeping 3-sector alignment
|
||||
/// when the result is >= 6.
|
||||
fn double_batch_size(size: u16, preferred: u16) -> u16 {
|
||||
let d = size.saturating_mul(2).min(preferred);
|
||||
if d >= 6 {
|
||||
d - (d % 3)
|
||||
} else {
|
||||
d
|
||||
}
|
||||
if d >= 6 { d - (d % 3) } else { d }
|
||||
}
|
||||
|
||||
/// Adaptive batch sizer. Shrinks on read failure, grows after a sustained
|
||||
|
||||
+1
-1
@@ -441,7 +441,7 @@ mod tests {
|
||||
fn test_write_uint() {
|
||||
let mut buf = Vec::new();
|
||||
write_uint(&mut buf, 0x4286, 1).unwrap(); // EBML_VERSION = 1
|
||||
// ID: 42 86, Size: 81 (1 byte), Data: 01
|
||||
// ID: 42 86, Size: 81 (1 byte), Data: 01
|
||||
assert_eq!(buf, [0x42, 0x86, 0x81, 0x01]);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -699,7 +699,7 @@ mod tests {
|
||||
// Track VINT: 1 byte (track 1 = 0x81)
|
||||
let track_vint_pos = after_id + size_len;
|
||||
let track_vint_len = 1; // track 1 encoded as 0x81
|
||||
// 2-byte relative timestamp
|
||||
// 2-byte relative timestamp
|
||||
let ts_pos = track_vint_pos + track_vint_len;
|
||||
// flags byte
|
||||
let flags_pos = ts_pos + 2;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! Write: PES frames in → MKV mux → Matroska container.
|
||||
|
||||
use super::mkv::{MkvMuxer, MkvTrack};
|
||||
use super::{ebml, WriteSeek};
|
||||
use super::{WriteSeek, ebml};
|
||||
|
||||
type MkvHeaderResult = io::Result<(crate::disc::DiscTitle, Vec<(u16, Vec<u8>)>)>;
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ pub use m2ts::M2tsStream;
|
||||
pub use mkvstream::MkvStream;
|
||||
pub use network::NetworkStream;
|
||||
pub use null::NullStream;
|
||||
pub use resolve::{input, output, parse_url, InputOptions, StreamUrl};
|
||||
pub use resolve::{InputOptions, StreamUrl, input, output, parse_url};
|
||||
pub use stdio::StdioStream;
|
||||
|
||||
use std::io::{Seek, Write};
|
||||
|
||||
+1
-5
@@ -227,11 +227,7 @@ fn hvcc_to_annex_b(hvcc: &[u8]) -> Option<Vec<u8>> {
|
||||
}
|
||||
}
|
||||
|
||||
if out.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(out)
|
||||
}
|
||||
if out.is_empty() { None } else { Some(out) }
|
||||
}
|
||||
|
||||
/// Convert length-prefixed NALUs (4-byte BE length + NAL) to Annex B
|
||||
|
||||
+3
-3
@@ -101,7 +101,7 @@ impl UdfFs {
|
||||
None => {
|
||||
return Err(Error::UdfNotFound {
|
||||
path: path.to_string(),
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
let entry = current
|
||||
@@ -136,7 +136,7 @@ impl UdfFs {
|
||||
None => {
|
||||
return Err(Error::UdfNotFound {
|
||||
path: path.to_string(),
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
let entry = current
|
||||
@@ -375,7 +375,7 @@ impl UdfFs {
|
||||
None => {
|
||||
return Err(Error::UdfNotFound {
|
||||
path: path.to_string(),
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
let entry = current
|
||||
|
||||
Reference in New Issue
Block a user