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
Create a cancellation token
Create a token to control the ffprobe lifetime: use tokio_util :: sync :: CancellationToken ;
let cancellation_token = CancellationToken :: new ();
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 ? ;
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.
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 " ));
}
}
FFprobe supports multiple output formats via the -of or -print_format argument:
JSON (Recommended)
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:
Checking the LIBFFMPEG_FFPROBE_PATH environment variable
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
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