diff --git a/Cargo.lock b/Cargo.lock index d9c7aac92..b9b4499b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1368,6 +1368,7 @@ dependencies = [ "console", "linked-hash-map", "once_cell", + "regex", "similar", ] @@ -2627,8 +2628,11 @@ dependencies = [ "bytes", "crossbeam-channel", "ffmpeg-sys-next", + "insta", "libc", + "rand", "scuffle-workspace-hack", + "tempfile", "tokio", "tracing", ] @@ -2825,6 +2829,7 @@ dependencies = [ "futures-sink", "futures-util", "getrandom", + "insta", "itertools 0.12.1", "libc", "log", @@ -3080,12 +3085,13 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", diff --git a/Justfile b/Justfile index ca1ea5e7e..87f2e957b 100644 --- a/Justfile +++ b/Justfile @@ -20,10 +20,10 @@ test *args: set -euo pipefail INSTA_FORCE_PASS=1 cargo +{{RUST_TOOLCHAIN}} llvm-cov clean --workspace - INSTA_FORCE_PASS=1 cargo +{{RUST_TOOLCHAIN}} llvm-cov nextest --include-build-script --no-report -- {{args}} + INSTA_FORCE_PASS=1 cargo +{{RUST_TOOLCHAIN}} llvm-cov nextest --include-build-script --no-report --all-features -- {{args}} # Coverage for doctests is currently broken in llvm-cov. # Once it fully works we can add the `--doctests` flag to the test and report command again. - cargo +{{RUST_TOOLCHAIN}} llvm-cov test --doc --no-report -- {{args}} + cargo +{{RUST_TOOLCHAIN}} llvm-cov test --doc --no-report --all-features -- {{args}} # Do not generate the coverage report on CI cargo insta review diff --git a/crates/av1/Cargo.toml b/crates/av1/Cargo.toml index e2e0adcc1..aa0fb9371 100644 --- a/crates/av1/Cargo.toml +++ b/crates/av1/Cargo.toml @@ -20,4 +20,4 @@ scuffle-bytes-util.workspace = true scuffle-workspace-hack.workspace = true [dev-dependencies] -insta = "1.2" +insta = "1.42" diff --git a/crates/bootstrap/Cargo.toml b/crates/bootstrap/Cargo.toml index 017520165..ca1ca6cea 100644 --- a/crates/bootstrap/Cargo.toml +++ b/crates/bootstrap/Cargo.toml @@ -24,7 +24,7 @@ scuffle-bootstrap-derive.workspace = true scuffle-workspace-hack.workspace = true [dev-dependencies] -insta = "1.42.0" +insta = "1.42" postcompile = { workspace = true, features = ["prettyplease"] } scuffle-future-ext.workspace = true scuffle-signal = { workspace = true, features = ["bootstrap"] } diff --git a/crates/bootstrap/derive/Cargo.toml b/crates/bootstrap/derive/Cargo.toml index 01294745e..2e94e4605 100644 --- a/crates/bootstrap/derive/Cargo.toml +++ b/crates/bootstrap/derive/Cargo.toml @@ -24,5 +24,5 @@ darling = "0.20" scuffle-workspace-hack.workspace = true [dev-dependencies] -insta = "1" +insta = "1.42" prettyplease = "0.2" diff --git a/crates/ffmpeg/Cargo.toml b/crates/ffmpeg/Cargo.toml index ff6af7edd..2c4825600 100644 --- a/crates/ffmpeg/Cargo.toml +++ b/crates/ffmpeg/Cargo.toml @@ -10,6 +10,9 @@ license = "MIT OR Apache-2.0" description = "FFmpeg bindings for Rust." keywords = ["ffmpeg", "video", "audio", "media"] +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] } + [dependencies] libc = "0.2" bytes = { optional = true, version = "1" } @@ -19,6 +22,11 @@ tracing = { optional = true, version = "0.1" } arc-swap = { version = "1.7" } ffmpeg-sys-next = { version = "7.1.0" } scuffle-workspace-hack.workspace = true +rand = "0.8" + +[dev-dependencies] +insta = {version = "1.42", features = ["filters"]} +tempfile = "3.15" [features] channel = ["dep:bytes"] diff --git a/crates/ffmpeg/src/dict.rs b/crates/ffmpeg/src/dict.rs index 3e38cdc3d..5755df350 100644 --- a/crates/ffmpeg/src/dict.rs +++ b/crates/ffmpeg/src/dict.rs @@ -126,6 +126,10 @@ impl Dictionary { } } + pub fn is_empty(&self) -> bool { + self.iter().next().is_none() + } + pub fn iter(&self) -> DictionaryIterator { DictionaryIterator::new(self) } diff --git a/crates/ffmpeg/src/io/channel.rs b/crates/ffmpeg/src/io/channel.rs index 909901f90..174db3ec2 100644 --- a/crates/ffmpeg/src/io/channel.rs +++ b/crates/ffmpeg/src/io/channel.rs @@ -11,8 +11,6 @@ pub struct ChannelCompat { /// not sure. FFmpeg might require the IO to be synchronized, but I do not /// think it does. inner: Arc>, - total: usize, - pkt_idx: usize, buffer: BytesMut, } @@ -20,8 +18,6 @@ impl ChannelCompat { pub fn new(inner: T) -> Self { Self { inner: Arc::new(Mutex::new(inner)), - total: 0, - pkt_idx: 0, buffer: BytesMut::new(), } } @@ -32,6 +28,8 @@ pub trait ChannelCompatRecv: Send { fn channel_recv(&mut self) -> Option; + fn try_channel_recv(&mut self) -> Option; + fn into_compat(self) -> ChannelCompat where Self: Sized, @@ -60,6 +58,10 @@ impl + Send> ChannelCompatRecv for tokio::sync::mpsc::Receiver fn channel_recv(&mut self) -> Option { self.blocking_recv() } + + fn try_channel_recv(&mut self) -> Option { + self.try_recv().ok() + } } #[cfg(feature = "tokio-channel")] @@ -78,6 +80,10 @@ impl + Send> ChannelCompatRecv for tokio::sync::mpsc::UnboundedRe fn channel_recv(&mut self) -> Option { self.blocking_recv() } + + fn try_channel_recv(&mut self) -> Option { + self.try_recv().ok() + } } #[cfg(feature = "tokio-channel")] @@ -96,6 +102,10 @@ impl + Clone + Send> ChannelCompatRecv for tokio::sync::broadcast fn channel_recv(&mut self) -> Option { self.blocking_recv().ok() } + + fn try_channel_recv(&mut self) -> Option { + self.try_recv().ok() + } } #[cfg(feature = "tokio-channel")] @@ -114,6 +124,10 @@ impl + Send> ChannelCompatRecv for crossbeam_channel::Receiver fn channel_recv(&mut self) -> Option { self.recv().ok() } + + fn try_channel_recv(&mut self) -> Option { + self.try_recv().ok() + } } #[cfg(feature = "crossbeam-channel")] @@ -131,6 +145,10 @@ impl + Send> ChannelCompatRecv for std::sync::mpsc::Receiver { fn channel_recv(&mut self) -> Option { self.recv().ok() } + + fn try_channel_recv(&mut self) -> Option { + self.try_recv().ok() + } } impl> + Send> ChannelCompatSend for std::sync::mpsc::Sender { @@ -141,30 +159,51 @@ impl> + Send> ChannelCompatSend for std::sync::mpsc::Sender { } } +impl> + Send> ChannelCompatSend for std::sync::mpsc::SyncSender { + type Data = D; + + fn channel_send(&mut self, data: Self::Data) -> bool { + self.send(data).is_ok() + } +} + impl std::io::Read for ChannelCompat { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + if self.buffer.len() >= buf.len() { + buf.copy_from_slice(&self.buffer[..buf.len()]); + self.buffer.advance(buf.len()); + return Ok(buf.len()); + } + + let mut inner = self.inner.lock().unwrap(); + + let mut total_read = 0; if self.buffer.is_empty() { - let data = match self.inner.lock().unwrap().channel_recv() { - Some(data) => data, - None => return Ok(0), + let Some(data) = inner.channel_recv() else { + return Ok(0); }; - let data = data.as_ref(); - self.pkt_idx += 1; - self.total += data.len(); + let data = data.as_ref(); + let min = data.len().min(buf.len()); - let min = std::cmp::min(buf.len(), data.len()); - buf[..min].copy_from_slice(&data[..min]); - if min < data.len() { - self.buffer.extend_from_slice(&data[min..]); - } - Ok(min) + buf.copy_from_slice(&data[..min]); + self.buffer.extend_from_slice(&data[min..]); + total_read += min; } else { - let min = std::cmp::min(buf.len(), self.buffer.len()); - buf[..min].copy_from_slice(&self.buffer[..min]); - self.buffer.advance(min); - Ok(min) + buf[..self.buffer.len()].copy_from_slice(&self.buffer); + total_read += self.buffer.len(); + self.buffer.clear(); + } + + while let Some(Some(data)) = (total_read < buf.len()).then(|| inner.try_channel_recv()) { + let data = data.as_ref(); + let min = data.len().min(buf.len() - total_read); + buf[total_read..total_read + min].copy_from_slice(&data[..min]); + self.buffer.extend_from_slice(&data[min..]); + total_read += min; } + + Ok(total_read) } } @@ -181,3 +220,460 @@ impl std::io::Write for ChannelCompat { Ok(()) } } + +#[cfg(test)] +#[cfg_attr(all(test, coverage_nightly), coverage(off))] +mod tests { + use std::io::{Read, Write}; + + use rand::distributions::Standard; + use rand::{thread_rng, Rng}; + + use crate::io::channel::{ChannelCompat, ChannelCompatRecv, ChannelCompatSend}; + + macro_rules! make_test { + ( + $( + $( + #[variant($name:ident, $channel:expr$(, cfg($($cfg_meta:meta)*))?)] + )* + |$tx:ident, $rx:ident| $body:block + )* + ) => { + $( + $( + #[test] + $(#[cfg($($cfg_meta)*)])? + fn $name() { + let ($tx, $rx) = $channel; + $body + } + )* + )* + }; + } + + // test 1000 byte read + make_test! { + #[variant( + test_read_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_read_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_read_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut reader = rx.into_compat(); + + // generate 1000 bytes of random data + let mut rng = thread_rng(); + let data: Vec = (0..1000).map(|_| rng.sample(Standard)).collect(); + + let mut tx = tx; + let write_result = tx.channel_send(data.clone()); + assert!(write_result); + + // read 1000 bytes + let mut buffer = vec![0u8; 1000]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok()); + assert_eq!(read_result.unwrap(), data.len()); + + // data read must match data written + assert_eq!(buffer, data); + } + } + + // test 1000 byte write + make_test! { + #[variant( + test_write_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_write_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_write_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_write_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_write_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_write_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut writer = tx.into_compat(); + + // generate 1000 bytes of random data + let mut rng = thread_rng(); + let data: Vec = (0..1000).map(|_| rng.sample(Standard)).collect(); + + let write_result = writer.write(&data); + assert!(write_result.is_ok(), "Failed to write data to the channel"); + assert_eq!(write_result.unwrap(), data.len(), "Written byte count mismatch"); + + // read 1000 bytes + let mut rx = rx; + let read_result = rx.channel_recv(); + assert!(read_result.is_some(), "No data received from the channel"); + + let received_data = read_result.unwrap(); + assert_eq!(received_data.len(), data.len(), "Received byte count mismatch"); + + // data read must match data written + assert_eq!( + received_data, data, + "Mismatch between written data and received data" + ); + } + } + + // test read with smaller buffer than data + make_test! { + #[variant( + test_read_smaller_buffer_than_data_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_read_smaller_buffer_than_data_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_read_smaller_buffer_than_data_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_smaller_buffer_than_data_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_smaller_buffer_than_data_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_smaller_buffer_than_data_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut reader = ChannelCompat::new(rx); + let data = b"PartialReadTest".to_vec(); + let mut tx = tx; + let send_result = tx.channel_send(data); + assert!(send_result); + + let mut buffer = vec![0u8; 7]; // buffer.len() < data.len() + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok()); + assert_eq!(read_result.unwrap(), buffer.len()); + assert_eq!(&buffer, b"Partial"); + + // Read the remaining part of the data + let mut buffer = vec![0u8; 8]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok()); + assert_eq!(read_result.unwrap(), buffer.len()); + assert_eq!(&buffer, b"ReadTest"); + } + } + + // test read with no data + make_test! { + #[variant( + test_read_no_data_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_read_no_data_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_read_no_data_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_no_data_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_no_data_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_no_data_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut reader = ChannelCompat::new(rx); + + // no data is sent to the channel + drop tx to prevent it from blocking + drop(tx); + let mut buffer = vec![0u8; 10]; + let read_result = reader.read(&mut buffer); + + assert!(read_result.is_ok()); + assert_eq!(read_result.unwrap(), 0); + } + } + + // test read non-empty buffer after initial read to catch else + make_test! { + #[variant( + test_read_else_case_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_read_else_case_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_read_else_case_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_else_case_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_else_case_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_else_case_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut reader = ChannelCompat::new(rx); + let mut tx = tx; + + let data1 = b"FirstChunk".to_vec(); + let write_result1 = tx.channel_send(data1); + assert!(write_result1, "Failed to send data1"); + + // read the first part of the data ("First") + let mut buffer = vec![0u8; 5]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok(), "Failed to read the first chunk"); + let bytes_read = read_result.unwrap(); + assert_eq!(bytes_read, buffer.len(), "Mismatch in first chunk read size"); + assert_eq!(&buffer, b"First", "Buffer content mismatch for first part of FirstChunk"); + + // read the remaining part of data1 ("Chunk") and part of data2 which hasn't been written yet ("Secon") + let mut buffer = vec![0u8; 10]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok(), "Failed to read the next 10 bytes"); + let bytes_read = read_result.unwrap(); + + // validate that the buffer contains "Chunk" at this point + assert_eq!(bytes_read, 5, "Unexpected read size for the next part"); + assert_eq!(&buffer[..bytes_read], b"Chunk", "Buffer content mismatch for combined reads"); + + // Write second chunk of data ("SecondChunk") + let data2 = b"SecondChunk".to_vec(); + let write_result2 = tx.channel_send(data2); + assert!(write_result2, "Failed to send data2"); + + // verify that there's leftover data from data2 + let mut buffer = vec![0u8; 5]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok(), "Failed to read leftover data from data2"); + let bytes_read = read_result.unwrap(); + assert!(bytes_read > 0, "No leftover data from data2 was available"); + } + } + + // test read to hit the while loop + make_test! { + #[variant( + test_read_while_case_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_read_while_case_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_read_while_case_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_while_case_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_while_case_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_read_while_case_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut reader = ChannelCompat::new(rx); + let mut tx = tx; + + let data1 = b"FirstChunk".to_vec(); + let write_result1 = tx.channel_send(data1); + assert!(write_result1, "Failed to send data1"); + + // read "First" + let mut buffer = vec![0u8; 5]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok(), "Failed to read the first chunk"); + let bytes_read = read_result.unwrap(); + assert_eq!(bytes_read, buffer.len(), "Mismatch in first chunk read size"); + assert_eq!(&buffer, b"First", "Buffer content mismatch for first part of FirstChunk"); + + // write "SecondChunk" + let data2 = b"SecondChunk".to_vec(); + let write_result2 = tx.channel_send(data2); + assert!(write_result2, "Failed to send data2"); + + // read "ChunkSecon" + let mut buffer = vec![0u8; 10]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok(), "Failed to read the next chunk of data"); + let bytes_read = read_result.unwrap(); + assert!(bytes_read > 0, "No data was read"); + assert_eq!(&buffer[..bytes_read], b"ChunkSecon", "Buffer content mismatch"); + + // continue reading to enter the while loop + let mut buffer = vec![0u8; 6]; + let read_result = reader.read(&mut buffer); + assert!(read_result.is_ok(), "Failed to read remaining data"); + let bytes_read = read_result.unwrap(); + assert!(bytes_read > 0, "No additional data was read"); + assert_eq!(&buffer[..bytes_read], b"dChunk", "Buffer content mismatch for remaining data"); + } + } + + // test write return ErrorKind::UnexpectedEof + make_test! { + #[variant( + test_write_eof_error_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_write_eof_error_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_write_eof_error_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_write_eof_error_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_write_eof_error_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_write_eof_error_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, rx| { + let mut writer = ChannelCompat::new(tx); + + // simulate sending failure by dropping the receiver + drop(rx); + + let data = vec![42u8; 100]; + let write_result = writer.write(&data); + assert!(write_result.is_err()); + assert_eq!(write_result.unwrap_err().kind(), std::io::ErrorKind::UnexpectedEof); + } + } + + // test write flush + make_test! { + #[variant( + test_flush_std_mpsc, + std::sync::mpsc::channel::>() + )] + #[variant( + test_flush_std_sync_mpsc, + std::sync::mpsc::sync_channel::>(1) + )] + #[variant( + test_flush_tokio_mpsc, + tokio::sync::mpsc::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_flush_tokio_unbounded, + tokio::sync::mpsc::unbounded_channel::>(), + cfg(feature = "tokio-channel") + )] + #[variant( + test_flush_tokio_broadcast, + tokio::sync::broadcast::channel::>(1), + cfg(feature = "tokio-channel") + )] + #[variant( + test_flush_crossbeam_unbounded, + crossbeam_channel::unbounded::>(), + cfg(feature = "crossbeam-channel") + )] + |tx, _rx| { + let mut writer = ChannelCompat::new(tx); + + let flush_result = writer.flush(); + assert!(flush_result.is_ok()); + } + } +} diff --git a/crates/ffmpeg/src/io/input.rs b/crates/ffmpeg/src/io/input.rs index dacf68276..8778573e1 100644 --- a/crates/ffmpeg/src/io/input.rs +++ b/crates/ffmpeg/src/io/input.rs @@ -146,3 +146,322 @@ impl Input<()> { Self::create_input(inner, Some(&std::ffi::CString::new(path).unwrap()), &mut Dictionary::new()) } } + +#[cfg(test)] +#[cfg_attr(all(test, coverage_nightly), coverage(off))] +mod tests { + use std::io::Cursor; + + use insta::Settings; + + use super::{FfmpegError, Input, InputOptions, DEFAULT_BUFFER_SIZE}; + + fn configure_insta_filters(settings: &mut Settings) { + settings.add_filter(r"0x0000000000000000", "[NULL_POINTER]"); + settings.add_filter(r"0x[0-9a-f]{16}", "[NON_NULL_POINTER]"); + } + + #[test] + fn test_input_options_default() { + let default_options = InputOptions::default(); + + assert_eq!(default_options.buffer_size, DEFAULT_BUFFER_SIZE); + assert!(default_options.dictionary.is_empty()); + assert!(default_options.interrupt_callback.is_none()); + } + + #[test] + fn test_open_valid_file() { + let valid_file_path = "../../assets/avc_aac_large.mp4"; + assert!(std::path::Path::new(valid_file_path).exists(), "Test file does not exist"); + + let result = Input::open(valid_file_path); + assert!(result.is_ok(), "Expected success but got error"); + } + + #[test] + fn test_open_invalid_path() { + let invalid_path = "invalid_file.mp4"; + let result = Input::open(invalid_path); + assert!(result.is_err(), "Expected an error for invalid path"); + if let Err(err) = result { + match err { + FfmpegError::Code(_) => (), + _ => panic!("Unexpected error type: {:?}", err), + } + } + } + + #[test] + fn test_new_with_default_options() { + let valid_media_data: Vec = include_bytes!("../../../../assets/avc_aac_large.mp4").to_vec(); + let data = Cursor::new(valid_media_data); + let result = Input::new(data); + + if let Err(e) = &result { + eprintln!("Error encountered: {:?}", e); + } + + assert!(result.is_ok(), "Expected success but got error"); + } + + #[test] + fn test_seekable_with_valid_input() { + let valid_media_data: Vec = include_bytes!("../../../../assets/avc_aac_large.mp4").to_vec(); + let data = Cursor::new(valid_media_data); + let result = Input::seekable(data); + + if let Err(e) = &result { + eprintln!("Error encountered: {:?}", e); + } + + assert!(result.is_ok(), "Expected success but got error"); + } + + #[test] + fn test_as_ptr() { + let valid_file_path = "../../assets/avc_aac_large.mp4"; + let input = Input::open(valid_file_path).expect("Failed to open valid file"); + + let ptr = input.as_ptr(); + assert!(!ptr.is_null(), "Expected non-null pointer"); + } + + #[test] + fn test_as_mut_ptr() { + let valid_file_path = "../../assets/avc_aac_large.mp4"; + let mut input = Input::open(valid_file_path).expect("Failed to open valid file"); + + let ptr = input.as_mut_ptr(); + assert!(!ptr.is_null(), "Expected non-null mutable pointer"); + } + + #[test] + fn test_streams() { + let valid_file_path = "../../assets/avc_aac_large.mp4"; + let input = Input::open(valid_file_path).expect("Failed to open valid file"); + let streams = input.streams(); + + assert!(!streams.is_empty(), "Expected at least one stream"); + + let mut settings = Settings::new(); + configure_insta_filters(&mut settings); + + settings.bind(|| { + insta::assert_debug_snapshot!(streams, @r" + Streams { + input: AVFormatContext { + av_class: [NON_NULL_POINTER], + iformat: [NON_NULL_POINTER], + oformat: [NULL_POINTER], + priv_data: [NON_NULL_POINTER], + pb: [NON_NULL_POINTER], + ctx_flags: 0, + nb_streams: 2, + streams: [NON_NULL_POINTER], + nb_stream_groups: 0, + stream_groups: [NULL_POINTER], + nb_chapters: 0, + chapters: [NULL_POINTER], + url: [NON_NULL_POINTER], + start_time: 0, + duration: 1066667, + bit_rate: 1900416, + packet_size: 0, + max_delay: -1, + flags: 2097152, + probesize: 5000000, + max_analyze_duration: 0, + key: [NULL_POINTER], + keylen: 0, + nb_programs: 0, + programs: [NULL_POINTER], + video_codec_id: AV_CODEC_ID_NONE, + audio_codec_id: AV_CODEC_ID_NONE, + subtitle_codec_id: AV_CODEC_ID_NONE, + data_codec_id: AV_CODEC_ID_NONE, + metadata: [NON_NULL_POINTER], + start_time_realtime: -9223372036854775808, + fps_probe_size: -1, + error_recognition: 1, + interrupt_callback: AVIOInterruptCB { + callback: None, + opaque: [NULL_POINTER], + }, + debug: 0, + max_streams: 1000, + max_index_size: 1048576, + max_picture_buffer: 3041280, + max_interleave_delta: 10000000, + max_ts_probe: 50, + max_chunk_duration: 0, + max_chunk_size: 0, + max_probe_packets: 2500, + strict_std_compliance: 0, + event_flags: 1, + avoid_negative_ts: -1, + audio_preload: 0, + use_wallclock_as_timestamps: 0, + skip_estimate_duration_from_pts: 0, + avio_flags: 0, + duration_estimation_method: AVFMT_DURATION_FROM_STREAM, + skip_initial_bytes: 0, + correct_ts_overflow: 1, + seek2any: 0, + flush_packets: -1, + probe_score: 100, + format_probesize: 1048576, + codec_whitelist: [NULL_POINTER], + format_whitelist: [NULL_POINTER], + protocol_whitelist: [NON_NULL_POINTER], + protocol_blacklist: [NULL_POINTER], + io_repositioned: 0, + video_codec: [NULL_POINTER], + audio_codec: [NULL_POINTER], + subtitle_codec: [NULL_POINTER], + data_codec: [NULL_POINTER], + metadata_header_padding: -1, + opaque: [NULL_POINTER], + control_message_cb: None, + output_ts_offset: 0, + dump_separator: [NON_NULL_POINTER], + io_open: Some( + [NON_NULL_POINTER], + ), + io_close2: Some( + [NON_NULL_POINTER], + ), + duration_probesize: 0, + }, + } + "); + }); + } + + #[test] + fn test_packets() { + let valid_file_path = "../../assets/avc_aac_large.mp4"; + let mut input = Input::open(valid_file_path).expect("Failed to open valid file"); + let mut packets = input.packets(); + + for _ in 0..5 { + match packets.next() { + Some(Ok(_)) => (), + Some(Err(e)) => panic!("Error encountered while reading packets: {:?}", e), + None => break, + } + } + + let mut settings = insta::Settings::new(); + configure_insta_filters(&mut settings); + + settings.bind(|| { + insta::assert_debug_snapshot!(packets, @r" + Packets { + context: AVFormatContext { + av_class: [NON_NULL_POINTER], + iformat: [NON_NULL_POINTER], + oformat: [NULL_POINTER], + priv_data: [NON_NULL_POINTER], + pb: [NON_NULL_POINTER], + ctx_flags: 0, + nb_streams: 2, + streams: [NON_NULL_POINTER], + nb_stream_groups: 0, + stream_groups: [NULL_POINTER], + nb_chapters: 0, + chapters: [NULL_POINTER], + url: [NON_NULL_POINTER], + start_time: 0, + duration: 1066667, + bit_rate: 1900416, + packet_size: 0, + max_delay: -1, + flags: 2097152, + probesize: 5000000, + max_analyze_duration: 0, + key: [NULL_POINTER], + keylen: 0, + nb_programs: 0, + programs: [NULL_POINTER], + video_codec_id: AV_CODEC_ID_NONE, + audio_codec_id: AV_CODEC_ID_NONE, + subtitle_codec_id: AV_CODEC_ID_NONE, + data_codec_id: AV_CODEC_ID_NONE, + metadata: [NON_NULL_POINTER], + start_time_realtime: -9223372036854775808, + fps_probe_size: -1, + error_recognition: 1, + interrupt_callback: AVIOInterruptCB { + callback: None, + opaque: [NULL_POINTER], + }, + debug: 0, + max_streams: 1000, + max_index_size: 1048576, + max_picture_buffer: 3041280, + max_interleave_delta: 10000000, + max_ts_probe: 50, + max_chunk_duration: 0, + max_chunk_size: 0, + max_probe_packets: 2500, + strict_std_compliance: 0, + event_flags: 1, + avoid_negative_ts: -1, + audio_preload: 0, + use_wallclock_as_timestamps: 0, + skip_estimate_duration_from_pts: 0, + avio_flags: 0, + duration_estimation_method: AVFMT_DURATION_FROM_STREAM, + skip_initial_bytes: 0, + correct_ts_overflow: 1, + seek2any: 0, + flush_packets: -1, + probe_score: 100, + format_probesize: 1048576, + codec_whitelist: [NULL_POINTER], + format_whitelist: [NULL_POINTER], + protocol_whitelist: [NON_NULL_POINTER], + protocol_blacklist: [NULL_POINTER], + io_repositioned: 0, + video_codec: [NULL_POINTER], + audio_codec: [NULL_POINTER], + subtitle_codec: [NULL_POINTER], + data_codec: [NULL_POINTER], + metadata_header_padding: -1, + opaque: [NULL_POINTER], + control_message_cb: None, + output_ts_offset: 0, + dump_separator: [NON_NULL_POINTER], + io_open: Some( + [NON_NULL_POINTER], + ), + io_close2: Some( + [NON_NULL_POINTER], + ), + duration_probesize: 0, + }, + } + "); + }); + } + + #[test] + fn test_receive_packet() { + let valid_file_path = "../../assets/avc_aac_large.mp4"; + let mut input = Input::open(valid_file_path).expect("Failed to open valid file"); + + let mut packets = Vec::new(); + while let Ok(Some(packet)) = input.receive_packet() { + assert!(!packet.data().is_empty(), "Expected a non-empty packet"); + assert!(packet.stream_index() >= 0, "Expected a valid stream index"); + packets.push(packet); + } + + if packets.is_empty() { + panic!("Expected at least one packet but received none"); + } + + insta::assert_debug_snapshot!(packets); + } +} diff --git a/crates/ffmpeg/src/io/internal.rs b/crates/ffmpeg/src/io/internal.rs index a9b875458..f5201de85 100644 --- a/crates/ffmpeg/src/io/internal.rs +++ b/crates/ffmpeg/src/io/internal.rs @@ -259,3 +259,160 @@ impl Inner<()> { Ok(this) } } + +#[cfg(test)] +#[cfg_attr(all(test, coverage_nightly), coverage(off))] +mod tests { + use std::ffi::CString; + use std::io::Cursor; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::Once; + + use ffmpeg_sys_next::{av_guess_format, AVSEEK_FORCE}; + use libc::{c_void, SEEK_CUR, SEEK_END}; + use tempfile::Builder; + + use crate::error::FfmpegError; + use crate::io::internal::{read_packet, seek, write_packet, Inner, InnerOptions, AVERROR_EOF}; + + #[test] + fn test_read_packet_eof() { + let mut data: Cursor> = Cursor::new(vec![]); + let mut buf = [0u8; 10]; + + unsafe { + let result = + read_packet::>>((&raw mut data) as *mut libc::c_void, buf.as_mut_ptr(), buf.len() as i32); + + assert_eq!(result, AVERROR_EOF); + } + } + + #[test] + fn test_write_packet_success() { + let mut data = Cursor::new(vec![0u8; 10]); + let buf = [1u8, 2, 3, 4, 5]; + + unsafe { + let result = write_packet::>>((&raw mut data) as *mut c_void, buf.as_ptr(), buf.len() as i32); + assert_eq!(result, buf.len() as i32); + + let written_data = data.get_ref(); + assert_eq!(&written_data[..buf.len()], &buf); + } + } + + #[test] + fn test_seek_force() { + let mut cursor = Cursor::new(vec![0u8; 100]); + let opaque = &raw mut cursor as *mut c_void; + assert_eq!(cursor.position(), 0); + let offset = 10; + let mut whence = SEEK_CUR | AVSEEK_FORCE; + let result = unsafe { seek::>>(opaque, offset, whence) }; + + assert_eq!(result, { offset }); + whence &= !AVSEEK_FORCE; + assert_eq!(whence, SEEK_CUR); + assert_eq!(cursor.position(), offset as u64); + } + + #[test] + fn test_seek_seek_end() { + let mut cursor = Cursor::new(vec![0u8; 100]); + let opaque = &raw mut cursor as *mut libc::c_void; + let offset = -10; + let whence = SEEK_END; + let result = unsafe { seek::>>(opaque, offset, whence) }; + + assert_eq!(result, 90); + assert_eq!(cursor.position(), 90); + } + + #[test] + fn test_seek_invalid_whence() { + let mut cursor = Cursor::new(vec![0u8; 100]); + let opaque = &raw mut cursor as *mut libc::c_void; + let result = unsafe { seek::>>(opaque, 0, 999) }; + + assert_eq!(result, -1); + assert_eq!(cursor.position(), 0); + } + + #[test] + fn test_avformat_alloc_output_context2_error() { + static BUF_SIZE_TRACKER: AtomicUsize = AtomicUsize::new(0); + static CALL_COUNT: AtomicUsize = AtomicUsize::new(0); + static INIT: Once = Once::new(); + + INIT.call_once(|| { + BUF_SIZE_TRACKER.store(0, Ordering::SeqCst); + CALL_COUNT.store(0, Ordering::SeqCst); + }); + + unsafe extern "C" fn dummy_write_fn(_opaque: *mut libc::c_void, _buf: *const u8, _buf_size: i32) -> i32 { + CALL_COUNT.fetch_add(1, Ordering::SeqCst); + BUF_SIZE_TRACKER.store(_buf_size as usize, Ordering::SeqCst); + 0 // simulate success + } + + let invalid_format = CString::new("invalid_format").expect("Failed to create CString"); + let options = InnerOptions { + buffer_size: 4096, + write_fn: Some(dummy_write_fn), + output_format: unsafe { av_guess_format(invalid_format.as_ptr(), std::ptr::null(), std::ptr::null()) }, + ..Default::default() + }; + let data = (); + let result = Inner::new(data, options); + + assert!(result.is_err(), "Expected an error but got Ok"); + + let call_count = CALL_COUNT.load(Ordering::SeqCst); + assert_eq!(call_count, 0, "Expected dummy_write_fn to not be called."); + + if let Err(error) = result { + match error { + FfmpegError::Code(_) => { + eprintln!("Expected avformat_alloc_output_context2 error occurred."); + } + _ => panic!("Unexpected error variant: {:?}", error), + } + } + } + + #[test] + fn test_open_output_valid_path() { + let temp_file = Builder::new() + .suffix(".mp4") + .tempfile() + .expect("Failed to create a temporary file"); + let test_path = temp_file.path(); + let result = Inner::open_output(test_path.to_str().unwrap()); + + assert!(result.is_ok(), "Expected success but got error"); + } + + #[test] + fn test_open_output_invalid_path() { + let test_path = ""; + let result = Inner::open_output(test_path); + + assert!(result.is_err(), "Expected Err, got Ok"); + } + + #[test] + fn test_open_output_avformat_alloc_error() { + let test_path = tempfile::tempdir().unwrap().path().join("restricted_output.mp4"); + let test_path_str = test_path.to_str().unwrap(); + let result = Inner::open_output(test_path_str); + if let Err(error) = &result { + eprintln!("Function returned an error: {:?}", error); + } + + assert!( + matches!(result, Err(FfmpegError::Code(_))), + "Expected FfmpegError::Code but received a different error." + ); + } +} diff --git a/crates/ffmpeg/src/io/output.rs b/crates/ffmpeg/src/io/output.rs index 11245819b..eac636dec 100644 --- a/crates/ffmpeg/src/io/output.rs +++ b/crates/ffmpeg/src/io/output.rs @@ -281,3 +281,224 @@ impl Output<()> { }) } } + +#[cfg(test)] +#[cfg_attr(all(test, coverage_nightly), coverage(off))] +mod tests { + use std::ffi::CString; + use std::io::Cursor; + use std::ptr; + + use tempfile::Builder; + + use crate::consts::DEFAULT_BUFFER_SIZE; + use crate::dict::Dictionary; + use crate::error::FfmpegError; + use crate::io::output::{AVCodec, AVRational, AVFMT_FLAG_AUTO_BSF}; + use crate::io::{Output, OutputOptions}; + + #[test] + fn test_output_options_default() { + let options = OutputOptions::default(); + + assert_eq!(options.buffer_size, DEFAULT_BUFFER_SIZE); + assert!(options.format_name.is_none()); + assert!(options.format_mime_type.is_none()); + assert!(options.format_ffi.is_null()); + } + + #[test] + fn test_output_options_new() { + let options = OutputOptions::new(); + + assert_eq!(options.buffer_size, DEFAULT_BUFFER_SIZE); + assert!(options.format_name.is_none()); + assert!(options.format_mime_type.is_none()); + assert!(options.format_ffi.is_null()); + } + + #[test] + fn test_output_options_custom_values() { + let options = OutputOptions::default() + .buffer_size(4096) + .format_name("mp4") + .format_mime_type("video/mp4"); + + assert_eq!(options.buffer_size, 4096); + assert_eq!(options.format_name, Some("mp4")); + assert_eq!(options.format_mime_type, Some("video/mp4")); + } + + #[test] + fn test_output_options_get_format_ffi() { + let options = OutputOptions::default().format_name("mp4"); + let format_ffi = options.get_format_ffi(); + assert!(format_ffi.is_ok()); + assert!(!format_ffi.unwrap().is_null()); + } + + #[test] + fn test_output_options_get_format_ffi_null() { + let format_name = CString::new("mp4").unwrap(); + let format_mime_type = CString::new("").unwrap(); + let format_ptr = + unsafe { ffmpeg_sys_next::av_guess_format(format_name.as_ptr(), ptr::null(), format_mime_type.as_ptr()) }; + + assert!( + !format_ptr.is_null(), + "Failed to retrieve AVOutputFormat for the given format name" + ); + + let output_options = OutputOptions::new().format_ffi(format_ptr); + let result = output_options.get_format_ffi(); + + assert!(result.is_ok(), "Expected Ok result, got Err instead"); + assert_eq!( + result.unwrap(), + format_ptr, + "Expected format_ffi pointer to match the retrieved format" + ); + } + + #[test] + fn test_output_options_get_format_ffi_unset_error() { + let options = OutputOptions::default(); + let format_ffi = options.get_format_ffi(); + assert!(format_ffi.is_err()); + } + + #[test] + fn test_output_options_get_format_ffi_output_format_error() { + let options = OutputOptions::default().format_name("unknown_format"); + let format_ffi_result = options.get_format_ffi(); + + assert!(format_ffi_result.is_err()); + match format_ffi_result { + Err(FfmpegError::Arguments(msg)) => { + assert_eq!(msg, "could not determine output format"); + } + _ => panic!("Expected FfmpegError::Arguments"), + } + } + + #[test] + fn test_output_into_inner() { + let data = Cursor::new(Vec::with_capacity(1024)); + let options = OutputOptions::default().format_name("mp4"); + let output = Output::new(data, options).expect("Failed to create Output"); + let inner_data = output.into_inner(); + + assert!(inner_data.get_ref().is_empty()); + let buffer = inner_data.into_inner(); + assert_eq!(buffer.capacity(), 1024); + } + + #[test] + fn test_output_new() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let output = Output::new(data, options); + + assert!(output.is_ok()); + } + + #[test] + fn test_output_seekable() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let output = Output::seekable(data, options); + + assert!(output.is_ok()); + } + + #[test] + fn test_output_set_metadata() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let mut output = Output::new(data, options).unwrap(); + let metadata = Dictionary::new(); + output.set_metadata(metadata); + + assert!(!output.as_ptr().is_null()); + } + + #[test] + fn test_output_as_mut_ptr() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let mut output = Output::new(data, options).expect("Failed to create Output"); + let context_ptr = output.as_mut_ptr(); + + assert!(!context_ptr.is_null(), "Expected non-null pointer from as_mut_ptr"); + } + + #[test] + fn test_add_stream_with_valid_codec() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let mut output = Output::new(data, options).expect("Failed to create Output"); + let dummy_codec: *const AVCodec = 0x1234 as *const AVCodec; + let stream = output.add_stream(Some(dummy_codec)); + + assert!(stream.is_some(), "Expected a valid Stream to be added"); + } + + #[test] + fn test_copy_stream() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let mut output = Output::new(data, options).expect("Failed to create Output"); + + // create new output to prevent double mut borrow + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let mut output_two = Output::new(data, options).expect("Failed to create Output"); + + let dummy_codec: *const AVCodec = 0x1234 as *const AVCodec; + let mut source_stream = output.add_stream(Some(dummy_codec)).expect("Failed to add source stream"); + + source_stream.set_time_base(AVRational { num: 1, den: 25 }); + source_stream.set_start_time(Some(1000)); + source_stream.set_duration(Some(500)); + let copied_stream = output_two.copy_stream(&source_stream).expect("Failed to copy the stream"); + + assert_eq!(copied_stream.index(), source_stream.index(), "Stream indices should match"); + assert_eq!(copied_stream.id(), source_stream.id(), "Stream IDs should match"); + assert_eq!( + copied_stream.time_base(), + source_stream.time_base(), + "Time bases should match" + ); + assert_eq!( + copied_stream.start_time(), + source_stream.start_time(), + "Start times should match" + ); + assert_eq!(copied_stream.duration(), source_stream.duration(), "Durations should match"); + assert_eq!(copied_stream.duration(), source_stream.duration(), "Durations should match"); + assert!(!copied_stream.as_ptr().is_null(), "Copied stream pointer should not be null"); + } + + #[test] + fn test_output_flags() { + let data = Cursor::new(Vec::new()); + let options = OutputOptions::default().format_name("mp4"); + let output = Output::new(data, options).expect("Failed to create Output"); + let flags = output.flags(); + + assert_eq!(flags, AVFMT_FLAG_AUTO_BSF, "Expected default flag to be AVFMT_FLAG_AUTO_BSF"); + } + + #[test] + fn test_output_open() { + let temp_file = Builder::new() + .suffix(".mp4") + .tempfile() + .expect("Failed to create a temporary file"); + let temp_path = temp_file.path(); + let output = Output::open(temp_path.to_str().unwrap()); + + assert!(output.is_ok(), "Expected Output::open to succeed"); + std::fs::remove_file(temp_path).expect("Failed to remove temporary file"); + } +} diff --git a/crates/ffmpeg/src/io/snapshots/scuffle_ffmpeg__io__input__tests__receive_packet.snap b/crates/ffmpeg/src/io/snapshots/scuffle_ffmpeg__io__input__tests__receive_packet.snap new file mode 100644 index 000000000..18e87a865 --- /dev/null +++ b/crates/ffmpeg/src/io/snapshots/scuffle_ffmpeg__io__input__tests__receive_packet.snap @@ -0,0 +1,2246 @@ +--- +source: crates/ffmpeg/src/io/input.rs +expression: packets +--- +[ + Packet { + stream_index: 0, + pts: Some( + 0, + ), + dts: Some( + -512, + ), + duration: Some( + 256, + ), + pos: Some( + 48, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + -1024, + ), + dts: Some( + -1024, + ), + duration: Some( + 1024, + ), + pos: Some( + 2297, + ), + is_key: true, + is_corrupt: false, + is_discard: true, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 1024, + ), + dts: Some( + -256, + ), + duration: Some( + 256, + ), + pos: Some( + 2321, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 512, + ), + dts: Some( + 0, + ), + duration: Some( + 256, + ), + pos: Some( + 17488, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 0, + ), + dts: Some( + 0, + ), + duration: Some( + 1024, + ), + pos: Some( + 17726, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 256, + ), + dts: Some( + 256, + ), + duration: Some( + 256, + ), + pos: Some( + 17734, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 1024, + ), + dts: Some( + 1024, + ), + duration: Some( + 1024, + ), + pos: Some( + 17970, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 768, + ), + dts: Some( + 512, + ), + duration: Some( + 256, + ), + pos: Some( + 18273, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 2048, + ), + dts: Some( + 2048, + ), + duration: Some( + 1024, + ), + pos: Some( + 18511, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 1536, + ), + dts: Some( + 768, + ), + duration: Some( + 256, + ), + pos: Some( + 19141, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 3072, + ), + dts: Some( + 3072, + ), + duration: Some( + 1024, + ), + pos: Some( + 33603, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 1280, + ), + dts: Some( + 1024, + ), + duration: Some( + 256, + ), + pos: Some( + 34222, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 1792, + ), + dts: Some( + 1280, + ), + duration: Some( + 256, + ), + pos: Some( + 36301, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 4096, + ), + dts: Some( + 4096, + ), + duration: Some( + 1024, + ), + pos: Some( + 41671, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 2560, + ), + dts: Some( + 1536, + ), + duration: Some( + 256, + ), + pos: Some( + 42292, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 5120, + ), + dts: Some( + 5120, + ), + duration: Some( + 1024, + ), + pos: Some( + 56751, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 2048, + ), + dts: Some( + 1792, + ), + duration: Some( + 256, + ), + pos: Some( + 57382, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 6144, + ), + dts: Some( + 6144, + ), + duration: Some( + 1024, + ), + pos: Some( + 78216, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 2304, + ), + dts: Some( + 2048, + ), + duration: Some( + 256, + ), + pos: Some( + 78840, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 7168, + ), + dts: Some( + 7168, + ), + duration: Some( + 1024, + ), + pos: Some( + 81029, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 3072, + ), + dts: Some( + 2304, + ), + duration: Some( + 256, + ), + pos: Some( + 81639, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 2816, + ), + dts: Some( + 2560, + ), + duration: Some( + 256, + ), + pos: Some( + 94920, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 8192, + ), + dts: Some( + 8192, + ), + duration: Some( + 1024, + ), + pos: Some( + 97439, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 3584, + ), + dts: Some( + 2816, + ), + duration: Some( + 256, + ), + pos: Some( + 97885, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 9216, + ), + dts: Some( + 9216, + ), + duration: Some( + 1024, + ), + pos: Some( + 101680, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 3328, + ), + dts: Some( + 3072, + ), + duration: Some( + 256, + ), + pos: Some( + 102099, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 10240, + ), + dts: Some( + 10240, + ), + duration: Some( + 1024, + ), + pos: Some( + 103904, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 4608, + ), + dts: Some( + 3328, + ), + duration: Some( + 256, + ), + pos: Some( + 104321, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 4096, + ), + dts: Some( + 3584, + ), + duration: Some( + 256, + ), + pos: Some( + 107327, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 11264, + ), + dts: Some( + 11264, + ), + duration: Some( + 1024, + ), + pos: Some( + 108933, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 3840, + ), + dts: Some( + 3840, + ), + duration: Some( + 256, + ), + pos: Some( + 109343, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 12288, + ), + dts: Some( + 12288, + ), + duration: Some( + 1024, + ), + pos: Some( + 110358, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 4352, + ), + dts: Some( + 4096, + ), + duration: Some( + 256, + ), + pos: Some( + 110734, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 13312, + ), + dts: Some( + 13312, + ), + duration: Some( + 1024, + ), + pos: Some( + 111796, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 5632, + ), + dts: Some( + 4352, + ), + duration: Some( + 256, + ), + pos: Some( + 112156, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 14336, + ), + dts: Some( + 14336, + ), + duration: Some( + 1024, + ), + pos: Some( + 114002, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 5120, + ), + dts: Some( + 4608, + ), + duration: Some( + 256, + ), + pos: Some( + 114348, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 4864, + ), + dts: Some( + 4864, + ), + duration: Some( + 256, + ), + pos: Some( + 115448, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 15360, + ), + dts: Some( + 15360, + ), + duration: Some( + 1024, + ), + pos: Some( + 116280, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 5376, + ), + dts: Some( + 5120, + ), + duration: Some( + 256, + ), + pos: Some( + 116631, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 16384, + ), + dts: Some( + 16384, + ), + duration: Some( + 1024, + ), + pos: Some( + 117280, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 6656, + ), + dts: Some( + 5376, + ), + duration: Some( + 256, + ), + pos: Some( + 117632, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 17408, + ), + dts: Some( + 17408, + ), + duration: Some( + 1024, + ), + pos: Some( + 119824, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 6144, + ), + dts: Some( + 5632, + ), + duration: Some( + 256, + ), + pos: Some( + 120169, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 5888, + ), + dts: Some( + 5888, + ), + duration: Some( + 256, + ), + pos: Some( + 121218, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 18432, + ), + dts: Some( + 18432, + ), + duration: Some( + 1024, + ), + pos: Some( + 121911, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 6400, + ), + dts: Some( + 6144, + ), + duration: Some( + 256, + ), + pos: Some( + 122258, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 19456, + ), + dts: Some( + 19456, + ), + duration: Some( + 1024, + ), + pos: Some( + 123190, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 7424, + ), + dts: Some( + 6400, + ), + duration: Some( + 256, + ), + pos: Some( + 123531, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 20480, + ), + dts: Some( + 20480, + ), + duration: Some( + 1024, + ), + pos: Some( + 124746, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 6912, + ), + dts: Some( + 6656, + ), + duration: Some( + 256, + ), + pos: Some( + 125093, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 21504, + ), + dts: Some( + 21504, + ), + duration: Some( + 1024, + ), + pos: Some( + 126372, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 7168, + ), + dts: Some( + 6912, + ), + duration: Some( + 256, + ), + pos: Some( + 126730, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 7680, + ), + dts: Some( + 7168, + ), + duration: Some( + 256, + ), + pos: Some( + 127541, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 22528, + ), + dts: Some( + 22528, + ), + duration: Some( + 1024, + ), + pos: Some( + 174893, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 8704, + ), + dts: Some( + 7424, + ), + duration: Some( + 256, + ), + pos: Some( + 175224, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 23552, + ), + dts: Some( + 23552, + ), + duration: Some( + 1024, + ), + pos: Some( + 177659, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 8192, + ), + dts: Some( + 7680, + ), + duration: Some( + 256, + ), + pos: Some( + 177981, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 24576, + ), + dts: Some( + 24576, + ), + duration: Some( + 1024, + ), + pos: Some( + 179147, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 7936, + ), + dts: Some( + 7936, + ), + duration: Some( + 256, + ), + pos: Some( + 179508, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 8448, + ), + dts: Some( + 8192, + ), + duration: Some( + 256, + ), + pos: Some( + 180159, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 25600, + ), + dts: Some( + 25600, + ), + duration: Some( + 1024, + ), + pos: Some( + 180705, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 9728, + ), + dts: Some( + 8448, + ), + duration: Some( + 256, + ), + pos: Some( + 181059, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 26624, + ), + dts: Some( + 26624, + ), + duration: Some( + 1024, + ), + pos: Some( + 183595, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 9216, + ), + dts: Some( + 8704, + ), + duration: Some( + 256, + ), + pos: Some( + 183934, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 27648, + ), + dts: Some( + 27648, + ), + duration: Some( + 1024, + ), + pos: Some( + 184851, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 8960, + ), + dts: Some( + 8960, + ), + duration: Some( + 256, + ), + pos: Some( + 185199, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 28672, + ), + dts: Some( + 28672, + ), + duration: Some( + 1024, + ), + pos: Some( + 185874, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 9472, + ), + dts: Some( + 9216, + ), + duration: Some( + 256, + ), + pos: Some( + 186229, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 10752, + ), + dts: Some( + 9472, + ), + duration: Some( + 256, + ), + pos: Some( + 187042, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 29696, + ), + dts: Some( + 29696, + ), + duration: Some( + 1024, + ), + pos: Some( + 189026, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 10240, + ), + dts: Some( + 9728, + ), + duration: Some( + 256, + ), + pos: Some( + 189380, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 30720, + ), + dts: Some( + 30720, + ), + duration: Some( + 1024, + ), + pos: Some( + 190219, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 9984, + ), + dts: Some( + 9984, + ), + duration: Some( + 256, + ), + pos: Some( + 190589, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 31744, + ), + dts: Some( + 31744, + ), + duration: Some( + 1024, + ), + pos: Some( + 191351, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 10496, + ), + dts: Some( + 10240, + ), + duration: Some( + 256, + ), + pos: Some( + 191689, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 32768, + ), + dts: Some( + 32768, + ), + duration: Some( + 1024, + ), + pos: Some( + 192195, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 11776, + ), + dts: Some( + 10496, + ), + duration: Some( + 256, + ), + pos: Some( + 192534, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 11264, + ), + dts: Some( + 10752, + ), + duration: Some( + 256, + ), + pos: Some( + 194281, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 33792, + ), + dts: Some( + 33792, + ), + duration: Some( + 1024, + ), + pos: Some( + 195161, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 11008, + ), + dts: Some( + 11008, + ), + duration: Some( + 256, + ), + pos: Some( + 195498, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 34816, + ), + dts: Some( + 34816, + ), + duration: Some( + 1024, + ), + pos: Some( + 196022, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 11520, + ), + dts: Some( + 11264, + ), + duration: Some( + 256, + ), + pos: Some( + 196367, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 35840, + ), + dts: Some( + 35840, + ), + duration: Some( + 1024, + ), + pos: Some( + 197043, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 12800, + ), + dts: Some( + 11520, + ), + duration: Some( + 256, + ), + pos: Some( + 197388, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 12288, + ), + dts: Some( + 11776, + ), + duration: Some( + 256, + ), + pos: Some( + 198953, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 36864, + ), + dts: Some( + 36864, + ), + duration: Some( + 1024, + ), + pos: Some( + 199718, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 12032, + ), + dts: Some( + 12032, + ), + duration: Some( + 256, + ), + pos: Some( + 200097, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 37888, + ), + dts: Some( + 37888, + ), + duration: Some( + 1024, + ), + pos: Some( + 200792, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 12544, + ), + dts: Some( + 12288, + ), + duration: Some( + 256, + ), + pos: Some( + 201167, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 38912, + ), + dts: Some( + 38912, + ), + duration: Some( + 1024, + ), + pos: Some( + 201806, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 13824, + ), + dts: Some( + 12544, + ), + duration: Some( + 256, + ), + pos: Some( + 202138, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 39936, + ), + dts: Some( + 39936, + ), + duration: Some( + 1024, + ), + pos: Some( + 203550, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 13312, + ), + dts: Some( + 12800, + ), + duration: Some( + 256, + ), + pos: Some( + 203895, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 13056, + ), + dts: Some( + 13056, + ), + duration: Some( + 256, + ), + pos: Some( + 204549, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 40960, + ), + dts: Some( + 40960, + ), + duration: Some( + 1024, + ), + pos: Some( + 205047, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 13568, + ), + dts: Some( + 13312, + ), + duration: Some( + 256, + ), + pos: Some( + 205375, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 41984, + ), + dts: Some( + 41984, + ), + duration: Some( + 1024, + ), + pos: Some( + 205823, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 14848, + ), + dts: Some( + 13568, + ), + duration: Some( + 256, + ), + pos: Some( + 206184, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 43008, + ), + dts: Some( + 43008, + ), + duration: Some( + 1024, + ), + pos: Some( + 207436, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 14336, + ), + dts: Some( + 13824, + ), + duration: Some( + 256, + ), + pos: Some( + 207776, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 14080, + ), + dts: Some( + 14080, + ), + duration: Some( + 256, + ), + pos: Some( + 208549, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 44032, + ), + dts: Some( + 44032, + ), + duration: Some( + 1024, + ), + pos: Some( + 208999, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 14592, + ), + dts: Some( + 14336, + ), + duration: Some( + 256, + ), + pos: Some( + 209364, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 45056, + ), + dts: Some( + 45056, + ), + duration: Some( + 1024, + ), + pos: Some( + 209974, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 15104, + ), + dts: Some( + 14592, + ), + duration: Some( + 256, + ), + pos: Some( + 210303, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 46080, + ), + dts: Some( + 46080, + ), + duration: Some( + 1024, + ), + pos: Some( + 211374, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 15360, + ), + dts: Some( + 14848, + ), + duration: Some( + 256, + ), + pos: Some( + 211720, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 1, + pts: Some( + 47104, + ), + dts: Some( + 47104, + ), + duration: Some( + 992, + ), + pos: Some( + 247025, + ), + is_key: true, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 16128, + ), + dts: Some( + 15104, + ), + duration: Some( + 256, + ), + pos: Some( + 247361, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 15616, + ), + dts: Some( + 15360, + ), + duration: Some( + 256, + ), + pos: Some( + 248850, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, + Packet { + stream_index: 0, + pts: Some( + 15872, + ), + dts: Some( + 15616, + ), + duration: Some( + 256, + ), + pos: Some( + 249638, + ), + is_key: false, + is_corrupt: false, + is_discard: false, + is_trusted: false, + is_disposable: false, + }, +] diff --git a/crates/ffmpeg/src/lib.rs b/crates/ffmpeg/src/lib.rs index f6decd76f..2f380889e 100644 --- a/crates/ffmpeg/src/lib.rs +++ b/crates/ffmpeg/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))] + pub mod codec; pub mod consts; pub mod decoder; diff --git a/crates/ffmpeg/src/packet.rs b/crates/ffmpeg/src/packet.rs index 395a1bb1a..71dffdd33 100644 --- a/crates/ffmpeg/src/packet.rs +++ b/crates/ffmpeg/src/packet.rs @@ -4,6 +4,7 @@ use crate::error::FfmpegError; use crate::smart_object::SmartPtr; use crate::utils::check_i64; +#[derive(Debug)] pub struct Packets<'a> { context: &'a mut AVFormatContext, } diff --git a/crates/ffmpeg/src/stream.rs b/crates/ffmpeg/src/stream.rs index e51ea934f..62f5fe351 100644 --- a/crates/ffmpeg/src/stream.rs +++ b/crates/ffmpeg/src/stream.rs @@ -4,6 +4,7 @@ use crate::consts::{Const, Mut}; use crate::dict::Dictionary; use crate::utils::check_i64; +#[derive(Debug)] pub struct Streams<'a> { input: &'a AVFormatContext, } diff --git a/crates/workspace-hack/Cargo.toml b/crates/workspace-hack/Cargo.toml index 78236f1b5..3dc7830b5 100644 --- a/crates/workspace-hack/Cargo.toml +++ b/crates/workspace-hack/Cargo.toml @@ -32,6 +32,7 @@ futures-io = { version = "0.3" } futures-sink = { version = "0.3" } futures-util = { version = "0.3", default-features = false, features = ["async-await-macro", "channel", "io", "sink"] } getrandom = { version = "0.2", default-features = false, features = ["std"] } +insta = { version = "1", features = ["filters"] } libc = { version = "0.2", features = ["extra_traits"] } log = { version = "0.4", default-features = false, features = ["std"] } memchr = { version = "2" } @@ -42,9 +43,9 @@ opentelemetry_sdk = { version = "0.27", features = ["rt-tokio", "spec_unstable_l proc-macro2 = { version = "1" } quote = { version = "1" } rand = { version = "0.8", features = ["small_rng"] } -regex = { version = "1", default-features = false, features = ["std", "unicode-perl"] } -regex-automata = { version = "0.4", default-features = false, features = ["meta", "std", "unicode-perl", "unicode-word-boundary"] } -regex-syntax = { version = "0.8", default-features = false, features = ["std", "unicode-perl"] } +regex = { version = "1", default-features = false, features = ["std", "unicode"] } +regex-automata = { version = "0.4", default-features = false, features = ["meta", "std", "unicode"] } +regex-syntax = { version = "0.8", default-features = false, features = ["std", "unicode"] } serde = { version = "1", features = ["alloc", "derive"] } serde_json = { version = "1", features = ["unbounded_depth"] } smallvec = { version = "1", default-features = false, features = ["const_new"] } @@ -78,6 +79,7 @@ futures-io = { version = "0.3" } futures-sink = { version = "0.3" } futures-util = { version = "0.3", default-features = false, features = ["async-await-macro", "channel", "io", "sink"] } getrandom = { version = "0.2", default-features = false, features = ["std"] } +insta = { version = "1", features = ["filters"] } itertools = { version = "0.12", default-features = false, features = ["use_alloc"] } libc = { version = "0.2", features = ["extra_traits"] } log = { version = "0.4", default-features = false, features = ["std"] } @@ -89,9 +91,9 @@ opentelemetry_sdk = { version = "0.27", features = ["rt-tokio", "spec_unstable_l proc-macro2 = { version = "1" } quote = { version = "1" } rand = { version = "0.8", features = ["small_rng"] } -regex = { version = "1", default-features = false, features = ["std", "unicode-perl"] } -regex-automata = { version = "0.4", default-features = false, features = ["meta", "std", "unicode-perl", "unicode-word-boundary"] } -regex-syntax = { version = "0.8", default-features = false, features = ["std", "unicode-perl"] } +regex = { version = "1", default-features = false, features = ["std", "unicode"] } +regex-automata = { version = "0.4", default-features = false, features = ["meta", "std", "unicode"] } +regex-syntax = { version = "0.8", default-features = false, features = ["std", "unicode"] } serde = { version = "1", features = ["alloc", "derive"] } serde_json = { version = "1", features = ["unbounded_depth"] } smallvec = { version = "1", default-features = false, features = ["const_new"] }