Module code >> skvideo.io.ffprobe
Fork me on GitHub

Source code for skvideo.io.ffprobe

import os
import subprocess as sp
import warnings

from ..utils import *
import skvideo  # accessed via attributes so setFFmpegPath() updates are seen
from .. import _FFPROBE_APPLICATION

[docs] def ffprobe(filename): """get metadata by using ffprobe Checks the output of ffprobe on the desired video file. MetaData is then parsed into a dictionary. Parameters ---------- filename : string Path to the video file Returns ------- metaDict : dict Dictionary containing all header-based information about the passed-in source video. For each codec type present in the file (e.g. ``video``, ``audio``, ``subtitle``), the dictionary contains two entries: - ``<type>`` — the first stream of that type (backward-compatible with the pre-#165 single-stream behavior). - ``<type>_streams`` — a list of *all* streams of that type, in the order ffprobe reported them. Use this when the file contains multiple streams of the same codec type (issue #165). Example for a file with one video stream and two audio streams:: info = ffprobe("foo.mkv") info["video"] # first (and only) video stream info["audio"] # first audio stream info["audio_streams"] # list of both audio streams """ # check if FFMPEG exists in the path if not skvideo._HAS_FFMPEG: raise RuntimeError("Cannot find installation of real FFmpeg (which comes with ffprobe).") filename = os.fspath(filename) try: command = [skvideo._FFMPEG_PATH + "/" + _FFPROBE_APPLICATION, "-v", "error", "-show_streams", "-print_format", "xml", filename] xml = check_output(command) d = xmltodictparser(xml)["ffprobe"]["streams"] # ffprobe's XML output produces either a single "stream" dict or a list of them # depending on stream count. Normalize to a list. streams = d["stream"] if not isinstance(streams, list): streams = [streams] # Seed the well-known plural keys so callers can iterate without # defensive `info.get('audio_streams', [])` — empty list is the # documented "no streams of this type" signal (issue #165). result = {"audio_streams": [], "video_streams": []} for stream in streams: codec_type = stream["@codec_type"].lower() # First stream of each type lives at the unindexed key (backward-compat) if codec_type not in result: result[codec_type] = stream # All streams of each type live at the plural key (issue #165) result.setdefault(codec_type + "_streams", []).append(stream) return result except Exception as exc: # Returning {} is load-bearing: raw/headerless video (e.g. .yuv) has # no probeable streams and the reader falls back to inputdict's # -s / -pix_fmt. But silently swallowing every failure also hides a # genuinely unreadable/corrupt file behind a later "No way to # determine width or height" error. Warn with the cause so the real # reason is visible, then preserve the {} fallback. warnings.warn( "ffprobe could not parse %r (%s); returning empty metadata. " "Expected for raw video (supply -s and -pix_fmt via inputdict); " "for a normal media file this usually means it is unreadable or " "not a recognized format." % (filename, exc), UserWarning, ) return {}