### Error Handling in Video Decoding Source: https://github.com/rust-av/av-decoders/blob/main/README.md This example shows how to handle potential errors during file opening and frame reading, including specific cases like EndOfFile and NoDecoder. ```rust use av_decoders::{Decoder, DecoderError}; match Decoder::from_file("video.mp4") { Ok(mut decoder) => { match decoder.read_video_frame::() { Ok(frame) => println!("Success!"), Err(DecoderError::EndOfFile) => println!("Reached end of video"), Err(e) => println!("Decode error: {}", e), } } Err(DecoderError::NoDecoder) => { println!("No decoder available - try enabling ffmpeg feature"); } Err(e) => println!("Failed to open file: {}", e), } ``` -------------------------------- ### Install av-decoders Crate Source: https://github.com/rust-av/av-decoders/blob/main/README.md Add the av-decoders crate to your Cargo.toml file. For optional features like FFmpeg or VapourSynth support, specify them in the features list. ```toml [dependencies] av-decoders = "0.1.0" ``` ```toml [dependencies] av-decoders = { version = "0.1.0", features = ["ffmpeg", "vapoursynth"] } ``` -------------------------------- ### Build av-decoders from Source Source: https://github.com/rust-av/av-decoders/blob/main/README.md These bash commands show how to clone the av-decoders repository, build the project with default features (Y4M only), build with all features (ffmpeg, vapoursynth), and run tests. ```bash # Clone the repository git clone https://github.com/rust-av/av-decoders cd av-decoders # Build with default features (Y4M only) cargo build # Build with all features cargo build --features "ffmpeg,vapoursynth" # Run tests cargo test ``` -------------------------------- ### Basic Video Decoding from File Source: https://github.com/rust-av/av-decoders/blob/main/README.md Initialize a decoder from a file path and retrieve video details. This snippet demonstrates reading frames until the end of the file is reached. ```rust use av_decoders::Decoder; // Decode from a file let mut decoder = Decoder::from_file("video.y4m")?; let details = decoder.get_video_details(); println!("Video: {}x{} @ {} fps", details.width, details.height, details.frame_rate ); // Read frames while let Ok(frame) = decoder.read_video_frame::() { // Process the frame... println!("Read frame with {} planes", frame.planes.len()); } ``` -------------------------------- ### Integrate with VapourSynth using Decoder Methods Source: https://context7.com/rust-av/av-decoders/llms.txt Demonstrates accessing VapourSynth environment and nodes for advanced integration, including evaluating scripts and setting variables. ```rust use av_decoders::{Decoder, DecoderError}; use std::collections::HashMap; fn main() -> Result<(), DecoderError> { let script = r#"\ import vapoursynth as vs core = vs.core clip = core.ffms2.Source("input.mkv") clip.set_output() "#; let mut decoder = Decoder::from_script(script, HashMap::new())?; // 1. Get both environment and node together let (env, node) = decoder.get_vapoursynth()?; let info = node.info(); println!("Node num_frames: {}", info.num_frames); drop(node); // release borrow before mutable access // 2. Access the mutable environment for advanced operations let env_mut = decoder.get_vapoursynth_env()?; // e.g. eval_script, set_variables, get_core, etc. let _ = env_mut; // 3. Get node only let node = decoder.get_vapoursynth_node()?; // Pass to another VapourSynth-aware component let _ = node; // Access via get_vapoursynth_impl for lower-level control if let Some(vs_impl) = decoder.get_vapoursynth_impl() { let mut vars = HashMap::new(); vars.insert("quality".to_string(), "high".to_string()); vs_impl.set_variables(vars)?; } Ok(()) } ``` -------------------------------- ### Open Video File with Automatic Backend Selection Source: https://context7.com/rust-av/av-decoders/llms.txt Use Decoder::from_file to open a video. The backend is chosen automatically based on file type and available features. Handles different pixel types and provides error handling for missing files or decoders. ```rust use av_decoders::{Decoder, DecoderError}; use v_frame::chroma::ChromaSubsampling; fn main() -> Result<(), DecoderError> { // Works with &str, String, Path, PathBuf let mut decoder = Decoder::from_file("video.y4m")?; let details = decoder.get_video_details(); println!( "{}x{} @ {}/{} fps, {} bpp, {:?}", details.width, details.height, details.frame_rate.numer(), details.frame_rate.denom(), details.bit_depth, details.chroma_sampling, ); // e.g. "352x240 @ 30/1 fps, 8 bpp, Yuv420" if let Some(total) = details.total_frames { println!("Total frames: {total}"); } // Decode all frames; pixel type must match bit_depth if details.bit_depth > 8 { while let Ok(frame) = decoder.read_video_frame::() { let _ = frame; // process 10/12-bit frame } } else { let mut n = 0usize; while let Ok(frame) = decoder.read_video_frame::() { n += 1; let _ = &frame.planes[0]; // Y plane } println!("Decoded {n} frames"); } // Error handling match Decoder::from_file("missing.mp4") { Err(DecoderError::FileReadError { cause }) => eprintln!("Cannot open: {cause}"), Err(DecoderError::NoDecoder) => eprintln!("Enable ffmpeg or vapoursynth feature"), _ => {} } Ok(()) } ``` -------------------------------- ### Video Decoding from Standard Input Source: https://github.com/rust-av/av-decoders/blob/main/README.md Initialize a decoder to read video data directly from standard input. ```rust use av_decoders::Decoder; let mut decoder = Decoder::from_stdin()?; let frame = decoder.read_video_frame::()?; ``` -------------------------------- ### Configure FFMS2 for Transparent Resizing and Color Conversion Source: https://context7.com/rust-av/av-decoders/llms.txt Use `set_output_format` with `Ffms2Decoder` to request specific output dimensions, bit depth, and chroma subsampling. This leverages FFMS2's codec-level transformations for efficiency. ```rust use av_decoders::{Decoder, DecoderImpl, DecoderError, Ffms2Decoder}; use v_frame::chroma::ChromaSubsampling; fn main() -> Result<(), DecoderError> { // Open any video file via FFMS2 let mut dec = Ffms2Decoder::new("4k_hdr.mkv") .map_err(|e| e)?; // Request 1920x1080 output in 10-bit 4:2:0 (downscale + bit depth change) dec.set_output_format(1920, 1080, 10, ChromaSubsampling::Yuv420)?; println!( "Output: {}x{} @ {} bpp", dec.video_details.width, dec.video_details.height, dec.video_details.bit_depth ); // Output: 1920x1080 @ 10 bpp // Wrap in unified Decoder and read let mut decoder = Decoder::from_decoder_impl(DecoderImpl::Ffms2(dec))?; while let Ok(frame) = decoder.read_video_frame::() { let _ = frame.planes[0].data_origin(); // &[u16] luma data } Ok(()) } ``` -------------------------------- ### Construct Decoder from Backend with Decoder::from_decoder_impl Source: https://context7.com/rust-av/av-decoders/llms.txt Constructs a decoder from a pre-built `DecoderImpl` variant, bypassing automatic format detection. Useful for pre-configuring a backend or transferring an implementation between contexts. ```rust use av_decoders::{Decoder, DecoderImpl, DecoderError, Y4mDecoder}; use std::fs::File; use std::io::{BufReader, Read}; fn main() -> Result<(), Box> { // Build the Y4M decoder implementation manually let file = File::open("video.y4m")?; let reader = BufReader::new(file); let y4m_dec = y4m::decode(Box::new(reader) as Box) .map_err(|e| DecoderError::GenericDecodeError { cause: e.to_string() })?; // Wrap it in the unified Decoder let mut decoder = Decoder::from_decoder_impl(DecoderImpl::Y4m(y4m_dec))?; let details = decoder.get_video_details(); println!("Opened via DecoderImpl: {}x{}", details.width, details.height); while let Ok(_frame) = decoder.read_video_frame::() { // process frame } Ok(()) } ``` -------------------------------- ### Process Video Frames with av-decoders Source: https://github.com/rust-av/av-decoders/blob/main/README.md This Rust function demonstrates how to initialize a decoder from a file, retrieve video details like chroma sampling, and read video frames. It prints detected chroma subsampling and the total number of frames processed. ```rust use av_decoders::Decoder; use v_frame::pixel::ChromaSampling; fn process_video(path: &str) -> Result<(), Box> { let mut decoder = Decoder::from_file(path)?; let details = decoder.get_video_details(); // Process based on video characteristics match details.chroma_sampling { ChromaSampling::Cs420 => println!("4:2:0 subsampling detected"), ChromaSampling::Cs422 => println!("4:2:2 subsampling detected"), ChromaSampling::Cs444 => println!("4:4:4 subsampling detected"), _ => println!("Other subsampling format"), } let mut frame_count = 0; while let Ok(_frame) = decoder.read_video_frame::() { frame_count += 1; if frame_count % 100 == 0 { println!("Processed {} frames", frame_count); } } println!("Total frames: {}", frame_count); Ok(()) } ``` -------------------------------- ### Decoder::from_file Source: https://context7.com/rust-av/av-decoders/llms.txt Opens a video file and automatically selects the appropriate decoding backend. Supports various file formats and provides detailed video information. ```APIDOC ## Decoder::from_file — Open a video file with automatic backend selection Creates a `Decoder` from a file path. The backend is selected automatically: Y4M/YUV extensions use the built-in Y4M parser; `.vpy` files use VapourSynth; all other formats fall through to FFMS2 → FFmpeg → VapourSynth-with-ffms2-script, in that order of preference. ### Method `Decoder::from_file(path)` ### Parameters - **path** (`&str`, `String`, `Path`, `PathBuf`) - Required - The path to the video file. ### Request Example ```rust use av_decoders::{Decoder, DecoderError}; use v_frame::chroma::ChromaSubsampling; fn main() -> Result<(), DecoderError> { let mut decoder = Decoder::from_file("video.y4m")?; let details = decoder.get_video_details(); println!( "{}x{} @ {}/{} fps, {} bpp, {{:?}}", details.width, details.height, details.frame_rate.numer(), details.frame_rate.denom(), details.bit_depth, details.chroma_sampling, ); if let Some(total) = details.total_frames { println!("Total frames: {{total}}"); } if details.bit_depth > 8 { while let Ok(frame) = decoder.read_video_frame::() { let _ = frame; } } else { let mut n = 0usize; while let Ok(frame) = decoder.read_video_frame::() { n += 1; let _ = &frame.planes[0]; } println!("Decoded {{n}} frames"); } match Decoder::from_file("missing.mp4") { Err(DecoderError::FileReadError { cause }) => eprintln!("Cannot open: {{cause}}"), Err(DecoderError::NoDecoder) => eprintln!("Enable ffmpeg or vapoursynth feature"), _ => {{}} } Ok(()) } ``` ### Response #### Success Response Returns a `Decoder` instance if the file is opened successfully. #### Response Example ```rust // Decoder instance ``` ### Error Handling - `DecoderError::FileReadError`: If the file cannot be read. - `DecoderError::NoDecoder`: If no suitable decoder is available (e.g., required features are not enabled). ``` -------------------------------- ### Reading Video Frames with Different Bit Depths Source: https://github.com/rust-av/av-decoders/blob/main/README.md Demonstrates how to read video frames for different bit depths. Use `` for 8-bit video and `` for 10-bit video. ```rust // For 8-bit video let frame_8bit = decoder.read_video_frame::()?; // For 10-bit video let frame_10bit = decoder.read_video_frame::()?; ``` -------------------------------- ### Decoder::from_script Source: https://context7.com/rust-av/av-decoders/llms.txt Initializes a decoder from a VapourSynth script. This method is useful for integrating with VapourSynth workflows and requires the `vapoursynth` feature to be enabled. ```APIDOC ## Decoder::from_script ### Description Initializes a decoder from a VapourSynth script. This method is useful for integrating with VapourSynth workflows and requires the `vapoursynth` feature to be enabled. ### Method `from_script(script: &str, variables: HashMap) -> Result` ### Parameters #### Path Parameters - **script** (string) - Required - The VapourSynth script content. - **variables** (HashMap) - Optional - A map of variables to be used within the script. ### Response #### Success Response (Decoder) - **Decoder** - An initialized decoder instance. #### Error Response (DecoderError) - **DecoderError::UnsupportedDecoder** - The decoder does not support VapourSynth. - **DecoderError** - Other potential errors during script processing or decoder initialization. ``` -------------------------------- ### Decode VapourSynth Script with Decoder::from_script Source: https://context7.com/rust-av/av-decoders/llms.txt Creates a decoder by evaluating a VapourSynth Python script. Supports optional key/value variables for dynamic processing pipelines. Requires the 'vapoursynth' Cargo feature. ```rust use av_decoders::{Decoder, DecoderError}; use std::collections::HashMap; fn main() -> Result<(), DecoderError> { // Simple: load and decode a file via VapourSynth let script = r#"import vapoursynth as vs core = vs.core clip = core.ffms2.Source("input.mkv") clip.set_output() "#; let mut decoder = Decoder::from_script(script, HashMap::new())?; let details = decoder.get_video_details(); println!("{}x{}, {} frames", details.width, details.height, details.total_frames.unwrap_or(0)); // Advanced: pass runtime variables and apply filters let script_with_vars = r#"import vapoursynth as vs core = vs.core import struct # Read variable bytes injected from Rust target_w = int(vs.get_output(0).get_frame(0).props.get("target_w", b"1280").decode()) clip = core.ffms2.Source("raw.mkv") clip = core.resize.Bicubic(clip, width=1920, height=1080) clip.set_output() "#; // Pass variables into the script environment let mut vars = HashMap::new(); vars.insert("source_file".to_string(), "/media/raw.mkv".to_string()); vars.insert("denoise_strength".to_string(), "3".to_string()); let mut decoder = Decoder::from_script(script_with_vars, vars)?; // Random-access frame retrieval (VapourSynth backend only) let frame_42 = decoder.get_video_frame::(42)?; println!("Frame 42: {}x{}", frame_42.planes[0].cfg.width, frame_42.planes[0].cfg.height); Ok(()) } ``` -------------------------------- ### Decoder::from_stdin Source: https://github.com/rust-av/av-decoders/blob/main/README.md Creates a new decoder instance that reads video data from standard input. ```APIDOC ## Decoder::from_stdin ### Description Creates a decoder instance that reads video data from standard input. ### Method `Decoder::from_stdin()` ### Parameters None. ### Request Example ```rust use av_decoders::Decoder; let mut decoder = Decoder::from_stdin()?; ``` ### Response #### Success Response - Returns a `Decoder` instance. #### Response Example ```rust // Decoder instance is returned on success ``` ``` -------------------------------- ### Decoder::get_video_details Source: https://github.com/rust-av/av-decoders/blob/main/README.md Retrieves detailed metadata and configuration information about the video stream. ```APIDOC ## Decoder::get_video_details ### Description Retrieves detailed metadata and configuration information about the video stream. ### Method `get_video_details()` ### Parameters None. ### Request Example ```rust let details = decoder.get_video_details(); ``` ### Response #### Success Response - Returns a `VideoDetails` struct containing video information. #### Response Example ```rust println!("Dimensions: {}x{}", details.width, details.height); println!("Bit depth: {} bits", details.bit_depth); println!("Chroma sampling: {:?}", details.chroma_sampling); println!("Frame rate: {}", details.frame_rate); ``` ``` -------------------------------- ### Inspect Video Metadata with Decoder::get_video_details Source: https://context7.com/rust-av/av-decoders/llms.txt Returns a `&VideoDetails` describing the stream's dimensions, bit depth, chroma subsampling, frame rate, and optional total frame count. Useful for understanding stream properties before processing. ```rust use av_decoders::{Decoder, DecoderError}; use v_frame::chroma::ChromaSubsampling; use num_rational::Rational32; fn print_video_info(path: &str) -> Result<(), DecoderError> { let decoder = Decoder::from_file(path)?; let d = decoder.get_video_details(); println!("Resolution : {}x{}", d.width, d.height); println!("Bit depth : {} bpp", d.bit_depth); println!("Frame rate : {}/{}", d.frame_rate.numer(), d.frame_rate.denom()); println!("Total frames: {:?}", d.total_frames); // None for Y4M (no header count) let subsampling = match d.chroma_sampling { ChromaSubsampling::Yuv420 => "4:2:0", ChromaSubsampling::Yuv422 => "4:2:2", ChromaSubsampling::Yuv444 => "4:4:4", ChromaSubsampling::Monochrome => "monochrome", }; println!("Subsampling : {subsampling}"); // fps as f64 let fps = *d.frame_rate.numer() as f64 / *d.frame_rate.denom() as f64; println!("FPS (float) : {fps:.3}"); // e.g. "23.976" for 24000/1001 Ok(()) } ``` -------------------------------- ### Decoder::from_file Source: https://github.com/rust-av/av-decoders/blob/main/README.md Creates a new decoder instance from a given file path. The library automatically detects the appropriate decoder based on the file content and available features. ```APIDOC ## Decoder::from_file ### Description Creates a decoder instance from a file path. ### Method `Decoder::from_file(path: &str)` ### Parameters #### Path Parameters - **path** (string) - Required - The path to the video file. ### Request Example ```rust use av_decoders::Decoder; let mut decoder = Decoder::from_file("video.y4m")?; ``` ### Response #### Success Response - Returns a `Decoder` instance. #### Response Example ```rust // Decoder instance is returned on success ``` ``` -------------------------------- ### Decoder::from_decoder_impl Source: https://context7.com/rust-av/av-decoders/llms.txt Constructs a decoder from a specific backend implementation (`DecoderImpl`). This advanced constructor bypasses automatic format detection and is useful when you need to pre-configure a backend or transfer an implementation between contexts. ```APIDOC ## `Decoder::from_decoder_impl` — Construct a decoder from a specific backend implementation Advanced constructor that accepts a pre-built `DecoderImpl` variant, bypassing automatic format detection. Useful when you need to pre-configure a backend or transfer an implementation between contexts. ### Parameters - `impl`: A `DecoderImpl` variant representing the pre-built decoder backend (e.g., `DecoderImpl::Y4m`). ### Returns A `Result` containing a `Decoder` instance on success, or a `DecoderError` on failure. ### Example ```rust use av_decoders::{Decoder, DecoderImpl, DecoderError, Y4mDecoder}; use std::fs::File; use std::io::{BufReader, Read}; let file = File::open("video.y4m")?; let reader = BufReader::new(file); let y4m_dec = y4m::decode(Box::new(reader) as Box) .map_err(|e| DecoderError::GenericDecodeError { cause: e.to_string() })?; let mut decoder = Decoder::from_decoder_impl(DecoderImpl::Y4m(y4m_dec))?; let details = decoder.get_video_details(); println!("Opened via DecoderImpl: {}x{}", details.width, details.height); ``` ``` -------------------------------- ### Random-Access Frame Retrieval with `Decoder::get_video_frame` (VapourSynth) Source: https://context7.com/rust-av/av-decoders/llms.txt Retrieves an arbitrary frame by index without advancing the sequential cursor. This functionality requires the `vapoursynth` feature to be enabled. It allows jumping directly to specific frames. ```rust use av_decoders::{Decoder, DecoderError}; use std::collections::HashMap; fn main() -> Result<(), DecoderError> { let script = r#"import vapoursynth as vs core = vs.core clip = core.ffms2.Source("long_movie.mkv") clip.set_output() "#; let mut decoder = Decoder::from_script(script, HashMap::new())?; let details = *decoder.get_video_details(); // Jump directly to specific frames — no sequential decoding needed let keyframes = [0usize, 500, 1000, 2500, 5000]; for &idx in &keyframes { if details.total_frames.map_or(true, |n| idx < n) { let frame = decoder.get_video_frame::(idx)?; println!("Frame {idx}: {}x{}", frame.planes[0].cfg.width, frame.planes[0].cfg.height); } } Ok(()) } ``` -------------------------------- ### Decoder::from_file Source: https://context7.com/rust-av/av-decoders/llms.txt Opens a video file and initializes a decoder. It returns a Result which can be Ok(Decoder) or Err(DecoderError). The DecoderError enum provides specific reasons for failure, such as file read errors, missing decoders, or unsupported formats. ```APIDOC ## Decoder::from_file ### Description Opens a video file and initializes a decoder. It returns a Result which can be Ok(Decoder) or Err(DecoderError). The DecoderError enum provides specific reasons for failure, such as file read errors, missing decoders, or unsupported formats. ### Method `Decoder::from_file(path: &str)` ### Parameters #### Path Parameters - **path** (string) - Required - The path to the video file. ### Response #### Success Response (Decoder) - **Decoder** - An initialized decoder instance. #### Error Response (DecoderError) - **DecoderError::FileReadError { cause }** - An error occurred while reading the file. - **DecoderError::NoDecoder** - No suitable decoder could be found for the file. - **DecoderError::UnsupportedFormat { fmt }** - The pixel format of the video is not supported. - **DecoderError::NoVideoStream** - The file does not contain a video stream. - **DecoderError** - A generic decoder initialization error. ``` -------------------------------- ### Decoder::get_vapoursynth Source: https://context7.com/rust-av/av-decoders/llms.txt Retrieves both the VapourSynth environment and node. This allows for advanced interaction with the VapourSynth runtime, such as evaluating scripts or accessing node information. ```APIDOC ## Decoder::get_vapoursynth ### Description Retrieves both the VapourSynth environment and node. This allows for advanced interaction with the VapourSynth runtime, such as evaluating scripts or accessing node information. ### Method `get_vapoursynth() -> Result<(VSPtr, VSPtr), DecoderError>` ### Response #### Success Response ((VSPtr, VSPtr)) - **VSPtr** - A smart pointer to the VapourSynth environment. - **VSPtr** - A smart pointer to the VapourSynth node. #### Error Response (DecoderError) - **DecoderError::UnsupportedDecoder** - The decoder does not support VapourSynth. ``` -------------------------------- ### Decoder::from_script Source: https://context7.com/rust-av/av-decoders/llms.txt Creates a decoder by evaluating a VapourSynth Python script supplied as a `&str`. This method supports optional key/value variables that the script can read, enabling fully dynamic processing pipelines. Requires the `vapoursynth` Cargo feature. ```APIDOC ## `Decoder::from_script` — Decode through an inline VapourSynth script Creates a decoder by evaluating a VapourSynth Python script supplied as a `&str`. Requires the `vapoursynth` Cargo feature. Supports optional key/value variables that the script can read, enabling fully dynamic processing pipelines. ### Parameters - `script`: A string slice (`&str`) containing the VapourSynth Python script. - `variables`: A `HashMap` of key-value pairs to be passed as variables to the script. ### Returns A `Result` containing a `Decoder` instance on success, or a `DecoderError` on failure. ### Example ```rust use av_decoders::{Decoder, DecoderError}; use std::collections::HashMap; let script = r#"import vapoursynth as vs core = vs.core clip = core.ffms2.Source("input.mkv") clip.set_output()"#; let mut decoder = Decoder::from_script(script, HashMap::new())?; let details = decoder.get_video_details(); println!("{}x{}, {} frames", details.width, details.height, details.total_frames.unwrap_or(0)); ``` ``` -------------------------------- ### Access Video Stream Metadata with VideoDetails Source: https://context7.com/rust-av/av-decoders/llms.txt Retrieves and analyzes video stream metadata such as resolution, bit depth, chroma subsampling, and frame rate from a video file. ```rust use av_decoders::{Decoder, DecoderError, VideoDetails}; use v_frame::chroma::ChromaSubsampling; use num_rational::Rational32; fn analyze(path: &str) -> Result { let decoder = Decoder::from_file(path)?; let d = *decoder.get_video_details(); // Copy // Derived calculations let fps: f64 = *d.frame_rate.numer() as f64 / *d.frame_rate.denom() as f64; let duration_secs = d.total_frames.map(|n| n as f64 / fps); let is_hdr = d.bit_depth > 8; let is_420 = matches!(d.chroma_sampling, ChromaSubsampling::Yuv420); println!("Width : {}", d.width); println!("Height : {}", d.height); println!("Bit depth : {} bpp (HDR: {{is_hdr}})", d.bit_depth); println!("Chroma : {{:?}} (4:2:0: {{is_420}})", d.chroma_sampling); println!("Frame rate : {fps:.4} fps"); println!("Duration : {{:?}} s", duration_secs); println!("Total frames : {{:?}}", d.total_frames); Ok(d) } ``` -------------------------------- ### Decoder::get_vapoursynth_impl Source: https://context7.com/rust-av/av-decoders/llms.txt Provides access to the lower-level VapourSynth implementation details. This method returns an Option containing a trait object that allows for more granular control over VapourSynth operations. ```APIDOC ## Decoder::get_vapoursynth_impl ### Description Provides access to the lower-level VapourSynth implementation details. This method returns an Option containing a trait object that allows for more granular control over VapourSynth operations. ### Method `get_vapoursynth_impl() -> Option>` ### Response #### Success Response (Option>) - **Option>** - An optional trait object for VapourSynth implementation details. This can be used to call methods like `set_variables`. ``` -------------------------------- ### Read All Sequential Video Frames with `Decoder::read_video_frame` Source: https://context7.com/rust-av/av-decoders/llms.txt Reads all sequential video frames from a file, handling both 8-bit and higher bit-depth content (10-bit/12-bit). Returns `DecoderError::EndOfFile` when the stream ends. Requires `av_decoders` crate. ```rust use av_decoders::{Decoder, DecoderError}; fn decode_all_frames(path: &str) -> Result { let mut decoder = Decoder::from_file(path)?; let details = *decoder.get_video_details(); let mut count = 0usize; if details.bit_depth > 8 { // 10-bit or 12-bit content loop { match decoder.read_video_frame::() { Ok(frame) => { count += 1; // frame.planes[0] = Y (luma) // frame.planes[1] = U (Cb), frame.planes[2] = V (Cr) // plane data as &[u16] let y_data: &[u16] = frame.planes[0].data_origin(); let _ = y_data[0]; // first luma sample } Err(DecoderError::EndOfFile) => break, Err(e) => return Err(e), } } } else { // 8-bit content loop { match decoder.read_video_frame::() { Ok(frame) => { count += 1; let _ = &frame.planes[0]; // Y plane } Err(DecoderError::EndOfFile) => break, Err(e) => return Err(e), } } } Ok(count) } ``` -------------------------------- ### Add av-decoders to Cargo.toml Source: https://context7.com/rust-av/av-decoders/llms.txt Specify the av-decoders version and enable optional features like ffmpeg, ffms2, or vapoursynth for extended codec support. ```toml [dependencies] av-decoders = "0.11.0" # With FFmpeg support av-decoders = { version = "0.11.0", features = ["ffmpeg"] } # With FFMS2 support av-decoders = { version = "0.11.0", features = ["ffms2"] } # With VapourSynth support av-decoders = { version = "0.11.0", features = ["vapoursynth"] } # With statically-linked FFmpeg built from source (includes dav1d) av-decoders = { version = "0.11.0", features = ["ffmpeg_build"] } ``` -------------------------------- ### Accessing Video Metadata Source: https://github.com/rust-av/av-decoders/blob/main/README.md Retrieve detailed information about the video stream, including dimensions, bit depth, chroma sampling, and frame rate. ```rust let details = decoder.get_video_details(); println!("Dimensions: {}x{}", details.width, details.height); println!("Bit depth: {} bits", details.bit_depth); println!("Chroma sampling: {:?}", details.chroma_sampling); println!("Frame rate: {}", details.frame_rate); ``` -------------------------------- ### Ffms2Decoder::set_output_format Source: https://context7.com/rust-av/av-decoders/llms.txt Configures the FFMS2 backend to transparently rescale and convert pixel format before delivering frames. This is more efficient than post-decode conversion. ```APIDOC ## `Ffms2Decoder::set_output_format` — Transparent resize and color conversion via FFMS2 Configures the FFMS2 backend to transparently rescale and convert pixel format before delivering frames. This is more efficient than post-decode conversion since FFMS2 applies the transformation at the codec level using bicubic resampling. Requires the `ffms2` feature. ```rust use av_decoders::{Decoder, DecoderImpl, DecoderError, Ffms2Decoder}; use v_frame::chroma::ChromaSubsampling; fn main() -> Result<(), DecoderError> { // Open any video file via FFMS2 let mut dec = Ffms2Decoder::new("4k_hdr.mkv") .map_err(|e| e)?; // Request 1920x1080 output in 10-bit 4:2:0 (downscale + bit depth change) dec.set_output_format(1920, 1080, 10, ChromaSubsampling::Yuv420)?; println!( "Output: {}x{} @ {} bpp", dec.video_details.width, dec.video_details.height, dec.video_details.bit_depth ); // Output: 1920x1080 @ 10 bpp // Wrap in unified Decoder and read let mut decoder = Decoder::from_decoder_impl(DecoderImpl::Ffms2(dec))?; while let Ok(frame) = decoder.read_video_frame::() { let _ = frame.planes[0].data_origin(); // &[u16] luma data } Ok(()) } ``` ``` -------------------------------- ### Seek and Resume Sequential Decoding with `Decoder::seek_to_frame` Source: https://context7.com/rust-av/av-decoders/llms.txt Repositions the decoder's internal frame counter to a specified index, allowing sequential decoding to resume from that point. This requires the `vapoursynth` or `ffms2` feature and is not supported by Y4M/FFmpeg backends. Returns `DecoderError::UnsupportedDecoder` or `DecoderError::EndOfFile` if the index is out of range. ```rust use av_decoders::{Decoder, DecoderError}; use std::collections::HashMap; fn main() -> Result<(), DecoderError> { let script = r#"import vapoursynth as vs core = vs.core clip = core.ffms2.Source("video.mp4") clip.set_output() "#; let mut decoder = Decoder::from_script(script, HashMap::new())?; // Skip the first 100 frames (e.g. intro) decoder.seek_to_frame(100)?; // Sequential decoding resumes from frame 100 let mut count = 0usize; while let Ok(_frame) = decoder.read_video_frame::() { count += 1; if count >= 10 { break; } // read just the next 10 frames } println!("Decoded {count} frames starting from frame 100"); // Seek back to the beginning decoder.seek_to_frame(0)?; let first_frame = decoder.read_video_frame::()?; println!("Back to frame 0: {}x{}", first_frame.planes[0].cfg.width, first_frame.planes[0].cfg.height); Ok(()) } ``` -------------------------------- ### Decoder::get_vapoursynth_env Source: https://context7.com/rust-av/av-decoders/llms.txt Provides mutable access to the VapourSynth environment. This method is intended for advanced use cases where direct manipulation of the VapourSynth environment is required, such as setting variables or evaluating scripts. ```APIDOC ## Decoder::get_vapoursynth_env ### Description Provides mutable access to the VapourSynth environment. This method is intended for advanced use cases where direct manipulation of the VapourSynth environment is required, such as setting variables or evaluating scripts. ### Method `get_vapoursynth_env() -> Result, DecoderError>` ### Response #### Success Response (VSPtr) - **VSPtr** - A mutable smart pointer to the VapourSynth environment. #### Error Response (DecoderError) - **DecoderError::UnsupportedDecoder** - The decoder does not support VapourSynth. ``` -------------------------------- ### VideoDetails Struct Definition Source: https://github.com/rust-av/av-decoders/blob/main/README.md The VideoDetails struct contains essential metadata for a video stream, including its dimensions, bit depth, chroma subsampling format, and frame rate. ```rust pub struct VideoDetails { pub width: usize, // Frame width in pixels pub height: usize, // Frame height in pixels pub bit_depth: usize, // Bits per color component pub chroma_sampling: ChromaSampling, // Subsampling format pub frame_rate: Rational32, // Frames per second } ``` -------------------------------- ### Decoder::get_video_details Source: https://context7.com/rust-av/av-decoders/llms.txt Inspects video metadata and returns a `&VideoDetails` struct. This struct contains information about the stream's dimensions, bit depth, chroma subsampling, frame rate, and an optional total frame count. ```APIDOC ## `Decoder::get_video_details` — Inspect video metadata Returns a `&VideoDetails` describing the stream's dimensions, bit depth, chroma subsampling, frame rate, and optional total frame count. ### Returns A reference to a `VideoDetails` struct containing metadata about the video stream. ### Example ```rust use av_decoders::{Decoder, DecoderError}; use v_frame::chroma::ChromaSubsampling; use num_rational::Rational32; fn print_video_info(path: &str) -> Result<(), DecoderError> { let decoder = Decoder::from_file(path)?; let d = decoder.get_video_details(); println!("Resolution : {}x{}", d.width, d.height); println!("Bit depth : {} bpp", d.bit_depth); println!("Frame rate : {}/{}", d.frame_rate.numer(), d.frame_rate.denom()); println!("Total frames: {:?}", d.total_frames); // None for Y4M (no header count) let subsampling = match d.chroma_sampling { ChromaSubsampling::Yuv420 => "4:2:0", ChromaSubsampling::Yuv422 => "4:2:2", ChromaSubsampling::Yuv444 => "4:4:4", ChromaSubsampling::Monochrome => "monochrome", }; println!("Subsampling : {subsampling}"); Ok(()) } ``` ``` -------------------------------- ### Decode Y4M from Standard Input Source: https://context7.com/rust-av/av-decoders/llms.txt Use Decoder::from_stdin to read Y4M video data piped from standard input, typically used with ffmpeg for streaming. Provides basic frame processing and error handling for end-of-file. ```rust use av_decoders::{Decoder, DecoderError}; fn main() -> Result<(), DecoderError> { // Usage: ffmpeg -i input.mp4 -f yuv4mpegpipe - | cargo run let mut decoder = Decoder::from_stdin()?; let details = decoder.get_video_details(); println!("Streaming {}x{}", details.width, details.height); let mut frame_count = 0usize; loop { match decoder.read_video_frame::() { Ok(frame) => { frame_count += 1; // Access luma plane data: // frame.planes[0] is the Y plane // frame.planes[1] is U, frame.planes[2] is V } Err(DecoderError::EndOfFile) => break, Err(e) => return Err(e), } } println!("Processed {frame_count} frames from stdin"); Ok(()) } ``` -------------------------------- ### Handle Decoder Errors and Decode Video Frames Source: https://context7.com/rust-av/av-decoders/llms.txt Opens a video file, decodes frames, and handles various `DecoderError` types including file I/O, format issues, and end-of-stream. ```rust use av_decoders::{Decoder, DecoderError}; fn open_and_decode(path: &str) -> Result { let mut decoder = match Decoder::from_file(path) { Ok(d) => d, Err(DecoderError::FileReadError { cause }) => return Err(format!("File error: {cause}")), Err(DecoderError::NoDecoder) => return Err("No decoder — enable 'ffmpeg' or 'vapoursynth' feature".into()), Err(DecoderError::UnsupportedFormat { fmt }) => return Err(format!("Unsupported pixel format: {fmt}")), Err(DecoderError::NoVideoStream) => return Err("File has no video stream".into()), Err(e) => return Err(format!("Decoder init error: {e}")), }; let mut frames = 0usize; loop { match decoder.read_video_frame::() { Ok(_frame) => frames += 1, Err(DecoderError::EndOfFile) => break, // normal end Err(DecoderError::GenericDecodeError { cause }) => return Err(format!("Decode error at frame {frames}: {cause}")), #[cfg(feature = "ffmpeg")] Err(DecoderError::FfmpegInternalError { cause }) => return Err(format!("FFmpeg error at frame {frames}: {cause}")), #[cfg(feature = "ffms2")] Err(DecoderError::Ffms2InternalError { cause }) => return Err(format!("FFMS2 error at frame {frames}: {cause}")), Err(e) => return Err(format!("Unexpected error: {e}")), } } Ok(frames) } fn main() { match open_and_decode("video.y4m") { Ok(n) => println!("Decoded {n} frames successfully"), Err(e) => eprintln!("Error: {e}"), } } ``` -------------------------------- ### Enable Luma-Only Decoding with `Decoder::set_luma_only` Source: https://context7.com/rust-av/av-decoders/llms.txt Instructs the decoder to only populate the Y (luma) plane, discarding U and V chroma planes. This mode is useful for processing that does not require color information. It can be toggled on and off. ```rust use av_decoders::{Decoder, DecoderError}; fn main() -> Result<(), DecoderError> { let mut decoder = Decoder::from_file("video.y4m")?; // Enable luma-only mode before reading frames decoder.set_luma_only(true); let mut luma_sum: u64 = 0; while let Ok(frame) = decoder.read_video_frame::() { // Only frame.planes[0] (Y) is populated; U/V planes are absent let y: &[u8] = frame.planes[0].data_origin(); luma_sum += y.iter().map(|&p| p as u64).sum::(); } println!("Total luma energy: {luma_sum}"); // Can be toggled back on at any time decoder.set_luma_only(false); Ok(()) } ``` -------------------------------- ### Decoder::get_video_frame Source: https://context7.com/rust-av/av-decoders/llms.txt Retrieves an arbitrary video frame by its index without advancing the sequential cursor. This method requires the `vapoursynth` feature to be enabled and a VapourSynth-backed decoder. ```APIDOC ## `Decoder::get_video_frame` — Random-access frame retrieval (VapourSynth) Retrieves an arbitrary frame by index without advancing the sequential cursor. Only available with the `vapoursynth` feature and a VapourSynth-backed decoder. ### Usage Example ```rust use av_decoders::{Decoder, DecoderError}; use std::collections::HashMap; fn main() -> Result<(), DecoderError> { let script = r#"import vapoursynth as vs core = vs.core clip = core.ffms2.Source("long_movie.mkv") clip.set_output() "#; let mut decoder = Decoder::from_script(script, HashMap::new())?; let details = *decoder.get_video_details(); // Jump directly to specific frames — no sequential decoding needed let keyframes = [0usize, 500, 1000, 2500, 5000]; for &idx in &keyframes { if details.total_frames.map_or(true, |n| idx < n) { let frame = decoder.get_video_frame::(idx)?; println!("Frame {idx}: {}x{}", frame.planes[0].cfg.width, frame.planes[0].cfg.height); } } Ok(()) } ``` ```