Skip to content

Media File Analysis with FFprobe

The typed-ffmpeg library provides functionality to analyze media files using FFmpeg's ffprobe utility. This allows you to extract detailed metadata about media files, including format information, stream details, and other relevant data.

Basic Usage

The main functions for media file analysis are:

  • probe(): Returns metadata as a Python dictionary
  • probe_obj(): Returns metadata as a Python dataclass

Here's a basic example:

import ffmpeg

# Get basic information about a media file
info = ffmpeg.probe("Digraph.gv.png")
print(info["streams"][0]["codec_type"])
info
{'streams': [{'index': 0,
   'codec_name': 'png',
   'codec_long_name': 'PNG (Portable Network Graphics) image',
   'codec_type': 'video',
   'codec_tag_string': '[0][0][0][0]',
   'codec_tag': '0x0000',
   'width': 548,
   'height': 131,
   'coded_width': 548,
   'coded_height': 131,
   'closed_captions': 0,
   'film_grain': 0,
   'has_b_frames': 0,
   'pix_fmt': 'rgba',
   'level': -99,
   'color_range': 'pc',
   'color_space': 'gbr',
   'refs': 1,
   'r_frame_rate': '25/1',
   'avg_frame_rate': '25/1',
   'time_base': '1/25',
   'disposition': {'default': 0,
    'dub': 0,
    'original': 0,
    'comment': 0,
    'lyrics': 0,
    'karaoke': 0,
    'forced': 0,
    'hearing_impaired': 0,
    'visual_impaired': 0,
    'clean_effects': 0,
    'attached_pic': 0,
    'timed_thumbnails': 0,
    'non_diegetic': 0,
    'captions': 0,
    'descriptions': 0,
    'metadata': 0,
    'dependent': 0,
    'still_image': 0}}],
 'format': {'filename': 'Digraph.gv.png',
  'nb_streams': 1,
  'nb_programs': 0,
  'format_name': 'png_pipe',
  'format_long_name': 'piped png sequence',
  'size': '13680',
  'probe_score': 99}}

Available Information

The probe functions can extract various types of information from media files:

  • Format information (container format, duration, bitrate)
  • Stream information (codecs, resolution, sample rate)
  • Program information
  • Chapter information
  • Frame and packet data

You can control which information is extracted using the following parameters:

  • show_format: Show format/container info (default: True)
  • show_streams: Show streams info (default: True)
  • show_programs: Show programs info (default: False)
  • show_chapters: Show chapters info (default: False)
  • show_frames: Show frames info (default: False)
  • show_packets: Show packets info (default: False)
  • show_program_version: Show program version (default: False)
  • show_library_versions: Show library versions (default: False)
  • show_pixel_formats: Show pixel formats (default: False)
  • show_error: Show error information (default: False)

Example: Detailed Stream Analysis

import ffmpeg

# Get detailed information about streams
info = ffmpeg.probe("video.mp4", show_streams=True, show_format=True)

# Print format information
print("Format Information:")
print(f"Format: {info['format']['format_name']}")
print(f"Duration: {float(info['format']['duration']):.2f} seconds")
print(f"Bitrate: {int(info['format']['bit_rate'])/1000:.0f} kbps")

# Print stream information
print("\nStream Information:")
for stream in info['streams']:
    if stream['codec_type'] == 'video':
        print(f"\nVideo Stream:")
        print(f"  Codec: {stream['codec_name']}")
        print(f"  Resolution: {stream['width']}x{stream['height']}")
        print(f"  Frame Rate: {eval(stream['r_frame_rate']):.2f} fps")
    elif stream['codec_type'] == 'audio':
        print(f"\nAudio Stream:")
        print(f"  Codec: {stream['codec_name']}")
        print(f"  Sample Rate: {stream['sample_rate']} Hz")
        print(f"  Channels: {stream['channels']}")

Using probe_obj()

The probe_obj() function returns the same information as probe(), but as a Python dataclass instead of a dictionary. This provides better type safety and IDE support:

import ffmpeg

