Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/charliethomson/libffmpeg/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The ffprobe function executes FFprobe to analyze media files and extract information like format, duration, codec details, streams, and metadata. It provides a flexible interface for configuring FFprobe arguments and captures the complete output for parsing.

When to Use ffprobe

Use the ffprobe function when you need to:
  • Extract media file metadata (duration, bitrate, codec, etc.)
  • Analyze video/audio streams
  • Validate media file integrity
  • Get format-specific information
  • Check file properties before processing
For specifically extracting duration, consider the higher-level get_duration utility function.

Function Signature

pub async fn ffprobe<Prepare>(
    cancellation_token: CancellationToken,
    prepare: Prepare,
) -> Result<CommandExit, FfprobeError>
where
    Prepare: FnOnce(&mut Command),

Parameters

cancellation_token
CancellationToken
required
A tokio cancellation token for stopping the ffprobe process if needed
prepare
FnOnce(&mut Command)
required
A closure that configures the ffprobe command with arguments

Return Value

Returns Result<CommandExit, FfprobeError> where:
  • CommandExit contains:
    • exit_code: The process exit code
    • stdout_lines: Captured stdout lines (typically JSON or text output)
    • stderr_lines: Captured stderr lines (log messages)
  • FfprobeError::NotFound if the ffprobe binary cannot be located

Basic Usage

1

Create a cancellation token

Create a token to control the ffprobe lifetime:
use tokio_util::sync::CancellationToken;

let cancellation_token = CancellationToken::new();
2

Call ffprobe with arguments

Configure ffprobe arguments in the prepare closure:
use libffmpeg::ffprobe::ffprobe;
use std::path::Path;

let input = Path::new("video.mp4");

let result = ffprobe(cancellation_token, |cmd| {
    cmd.arg("-v").arg("quiet");
    cmd.arg("-print_format").arg("json");
    cmd.arg("-show_format");
    cmd.arg("-show_streams");
    cmd.arg(input);
}).await?;
3

Parse the output

Extract and parse the stdout data:
if let Some(exit) = result.exit_code {
    if exit.success {
        let json_output = result.stdout_lines.join("\n");
        // Parse JSON with serde_json or your preferred parser
        println!("FFprobe output: {}", json_output);
    }
}

Complete Example: JSON Output

use libffmpeg::ffprobe::ffprobe;
use tokio_util::sync::CancellationToken;
use serde_json::Value;
use std::path::PathBuf;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let input = PathBuf::from("video.mp4");
    let cancellation_token = CancellationToken::new();
    
    // Run ffprobe with JSON output
    let result = ffprobe(cancellation_token, |cmd| {
        cmd.arg("-v").arg("quiet");
        cmd.arg("-print_format").arg("json");
        cmd.arg("-show_format");
        cmd.arg("-show_streams");
        cmd.arg(&input);
    }).await?;
    
    // Check exit code
    let exit_code = result.exit_code
        .ok_or_else(|| anyhow::anyhow!("No exit code"))?;
    
    if !exit_code.success {
        anyhow::bail!("ffprobe failed: {}", result.stderr_lines.join("\n"));
    }
    
    // Parse JSON output
    let json_str = result.stdout_lines.join("\n");
    let data: Value = serde_json::from_str(&json_str)?;
    
    // Extract format information
    if let Some(format) = data["format"].as_object() {
        println!("Format: {}", format["format_name"].as_str().unwrap_or("unknown"));
        println!("Duration: {} seconds", format["duration"].as_str().unwrap_or("unknown"));
        println!("Bitrate: {} bps", format["bit_rate"].as_str().unwrap_or("unknown"));
    }
    
    // Extract stream information
    if let Some(streams) = data["streams"].as_array() {
        for (i, stream) in streams.iter().enumerate() {
            let codec_type = stream["codec_type"].as_str().unwrap_or("unknown");
            let codec_name = stream["codec_name"].as_str().unwrap_or("unknown");
            println!("Stream {}: {} ({})", i, codec_type, codec_name);
            
            if codec_type == "video" {
                println!("  Resolution: {}x{}",
                    stream["width"].as_i64().unwrap_or(0),
                    stream["height"].as_i64().unwrap_or(0)
                );
                println!("  FPS: {}", stream["r_frame_rate"].as_str().unwrap_or("unknown"));
            }
        }
    }
    
    Ok(())
}

Common Use Cases

Get File Duration

use libffmpeg::ffprobe::ffprobe;

let result = ffprobe(cancellation_token, |cmd| {
    cmd.arg("-v").arg("quiet");
    cmd.arg("-show_entries").arg("format=duration");
    cmd.arg("-of").arg("default=noprint_wrappers=1:nokey=1");
    cmd.arg(input);
}).await?;

if let Some(duration_str) = result.stdout_lines.first() {
    let duration_secs: f64 = duration_str.parse()?;
    println!("Duration: {:.2} seconds", duration_secs);
}
Use the get_duration utility function for a higher-level API that handles all the parsing for you.

Get Video Codec Information

let result = ffprobe(cancellation_token, |cmd| {
    cmd.arg("-v").arg("error");
    cmd.arg("-select_streams").arg("v:0"); // First video stream
    cmd.arg("-show_entries").arg("stream=codec_name,width,height,r_frame_rate");
    cmd.arg("-of").arg("json");
    cmd.arg(input);
}).await?;

let json_str = result.stdout_lines.join("\n");
let data: Value = serde_json::from_str(&json_str)?;

