### Create an Example Calling a Documented Function Source: https://docs.rs/libfreemkv/0.10.10/scrape-examples-help.html This example demonstrates how to create a separate Rust file to call a documented function from another crate, intended for scraping by Rustdoc. ```rust // examples/ex.rs fn main() { a_crate::a_func(); } ``` -------------------------------- ### CSS Module Usage Example Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/css/index.html Example demonstrating how to use the CSS module to crack a title key and descramble a sector. ```APIDOC ## Module css libfreemkv ### Summary CSS (Content Scramble System) — DVD disc encryption. CSS uses a weak 40-bit LFSR stream cipher (broken since 1999). No keys needed — the title key is cracked from encrypted content using a known-plaintext attack on MPEG-2 PES headers. ### Usage: ```rust let key = css::crack_key(reader, &extents)?; css::descramble_sector(&key, &mut sector); ``` ## Functions ### crack_key Crack the CSS title key by reading encrypted sectors and applying a known-plaintext attack on MPEG-2 headers. ### descramble_sector Descramble a single CSS-encrypted sector in place. ### is_scrambled Check if a sector has the CSS scramble flag set. ``` -------------------------------- ### Dump ISO Image from Drive - Rust Example Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/drive/struct.Drive.html This example demonstrates how to open a Blu-ray drive, initialize it, scan the disc for AACS protection, and then read and dump the entire disc content to a file. It includes progress reporting and handles slow reads. ```rust fn main() { let args: Vec = std::env::args().collect(); if args.len() < 3 { eprintln!("Usage: iso_dump "); std::process::exit(1); } let mut drive = Drive::open(Path::new(&args[1])).unwrap(); drive.wait_ready().unwrap(); let _ = drive.init(); let _ = drive.probe_disc(); // AACS handshake — required to read past the protected area eprint!("Scanning disc... "); let _ = libfreemkv::Disc::scan(&mut drive, &libfreemkv::ScanOptions::default()); eprintln!("OK"); let cap = drive.read_capacity().unwrap(); let batch = libfreemkv::disc::detect_max_batch_sectors(drive.device_path()); eprintln!("Device: {} | {} sectors | batch {}", args[1], cap, batch); let file = std::fs::File::create(&args[2]).unwrap(); let mut w = BufWriter::with_capacity(4 * 1024 * 1024, file); let mut buf = vec![0u8; batch as usize * 2048]; let mut lba: u32 = 0; let start = Instant::now(); let mut last = Instant::now(); let mut bytes: u64 = 0; let mut last_bytes: u64 = 0; while lba < cap { let count = ((cap - lba) as u16).min(batch); let n = count as usize * 2048; // Tiny yield between reads — test if pacing prevents firmware throttle std::thread::yield_now(); let t0 = Instant::now(); let ok = drive.read(lba, count, &mut buf[..n]).is_ok(); let read_ms = t0.elapsed().as_millis(); // Flag slow reads if read_ms > 2000 { eprintln!("\n SLOW READ: LBA {} took {}ms (ok={})", lba, read_ms, ok); } if !ok { buf[..n].fill(0); } w.write_all(&buf[..n]).unwrap(); lba += count as u32; bytes += n as u64; if last.elapsed().as_millis() >= 1000 { let delta = bytes - last_bytes; let speed = delta as f64 / last.elapsed().as_secs_f64() / 1_048_576.0; let avg = bytes as f64 / start.elapsed().as_secs_f64() / 1_048_576.0; let pct = bytes as f64 / (cap as f64 * 2048.0) * 100.0; eprint!( "\r {:.1}% LBA {} | {:.0} MB/s (avg {:.0}) | {:.1} GB ", pct, lba, speed, avg, bytes as f64 / 1e9 ); last_bytes = bytes; last = Instant::now(); } } w.flush().unwrap(); eprintln!( "\nDone: {:.1} GB in {:.0}s", bytes as f64 / 1e9, start.elapsed().as_secs_f64() ); } ``` -------------------------------- ### Get Metadata Partition Start Sector Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/struct.UdfFs.html Retrieves the starting sector of the metadata partition for the UDF filesystem. ```rust pub fn metadata_start(&self) -> u32 ``` -------------------------------- ### start_master Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/mux/ebml/fn.start_master.html Starts a master element by writing its ID and a placeholder for its size. It returns the file offset of the size field, which can be used for later fixups. ```APIDOC ## start_master ### Description Starts a master element: write ID + placeholder size. Returns the file offset of the size field for later fixups. ### Function Signature ```rust pub fn start_master(w: &mut W, id: u32) -> Result ``` ### Parameters * `w` - A mutable reference to a type implementing `Write` and `Seek`, representing the output stream. * `id` - The unique identifier (u32) for the master element. ### Returns * `Result` - On success, returns the file offset (u64) of the size field. On failure, returns an error. ### Type Parameters * `W` - A generic type that must implement the `Write` and `Seek` traits. ``` -------------------------------- ### Read Metadata and Determine Partition Start Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/udf.rs.html Reads the metadata ICB to determine the size and starting position of the metadata partition. Falls back to the physical partition if no metadata partition is found. ```rust read_sector(reader, meta_file_lba, &mut meta_icb)?; let meta_tag = u16::from_le_bytes([meta_icb[0], meta_icb[1]]); if meta_tag == 266 { // Extended File Entry — get allocation extent let l_ea = u32::from_le_bytes([ meta_icb[208], meta_icb[209], meta_icb[210], meta_icb[211], ]) as usize; let ad_off = 216 + l_ea; if ad_off + 8 > meta_icb.len() { return Err(Error::DiscRead { sector: meta_file_lba as u64, }); } let ad_len = u32::from_le_bytes([ meta_icb[ad_off], meta_icb[ad_off + 1], meta_icb[ad_off + 2], meta_icb[ad_off + 3], ]) & 0x3FFF_FFFF; metadata_size_bytes = ad_len; let ad_pos = u32::from_le_bytes([ meta_icb[ad_off + 4], meta_icb[ad_off + 5], meta_icb[ad_off + 6], meta_icb[ad_off + 7], ]); // Metadata content starts at partition_start + ad_pos partition_start + ad_pos } else { // Fallback: no metadata partition, use physical partition directly partition_start } } else { partition_start } } else { partition_start } } else { // Single partition map — no metadata partition (older UDF) partition_start }; ``` -------------------------------- ### FromIterator Example (Ok) Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Demonstrates collecting an iterator of Results into a single Result, succeeding when all elements are Ok. ```rust let v = vec![1, 2]; let res: Result, &'static str> = v.iter().map(|x: &u32| x.checked_add(1).ok_or("Overflow!") ).collect(); assert_eq!(res, Ok(vec![2, 3])); ``` -------------------------------- ### IntoIterator Example (Ok) Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Demonstrates converting an Ok Result into an iterator that yields the contained value once. ```rust let x: Result = Ok(5); let v: Vec = x.into_iter().collect(); assert_eq!(v, [5]); ``` -------------------------------- ### Example Playlist XML Structure Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/labels/paramount.rs.html Illustrates the structure of a 'playlists.xml' file, showing attributes for language codes, forced subtitles, and commentary indices. ```xml ``` -------------------------------- ### FromIterator Example (Err) Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Demonstrates collecting an iterator of Results into a single Result, failing when any element is Err. ```rust let v = vec![1, 2, 0]; let res: Result, &'static str> = v.iter().map(|x: &u32| x.checked_sub(1).ok_or("Underflow!") ).collect(); assert_eq!(res, Err("Underflow!")); ``` -------------------------------- ### unwrap_or_else Example Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Demonstrates the use of unwrap_or_else with a closure to provide a default value when the Result is an Err. ```rust assert_eq!(Ok(2).unwrap_or_else(count), 2); assert_eq!(Err("foo").unwrap_or_else(count), 3); ``` -------------------------------- ### Get Drive Platform Name Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/drive/mod.rs.html Returns the name of the drive's platform. If no platform is configured, it defaults to 'Unknown'. ```rust pub fn platform_name(&self) -> &str { match self.platform { Some(ref p) => p.name(), None => "Unknown", } } ``` -------------------------------- ### Quick Start with libfreemkv Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/index.html Demonstrates basic usage of libfreemkv for finding a drive, initializing it, scanning a disc, and streaming content to an MKV file. Ensure you have an optical drive connected and a compatible disc inserted. ```rust use libfreemkv::{Drive, Disc, ScanOptions, find_drive}; let mut drive = find_drive().expect("no optical drive found"); drive.wait_ready().unwrap(); drive.init().unwrap(); let disc = Disc::scan(&mut drive, &ScanOptions::default()).unwrap(); for title in &disc.titles { println!("{} -- {} streams", title.duration_display(), title.streams.len()); } // Stream via PES pipeline let opts = libfreemkv::InputOptions::default(); let mut input = libfreemkv::input("disc://", &opts).unwrap(); let title = input.info().clone(); let mut output = libfreemkv::output("mkv://Movie.mkv", &title).unwrap(); while let Ok(Some(frame)) = input.read() { output.write(&frame).unwrap(); } output.finish().unwrap(); ``` -------------------------------- ### Dump Disc Contents with Drive Methods Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/drive/struct.Drive.html This example demonstrates how to open a drive, wait for it to be ready, initialize it, and then read its capacity and contents sector by sector. It includes progress reporting and handling of slow reads. Requires drive and output path as command-line arguments. ```rust fn main() { let args: Vec = std::env::args().collect(); if args.len() < 3 { eprintln!("Usage: iso_dump "); std::process::exit(1); } let mut drive = Drive::open(Path::new(&args[1])).unwrap(); drive.wait_ready().unwrap(); let _ = drive.init(); let _ = drive.probe_disc(); // AACS handshake — required to read past the protected area eprint!("Scanning disc... "); let _ = libfreemkv::Disc::scan(&mut drive, &libfreemkv::ScanOptions::default()); eprintln!("OK"); let cap = drive.read_capacity().unwrap(); let batch = libfreemkv::disc::detect_max_batch_sectors(drive.device_path()); eprintln!("Device: {} | {} sectors | batch {}", args[1], cap, batch); let file = std::fs::File::create(&args[2]).unwrap(); let mut w = BufWriter::with_capacity(4 * 1024 * 1024, file); let mut buf = vec![0u8; batch as usize * 2048]; let mut lba: u32 = 0; let start = Instant::now(); let mut last = Instant::now(); let mut bytes: u64 = 0; let mut last_bytes: u64 = 0; while lba < cap { let count = ((cap - lba) as u16).min(batch); let n = count as usize * 2048; // Tiny yield between reads — test if pacing prevents firmware throttle std::thread::yield_now(); let t0 = Instant::now(); let ok = drive.read(lba, count, &mut buf[..n]).is_ok(); let read_ms = t0.elapsed().as_millis(); // Flag slow reads if read_ms > 2000 { eprintln!("\n SLOW READ: LBA {} took {}ms (ok={})", lba, read_ms, ok); } if !ok { buf[..n].fill(0); } w.write_all(&buf[..n]).unwrap(); lba += count as u32; bytes += n as u64; if last.elapsed().as_millis() >= 1000 { let delta = bytes - last_bytes; let speed = delta as f64 / last.elapsed().as_secs_f64() / 1_048_576.0; let avg = bytes as f64 / start.elapsed().as_secs_f64() / 1_048_576.0; let pct = bytes as f64 / (cap as f64 * 2048.0) * 100.0; eprint!( "\r {:.1}% LBA {} | {:.0} MB/s (avg {:.0}) | {:.1} GB ", pct, lba, speed, avg, bytes as f64 / 1e9 ); last_bytes = bytes; last = Instant::now(); } } w.flush().unwrap(); eprintln!( "\nDone: {:.1} GB in {:.0}s", bytes as f64 / 1e9, start.elapsed().as_secs_f64() ); } ``` -------------------------------- ### Get Physical Partition Start Sector Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/struct.UdfFs.html Retrieves the starting sector of the physical partition for the UDF filesystem. ```rust pub fn partition_start(&self) -> u32 ``` -------------------------------- ### Quick Start: Accessing Drive and Disc Information Source: https://docs.rs/libfreemkv/0.10.10/index.html This snippet demonstrates how to find an optical drive, initialize it, scan the disc, and iterate through its titles. It also shows how to stream content via a PES pipeline to an MKV file. ```rust use libfreemkv::{Drive, Disc, ScanOptions, find_drive}; let mut drive = find_drive().expect("no optical drive found"); drive.wait_ready().unwrap(); drive.init().unwrap(); let disc = Disc::scan(&mut drive, &ScanOptions::default()).unwrap(); for title in &disc.titles { println!("{} -- {} streams", title.duration_display(), title.streams.len()); } // Stream via PES pipeline let opts = libfreemkv::InputOptions::default(); let mut input = libfreemkv::input("disc://", &opts).unwrap(); let title = input.info().clone(); let mut output = libfreemkv::output("mkv://Movie.mkv", &title).unwrap(); while let Ok(Some(frame)) = input.read() { output.write(&frame).unwrap(); } output.finish().unwrap(); ``` -------------------------------- ### Create Master Element Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mux/ebml.rs.html Shows how to start and end a master element in EBML. `start_master` is used to get the starting position, and `end_master` finalizes the element. ```rust let mut buf = Cursor::new(Vec::new()); let pos = start_master(&mut buf, EBML).unwrap(); write_uint(&mut buf, EBML_VERSION, 1).unwrap(); end_master(&mut buf, pos).unwrap(); let data = buf.into_inner(); // EBML header: 1A 45 DF A3, then 8-byte size, then content assert_eq!(&data[0..4], &[0x1A, 0x45, 0xDF, 0xA3]); ``` -------------------------------- ### Get File Starting LBA Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/struct.UdfFs.html Determines the absolute starting Logical Block Address (LBA) of a file on disk. This is used to locate content sectors for processes like the rip pipeline. ```rust pub fn file_start_lba( &self, reader: &mut dyn SectorReader, path: &str, ) -> Result ``` -------------------------------- ### init Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/drive/mod.rs.html Initializes the drive, which includes unlocking and uploading firmware. This optional step enables features like removing riplock, enabling UHD reads, and speed control. ```APIDOC ## init ### Description Initializes the drive by performing an unlock and firmware upload. This operation is optional but enables advanced features. ### Method `&mut self.init()` ### Returns - `Result<()>`: Ok(()) on success, or an Error if the drive is unsupported or initialization fails. ``` -------------------------------- ### Get File Start LBA in UDF Filesystem Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/udf.rs.html Retrieves the absolute starting Logical Block Address (LBA) of a file on disc. This is used to locate content sectors for processing. Requires a SectorReader to access disc data. ```rust pub fn file_start_lba(&self, reader: &mut dyn SectorReader, path: &str) -> Result { let parts: Vec<&str> = path.trim_matches('/').split('/').collect(); let mut current = &self.root; for part in &parts[..parts.len() - 1] { current = current .entries .iter() .find(|e| e.is_dir && e.name.eq_ignore_ascii_case(part)) .ok_or_else(|| Error::UdfNotFound { path: part.to_string(), })?; } let filename = match parts.last() { Some(f) => f, None => { return Err(Error::UdfNotFound { path: path.to_string(), }) } }; let entry = current .entries .iter() .find(|e| !e.is_dir && e.name.eq_ignore_ascii_case(filename)) .ok_or_else(|| Error::UdfNotFound { path: path.to_string(), })?; let (data_lba, _) = self.read_icb_extent(reader, entry.meta_lba)?; Ok(self.partition_start + data_lba) } ``` -------------------------------- ### unsafe unwrap_err_unchecked Example (Err) Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Shows how to use unwrap_err_unchecked to get the Err value without safety checks. This is safe only when the Result is guaranteed to be Err. ```rust let x: Result = Err("emergency failure"); assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure"); ``` -------------------------------- ### unsafe unwrap_unchecked Example (Ok) Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Shows how to use unwrap_unchecked to get the Ok value without safety checks. This is safe only when the Result is guaranteed to be Ok. ```rust let x: Result = Ok(2); assert_eq!(unsafe { x.unwrap_unchecked() }, 2); ``` -------------------------------- ### Open and Read Drive Data Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/drive/struct.Drive.html Opens a drive from a device path and reads its entire content sector by sector, writing it to an output file. This example demonstrates initializing the drive, scanning the disc, reading capacity, and performing a sector-by-sector dump, including handling slow reads and displaying progress. ```rust 7fn main() { 8 let args: Vec = std::env::args().collect(); 9 if args.len() < 3 { 10 eprintln!("Usage: iso_dump "); 11 std::process::exit(1); 12 } 13 14 let mut drive = Drive::open(Path::new(&args[1])).unwrap(); 15 drive.wait_ready().unwrap(); 16 let _ = drive.init(); 17 let _ = drive.probe_disc(); 18 19 // AACS handshake — required to read past the protected area 20 eprint!("Scanning disc... "); 21 let _ = libfreemkv::Disc::scan(&mut drive, &libfreemkv::ScanOptions::default()); 22 eprintln!("OK"); 23 24 let cap = drive.read_capacity().unwrap(); 25 let batch = libfreemkv::disc::detect_max_batch_sectors(drive.device_path()); 26 27 eprintln!("Device: {} | {} sectors | batch {}", args[1], cap, batch); 28 29 let file = std::fs::File::create(&args[2]).unwrap(); 30 let mut w = BufWriter::with_capacity(4 * 1024 * 1024, file); 31 let mut buf = vec![0u8; batch as usize * 2048]; 32 let mut lba: u32 = 0; 33 let start = Instant::now(); 34 let mut last = Instant::now(); 35 let mut bytes: u64 = 0; 36 let mut last_bytes: u64 = 0; 37 38 while lba < cap { 39 let count = ((cap - lba) as u16).min(batch); 40 let n = count as usize * 2048; 41 42 // Tiny yield between reads — test if pacing prevents firmware throttle 43 std::thread::yield_now(); 44 let t0 = Instant::now(); 45 let ok = drive.read(lba, count, &mut buf[..n]).is_ok(); 46 let read_ms = t0.elapsed().as_millis(); 47 48 // Flag slow reads 49 if read_ms > 2000 { 50 eprintln!("\n SLOW READ: LBA {} took {}ms (ok={})", lba, read_ms, ok); 51 } 52 53 if !ok { 54 buf[..n].fill(0); 55 } 56 w.write_all(&buf[..n]).unwrap(); 57 lba += count as u32; 58 bytes += n as u64; 59 60 if last.elapsed().as_millis() >= 1000 { 61 let delta = bytes - last_bytes; 62 let speed = delta as f64 / last.elapsed().as_secs_f64() / 1_048_576.0; 63 let avg = bytes as f64 / start.elapsed().as_secs_f64() / 1_048_576.0; 64 let pct = bytes as f64 / (cap as f64 * 2048.0) * 100.0; 65 eprint!( 66 "\r {:.1}% LBA {} | {:.0} MB/s (avg {:.0}) | {:.1} GB ", 67 pct, 68 lba, 69 speed, 70 avg, 71 bytes as f64 / 1e9 72 ); 73 last_bytes = bytes; 74 last = Instant::now(); 75 } 76 } 77 w.flush().unwrap(); 78 eprintln!( 79 "\nDone: {:.1} GB in {:.0}s", 80 bytes as f64 / 1e9, 81 start.elapsed().as_secs_f64() 82 ); 83} ``` -------------------------------- ### H.264 PTS Conversion Example Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mux/codec/h264.rs.html Illustrates the setup for a PES packet containing H.264 data, specifically for testing Presentation Timestamp (PTS) conversion. This snippet sets up the initial data vector for parsing. ```rust let mut parser = H264Parser::new(); let mut data = Vec::new(); data.extend_from_slice(&[0x00, 0x00, 0x01]); data.push(0x41); ``` -------------------------------- ### Get Sector Extents Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/clpi.rs.html Calculates the sector extents (start LBA and sector count) for a given time range (in_time, out_time). It converts PTS timestamps to SPN ranges and then to logical block addressing (LBA) sectors. ```rust /// Get sector extents for a given in/out time range. /// /// Converts PTS timestamps to SPN ranges, then SPN to LBA /// using the file's starting LBA on disc. pub fn get_extents(&self, in_time: u32, out_time: u32) -> Vec { let ep_map = self.resolved_ep_map(); if ep_map.is_empty() { return Vec::new(); } // Find SPN at or before in_time let start_spn = match ep_map.binary_search_by_key(&in_time, |(pts, _)| *pts) { Ok(i) => ep_map[i].1, Err(0) => ep_map[0].1, Err(i) => ep_map[i - 1].1, }; // Find SPN at or after out_time let end_spn = match ep_map.binary_search_by_key(&out_time, |(pts, _)| *pts) { Ok(i) => ep_map[i].1, Err(i) if i < ep_map.len() => ep_map[i].1, _ => ep_map.last().unwrap().1 + 1, }; if end_spn <= start_spn { return Vec::new(); } // SPN → byte offset: spn × 192 // Byte offset → sectors: offset / 2048 // Note: the caller needs to add the file's starting LBA from UDF let start_byte = start_spn as u64 * 192; let end_byte = end_spn as u64 * 192; let start_sector = (start_byte / 2048) as u32; let end_sector = end_byte.div_ceil(2048) as u32; vec![Extent { start_lba: start_sector, // relative to m2ts file start sector_count: end_sector - start_sector, }] } } ``` -------------------------------- ### Initialize Drive - libfreemkv Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/drive/struct.Drive.html Initializes the drive, which can unlock features like UHD reads and speed control. This is an optional step. ```rust let _ = drive.init(); ``` -------------------------------- ### KeyDB::load Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/aacs/keydb.rs.html Loads the KEYDB.cfg file from the specified path and parses its content into a KeyDB structure. This is the primary method for initializing the key database from a file. ```APIDOC ## KeyDB::load ### Description Loads the KEYDB.cfg file from the specified path and parses its content into a KeyDB structure. This is the primary method for initializing the key database from a file. ### Signature `pub fn load(path: &std::path::Path) -> std::io::Result` ### Parameters * `path` (&std::path::Path): The file path to the KEYDB.cfg file. ### Returns * `std::io::Result`: A Result containing the loaded `KeyDB` instance on success, or an `std::io::Error` on failure. ``` -------------------------------- ### Find Next Start Code in VC-1 Data Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mux/codec/vc1.rs.html Locates the next occurrence of a VC-1 start code (00 00 01) within a byte slice, starting from a specified offset. Returns `None` if no start code is found. ```rust fn find_next_sc(data: &[u8], from: usize) -> Option { (from..data.len().saturating_sub(2)) .find(|&i| data[i] == 0x00 && data[i + 1] == 0x00 && data[i + 2] == 0x01) } ``` -------------------------------- ### Build and Parse MPLS with Streams Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mpls.rs.html Demonstrates building an MPLS structure with video, audio, and subtitle streams, then parsing it and asserting the stream properties. ```rust let audio = build_stream_entry_audio(0x1100, 0x83, 6, 1, b"eng"); let pg = build_stream_entry_pg(0x1200, 0x90, b"fra"); let data = build_mpls( &[(b"00001", 1, 0, 9000000)], (1, 1, 1, 0, 0, 0, 0, 0), &[video, audio, pg], ); let playlist = parse(&data).expect("should parse"); assert_eq!(playlist.streams.len(), 3); // Video stream let v = &playlist.streams[0]; assert_eq!(v.stream_type, 1); assert_eq!(v.pid, 0x1011); assert_eq!(v.coding_type, 0x24); // HEVC assert_eq!(v.video_format, 8); // 2160p assert_eq!(v.video_rate, 1); // 23.976 assert_eq!(v.dynamic_range, 1); // HDR10 assert_eq!(v.color_space, 2); // BT.2020 assert!(!v.secondary); // Audio stream let a = &playlist.streams[1]; assert_eq!(a.stream_type, 2); assert_eq!(a.pid, 0x1100); assert_eq!(a.coding_type, 0x83); // TrueHD assert_eq!(a.audio_format, 6); // 5.1 assert_eq!(a.audio_rate, 1); // 48kHz assert_eq!(a.language, "eng"); assert!(!a.secondary); // PG subtitle stream let s = &playlist.streams[2]; assert_eq!(s.stream_type, 3); assert_eq!(s.pid, 0x1200); assert_eq!(s.coding_type, 0x90); // PGS assert_eq!(s.language, "fra"); assert!(!s.secondary); ``` -------------------------------- ### Skip H.264 Start Code Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mux/codec/h264.rs.html Skips past an H.264 start code (either 3 or 4 bytes) at a given position in a byte slice. Returns the offset of the first byte after the start code, or None if the start code is not found or the data is too short. ```rust pub fn skip_start_code(data: &[u8], pos: usize) -> Option { if pos + 2 >= data.len() { return None; } if data[pos] == 0x00 && data[pos + 1] == 0x00 { if pos + 3 < data.len() && data[pos + 2] == 0x00 && data[pos + 3] == 0x01 { return Some(pos + 4); // 4-byte start code } if data[pos + 2] == 0x01 { return Some(pos + 3); // 3-byte start code } } None } ``` -------------------------------- ### Initialize Drive (Unlock and Firmware Load) Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/platform/mt1959/mod.rs.html Handles the drive initialization process, which involves attempting to unlock the drive and potentially loading firmware. It includes retry logic and a delay after firmware loading to allow the drive to recover. ```rust fn run_init(&mut self, scsi: &mut dyn ScsiTransport) -> Result<()> { let mut unlocked = false; for _attempt in 0..3 { match self.do_unlock(scsi) { Ok(_) => { unlocked = true; break; } Err(Error::SignatureMismatch { .. }) => { return Err(Error::UnlockFailed); } Err(_) => { let loaded = if self.mode == MODE_A { variant_a::load_firmware(self, scsi).is_ok() } else { variant_b::load_firmware(self, scsi).is_ok() }; if !loaded { continue; } // Firmware upload resets the drive. Give it time to // fully recover before retrying unlock. std::thread::sleep(std::time::Duration::from_secs(10)); } } } if !unlocked { return Err(Error::UnlockFailed); } Ok(()) } ``` -------------------------------- ### Find Next Start Code in Data Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mux/codec/mpeg2.rs.html Locates the position of the next MPEG-2 start code (00 00 01) within a byte slice, starting the search from a specified offset. ```rust /// Find the position of the next start code (00 00 01) at or after `from`. fn find_start_code(data: &[u8], from: usize) -> Option { ``` -------------------------------- ### skip_start_code Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/mux/codec/h264/fn.skip_start_code.html Skips past the start code at the given position in the byte slice and returns the position of the first byte after the start code. Returns None if a start code is not found or if the data is insufficient. ```APIDOC ## skip_start_code ### Description Skip past the start code at position `pos`, returning the first byte after it. ### Signature ```rust pub fn skip_start_code(data: &[u8], pos: usize) -> Option ``` ### Parameters * `data` - A slice of bytes representing the H.264 data. * `pos` - The starting position within the `data` slice to look for a start code. ### Returns * `Some(usize)` - The position of the first byte immediately following the start code if found. * `None` - If a start code is not found at the specified position or if the data is insufficient to determine a start code. ``` -------------------------------- ### open Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/scsi/fn.open.html Opens a SCSI transport for the specified device path, automatically selecting the correct backend for the operating system. ```APIDOC ## open ### Description Opens a SCSI transport for the given device path. Selects the right backend for the current platform. ### Function Signature ```rust pub fn open(device: &Path) -> Result> ``` ### Parameters #### Path Parameters - **device** (*&Path*) - Required - The path to the SCSI device. ### Returns - **Result>** - A Result containing a boxed trait object implementing `ScsiTransport` on success, or an error on failure. ``` -------------------------------- ### H.264 Start Code Search Function Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/mux/codec/h264/fn.find_start_code.html Finds the position of the next start code (00 00 01) at or after a specified offset in a byte slice. Returns `None` if no start code is found. ```rust pub fn find_start_code(data: &[u8], from: usize) -> Option ``` -------------------------------- ### Load KeyDb from File Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/aacs/keydb/struct.KeyDb.html Loads the KEYDB.cfg file from a given file path. Returns a Result containing the KeyDb struct or an error. ```rust pub fn load(path: &Path) -> Result ``` -------------------------------- ### find_start_code Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/mux/codec/h264/fn.find_start_code.html Finds the position of the next H.264 start code (00 00 01) in a byte slice, starting from a specified offset. ```APIDOC ## find_start_code ### Description Find the position of the next start code (00 00 01) at or after `from`. ### Function Signature ```rust pub fn find_start_code(data: &[u8], from: usize) -> Option ``` ### Parameters * `data` (&[u8]): The byte slice to search within. * `from` (usize): The starting index for the search. ### Returns * `Option`: `Some(index)` if a start code is found, where `index` is the starting position of the start code. `None` if no start code is found at or after `from`. ``` -------------------------------- ### Load and Verify Host Certificate from KeyDB Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/aacs/handshake.rs.html Loads the Key Database from a specified path and verifies the host certificate. Skips execution if the KEYDB_PATH environment variable is not set or the path does not exist. Prints verification status to stderr. ```rust #[test] fn test_verify_host_cert_from_keydb() { // Verify the host cert from our KEYDB let keydb_path = match std::env::var("KEYDB_PATH").ok() { Some(p) => std::path::PathBuf::from(p), None => return, // skip if KEYDB_PATH not set }; if !keydb_path.exists() { return; } let db = crate::aacs::KeyDb::load(&keydb_path).unwrap(); if let Some(hc) = db.host_certs.first() { let valid = verify_cert(&hc.certificate); eprintln!( "Host cert verification: {}", if valid { "PASS" } else { "FAIL" } ); // Note: our cert is revoked but should still have valid LA signature // If it doesn't verify, the LA public key might be wrong if !valid { eprintln!(" (cert may use different LA key or format)"); } } } } ``` -------------------------------- ### GET CONFIGURATION (Feature 0x010C) Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/scsi/mod.rs.html Sends a GET CONFIGURATION command specifically requesting feature 0x010C, which corresponds to Firmware Information. ```APIDOC ## get_config_010c ### Description Sends GET CONFIGURATION for feature 0x010C (Firmware Information). ### Function Signature `pub fn get_config_010c(scsi: &mut dyn ScsiTransport) -> Result>` ### Parameters - **scsi** (`&mut dyn ScsiTransport`): A mutable reference to a SCSI transport implementation. ### Returns - `Result>`: A vector containing the raw response data for the firmware information. ``` -------------------------------- ### is_ready Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/drive/struct.Drive.html Checks if the drive is currently ready. ```APIDOC ## is_ready ### Description Check if the drive is ready. ### Method `&self` ### Parameters None ### Response - `bool`: True if the drive is ready, false otherwise. ``` -------------------------------- ### Perform GET CONFIGURATION (0x010C) Command Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/scsi/mod.rs.html Sends a SCSI GET CONFIGURATION command for feature 0x010C (Firmware Information) and returns the raw response data. ```rust /// Send GET CONFIGURATION for feature 0x010C (Firmware Information). pub fn get_config_010c(scsi: &mut dyn ScsiTransport) -> Result> { let cdb = [ SCSI_GET_CONFIGURATION, 0x02, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, ]; let mut buf = [0u8; 16]; scsi.execute(&cdb, DataDirection::FromDevice, &mut buf, 5_000)?; Ok(buf.to_vec()) } ``` -------------------------------- ### HTTP GET Request Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/keydb.rs.html Performs an HTTP GET request to retrieve data from a URL using raw TCP. It handles redirects and checks for a 200 OK status. ```rust fn http_get(url: &str) -> Result> { let (mut host, mut port, mut path) = parse_url(url)?; for _ in 0..5 { let addr = format!("{host}:{port}"); let mut stream = TcpStream::connect(&addr).map_err(|_| Error::KeydbConnect { host: host.clone() })?; stream .set_read_timeout(Some(std::time::Duration::from_secs(30))) .ok(); let request = format!( "GET {path} HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\nAccept-Encoding: identity\r\n\r\n" ); stream .write_all(request.as_bytes()) .map_err(|_| Error::KeydbConnect { host: host.clone() })?; let mut response = Vec::new(); stream .take(100 * 1024 * 1024) .read_to_end(&mut response) .map_err(|_| Error::KeydbConnect { host: host.clone() })?; let header_end = find_header_end(&response).ok_or(Error::KeydbParse)?; let headers = std::str::from_utf8(&response[..header_end]).unwrap_or(""); let body = &response[header_end + 4..]; if let Some(location) = extract_header(headers, "Location") { let parsed = parse_url(&location)?; host = parsed.0; port = parsed.1; path = parsed.2; continue; } let status = parse_status(headers); if status != 200 { return Err(Error::KeydbHttp { status }); } return Ok(body.to_vec()); } Err(Error::KeydbHttp { status: 302 }) } ``` -------------------------------- ### Open Drive and Identify Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/drive/mod.rs.html Opens a device, identifies the drive using its ID, and attempts to load a profile. This is the first step in interacting with a drive. ```rust pub fn open(device: &Path) -> Result { let mut transport = crate::scsi::open(device)?; let profiles = profile::load_bundled()?; let drive_id = DriveId::from_drive(transport.as_mut())?; let m = profile::find_by_drive_id(&profiles, &drive_id); let (driver, platform, profile) = match m { Some(m) => ( create_driver(m.platform, &m.profile).ok(), Some(m.platform), Some(m.profile), ), None => (None, None, None), }; Ok(Drive { scsi: transport, driver, platform, profile, drive_id, device_path: device.to_string_lossy().to_string(), recovery_bytes_remaining: 0, }) } ``` -------------------------------- ### Getting File Metadata with and_then Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/error/type.Result.html Demonstrates using `and_then` to chain file system operations, such as getting metadata and then its modification time. Handles potential errors like 'NotFound'. ```rust use std::{io::ErrorKind, path::Path}; // Note: on Windows "/" maps to "C:\\" let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); assert!(root_modified_time.is_ok()); let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); assert!(should_fail.is_err()); assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); ``` -------------------------------- ### ScanOptions with_keydb Constructor Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/disc/struct.ScanOptions.html Creates a new ScanOptions instance with a specified path to the KEYDB.cfg file. ```rust pub fn with_keydb(path: impl Into) -> Self ``` -------------------------------- ### Initialize Drive (Unlock + Firmware Upload) Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/drive/mod.rs.html Initializes the drive, which may include unlocking and uploading firmware. This operation is optional and can enable features like removing riplock and enabling UHD reads. ```rust pub fn init(&mut self) -> Result<()> { match self.driver { Some(ref mut d) => d.init(self.scsi.as_mut()), None => Err(Error::UnsupportedDrive { vendor_id: self.drive_id.vendor_id.trim().to_string(), product_id: self.drive_id.product_id.trim().to_string(), product_revision: self.drive_id.product_revision.trim().to_string(), }), } } ``` -------------------------------- ### VC1 Parser: Frame Data Starts at Frame SC Source: https://docs.rs/libfreemkv/0.10.10/src/libfreemkv/mux/codec/vc1.rs.html Verifies that the frame data extracted by the VC1 parser begins with the frame start code (00 00 01 0D). ```rust let mut parser = Vc1Parser::new(); let data = build_vc1_iframe_pes(); let pes = make_pes(data.clone(), Some(0)); let frames = parser.parse(&pes); assert_eq!(frames.len(), 1); // Frame data should start with the frame start code (00 00 01 0D) assert!(frames[0].data.len() >= 4); assert_eq!(&frames[0].data[0..4], &[0x00, 0x00, 0x01, SC_FRAME]); ``` -------------------------------- ### libfreemkv Architecture Overview Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/index.html Provides a high-level overview of the libfreemkv architecture, detailing the components involved in drive interaction and disc parsing. This is for informational purposes and does not contain executable code. ```text Drive -- open, identify, unlock, read sectors ├── ScsiTransport -- SG_IO (Linux), IOKit (macOS) ├── DriveProfile -- per-drive unlock parameters (206 bundled) ├── DriveId -- INQUIRY + GET_CONFIG identification └── Platform └── Mt1959 -- MediaTek unlock/read (Renesas planned) Disc -- scan titles, streams, AACS state ├── UDF reader -- Blu-ray UDF 2.50 with metadata partitions ├── MPLS parser -- playlists → titles + clips + STN streams ├── CLPI parser -- clip info → EP map → sector extents ├── JAR parser -- BD-J audio track labels └── AACS -- encryption: key resolution + content decrypt ├── aacs -- KEYDB, VUK, MKB, unit decrypt └── handshake -- SCSI auth, ECDH, bus key ``` -------------------------------- ### H.264 Skip Start Code Function Signature Source: https://docs.rs/libfreemkv/0.10.10/libfreemkv/mux/codec/h264/fn.skip_start_code.html This snippet shows the function signature for skip_start_code. It takes a byte slice and a position, returning the position after the start code or None if not found. ```rust pub fn skip_start_code(data: &[u8], pos: usize) -> Option ```