# Get information as a dataclass
info = ffmpeg.probe_obj("Digraph.gv.png")

# Access information using dot notation
print(f"Streams: {len(info.streams.stream)}")

# Access stream information
for stream in info.streams.stream:
    if stream.codec_type == "video":
        print("\nVideo Stream:")
        print(f"  Codec: {stream.codec_name}")
        print(f"  Resolution: {stream.width}x{stream.height}")
info
Streams: 1

Video Stream:
  Codec: png
  Resolution: 548x131

ffprobeType(program_version=None, library_versions=None, pixel_formats=None, packets=None, frames=None, packets_and_frames=None, programs=None, streams=streamsType(stream=(streamType(disposition=streamDispositionType(default=0, dub=0, original=0, comment=0, lyrics=0, karaoke=0, forced=0, hearing_impaired=0, visual_impaired=0, clean_effects=0, attached_pic=0, timed_thumbnails=0, non_diegetic=0, captions=0, descriptions=0, metadata=0, dependent=0, still_image=0), tags=None, side_data_list=None, index=0, codec_name='png', codec_long_name='PNG (Portable Network Graphics) image', profile=None, codec_type='video', codec_tag='0x0000', codec_tag_string='[0][0][0][0]', extradata=None, extradata_size=None, extradata_hash=None, width=548, height=131, coded_width=548, coded_height=131, closed_captions=True, film_grain=True, has_b_frames=0, sample_aspect_ratio=None, display_aspect_ratio=None, pix_fmt='rgba', level=-99, color_range='pc', color_space='gbr', color_transfer=None, color_primaries=None, chroma_location=None, field_order=None, refs=1, sample_fmt=None, sample_rate=None, channels=None, channel_layout=None, bits_per_sample=None, initial_padding=None, id=None, r_frame_rate='25/1', avg_frame_rate='25/1', time_base='1/25', start_pts=None, start_time=None, duration_ts=None, duration=None, bit_rate=None, max_bit_rate=None, bits_per_raw_sample=None, nb_frames=None, nb_read_frames=None, nb_read_packets=None),)), chapters=None, format=formatType(tags=None, filename='Digraph.gv.png', nb_streams=1, nb_programs=0, nb_stream_groups=None, format_name='png_pipe', format_long_name='piped png sequence', start_time=None, duration=None, size=13680, bit_rate=None, probe_score=99), error=None)

Additional Options

Both probe() and probe_obj() support additional options:

  • cmd: Path or name of the ffprobe executable (default: "ffprobe")
  • timeout: Maximum time in seconds to wait for ffprobe to complete (default: None, wait indefinitely)
  • Additional ffprobe command line parameters can be passed as keyword arguments

Example with additional options:

import ffmpeg

# Get information with custom options
info = ffmpeg.probe(
    "video.mp4",
    cmd="/usr/local/bin/ffprobe",  # Custom ffprobe path
    timeout=30,  # 30 second timeout
    loglevel="quiet",  # Suppress ffprobe output
    show_frames=True,  # Include frame information
    show_packets=True  # Include packet information
)

Error Handling

The probe functions will raise exceptions in case of errors:

  • FFMpegExecuteError: If ffprobe returns a non-zero exit code
  • subprocess.TimeoutExpired: If the timeout is reached before ffprobe completes

Example of error handling:

import ffmpeg
from ffmpeg.exceptions import FFMpegExecuteError

try:
    info = ffmpeg.probe("nonexistent.mp4")
except FFMpegExecuteError as e:
    print(f"Error executing ffprobe: {e}")
    print(f"Command: {e.cmd}")
    print(f"Return code: {e.retcode}")
    print(f"Error output: {e.stderr.decode()}")
import ffmpeg
from ffmpeg.exceptions import FFMpegExecuteError

try:
    info = ffmpeg.probe("nonexistent.mp4")
except FFMpegExecuteError as e:
    print(f"Error executing ffprobe: {e}")
    print(f"Command: {e.cmd}")
    print(f"Return code: {e.retcode}")
    print(f"Error output: {e.stderr.decode()}")