if let Some(stream) = data["streams"][0].as_object() {
    println!("Codec: {}", stream["codec_name"].as_str().unwrap_or("unknown"));
    println!("Resolution: {}x{}",
        stream["width"].as_i64().unwrap_or(0),
        stream["height"].as_i64().unwrap_or(0)
    );
}

Check Audio Streams

let result = ffprobe(cancellation_token, |cmd| {
    cmd.arg("-v").arg("error");
    cmd.arg("-select_streams").arg("a"); // All audio streams
    cmd.arg("-show_entries").arg("stream=codec_name,sample_rate,channels");
    cmd.arg("-of").arg("json");
    cmd.arg(input);
}).await?;

let json_str = result.stdout_lines.join("\n");
let data: Value = serde_json::from_str(&json_str)?;

if let Some(streams) = data["streams"].as_array() {
    println!("Found {} audio stream(s)", streams.len());
    for stream in streams {
        println!("  Codec: {}", stream["codec_name"].as_str().unwrap_or("unknown"));
        println!("  Sample rate: {} Hz", stream["sample_rate"].as_str().unwrap_or("unknown"));
        println!("  Channels: {}", stream["channels"].as_i64().unwrap_or(0));
    }
}

Validate File Integrity

let result = ffprobe(cancellation_token, |cmd| {
    cmd.arg("-v").arg("error");
    cmd.arg("-show_format");
    cmd.arg("-of").arg("json");
    cmd.arg(input);
}).await?;

if let Some(exit) = result.exit_code {
    if exit.success && !result.stdout_lines.is_empty() {
        println!("File is valid");
    } else {
        eprintln!("File may be corrupted: {}", result.stderr_lines.join("\n"));
    }
}

Output Formats

FFprobe supports multiple output formats via the -of or -print_format argument:
cmd.arg("-print_format").arg("json");
Best for programmatic parsing with strong typing.

Plain Text

cmd.arg("-of").arg("default=noprint_wrappers=1:nokey=1");
Useful for single-value extraction (like duration).

CSV

cmd.arg("-print_format").arg("csv");
Good for batch processing multiple files.

XML

cmd.arg("-print_format").arg("xml");
Useful when integrating with XML-based systems.

Binary Discovery

The function locates the ffprobe binary by:
  1. Checking the LIBFFMPEG_FFPROBE_PATH environment variable
  2. Searching the system PATH
If not found, it returns FfprobeError::NotFound.
Set a custom ffprobe location:
export LIBFFMPEG_FFPROBE_PATH=/usr/local/bin/ffprobe

Error Handling

use libffmpeg::ffprobe::{ffprobe, FfprobeError};

match ffprobe(cancellation_token, |cmd| {
    cmd.arg("-show_format");
    cmd.arg("input.mp4");
}).await {
    Ok(result) => {
        if let Some(exit) = result.exit_code {
            if exit.success {
                println!("Success: {}", result.stdout_lines.join("\n"));
            } else {
                eprintln!("ffprobe failed with code: {:?}", exit.code);
                eprintln!("Stderr: {}", result.stderr_lines.join("\n"));
            }
        }
    }
    Err(FfprobeError::NotFound) => {
        eprintln!("ffprobe binary not found in PATH");
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}

Implementation Details

From the source code at libffmpeg/src/ffprobe/proc.rs:9-50:
pub async fn ffprobe<Prepare>(
    cancellation_token: CancellationToken,
    prepare: Prepare,
) -> Result<CommandExit, FfprobeError>
where
    Prepare: FnOnce(&mut Command),
{
    tracing::debug!("Starting ffprobe execution");

    let ffprobe_path = find_ffprobe().ok_or(FfprobeError::NotFound).inspect_err(
        |e| tracing::error!(error =% e, error_context =? e, "ffprobe binary not found"),
    )?;

    tracing::info!(
        ffprobe_path = %ffprobe_path.display(),
        "Executing ffprobe"
    );

    libcmd::run(
        ffprobe_path,
        None,
        cancellation_token.child_token(),
        prepare,
    )
    .await
    .inspect(|exit| {
        tracing::debug!(exit = exit.as_value(), "ffprobe completed");
    })
    .inspect_err(|e| {
        tracing::error!(
            error = %e,
            "ffprobe execution failed"
        );
    })
    .map_err(Into::into)
}
Key characteristics:
  • No output monitoring (stdout/stderr captured in result)
  • Uses libcmd::run with None for monitor
  • Includes structured tracing
  • Creates a child cancellation token

Performance Considerations

FFprobe needs to read the entire file to extract some information (like duration). For large files, this can take time. Consider:
  • Using -threads to parallelize decoding
  • Limiting analysis with -analyzeduration and -probesize
  • Caching results for frequently-accessed files

Optimize for Speed

let result = ffprobe(cancellation_token, |cmd| {
    cmd.arg("-threads").arg("4"); // Use 4 threads
    cmd.arg("-analyzeduration").arg("1000000"); // Analyze first 1 second
    cmd.arg("-probesize").arg("1000000"); // Probe first 1MB
    cmd.arg("-v").arg("quiet");
    cmd.arg("-show_format");
    cmd.arg(input);
}).await?;

Next Steps

Duration Extraction

Use get_duration for easier duration extraction

FFmpeg Execution

Run FFmpeg with the extracted metadata

Error Handling

Handle FfprobeError types

API Reference

Complete ffprobe API documentation