93 lines
2.3 KiB
Python
93 lines
2.3 KiB
Python
"""
|
|
FFmpeg probe module - Extract metadata from media files using ffprobe.
|
|
"""
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Dict, Optional
|
|
|
|
import ffmpeg
|
|
|
|
|
|
@dataclass
|
|
class ProbeResult:
|
|
"""Structured ffprobe result."""
|
|
|
|
duration: Optional[float]
|
|
file_size: int
|
|
|
|
# Video
|
|
video_codec: Optional[str]
|
|
width: Optional[int]
|
|
height: Optional[int]
|
|
framerate: Optional[float]
|
|
video_bitrate: Optional[int]
|
|
|
|
# Audio
|
|
audio_codec: Optional[str]
|
|
audio_channels: Optional[int]
|
|
audio_samplerate: Optional[int]
|
|
audio_bitrate: Optional[int]
|
|
|
|
# Raw data
|
|
raw: Dict[str, Any]
|
|
|
|
|
|
def probe_file(file_path: str) -> ProbeResult:
|
|
"""
|
|
Run ffprobe and return structured result.
|
|
|
|
Args:
|
|
file_path: Path to the media file
|
|
|
|
Returns:
|
|
ProbeResult with extracted metadata
|
|
|
|
Raises:
|
|
ffmpeg.Error: If ffprobe fails
|
|
"""
|
|
data = ffmpeg.probe(file_path)
|
|
|
|
# Extract video stream info
|
|
video_stream = next(
|
|
(s for s in data.get("streams", []) if s.get("codec_type") == "video"), {}
|
|
)
|
|
|
|
# Extract audio stream info
|
|
audio_stream = next(
|
|
(s for s in data.get("streams", []) if s.get("codec_type") == "audio"), {}
|
|
)
|
|
|
|
format_info = data.get("format", {})
|
|
|
|
# Parse framerate (e.g., "30000/1001" -> 29.97)
|
|
framerate = None
|
|
if "r_frame_rate" in video_stream:
|
|
try:
|
|
num, den = video_stream["r_frame_rate"].split("/")
|
|
framerate = float(num) / float(den)
|
|
except (ValueError, ZeroDivisionError):
|
|
pass
|
|
|
|
# Parse duration
|
|
duration = None
|
|
if "duration" in format_info:
|
|
try:
|
|
duration = float(format_info["duration"])
|
|
except ValueError:
|
|
pass
|
|
|
|
return ProbeResult(
|
|
duration=duration,
|
|
file_size=int(format_info.get("size", 0)),
|
|
video_codec=video_stream.get("codec_name"),
|
|
width=video_stream.get("width"),
|
|
height=video_stream.get("height"),
|
|
framerate=framerate,
|
|
video_bitrate=int(video_stream.get("bit_rate", 0)) or None,
|
|
audio_codec=audio_stream.get("codec_name"),
|
|
audio_channels=audio_stream.get("channels"),
|
|
audio_samplerate=int(audio_stream.get("sample_rate", 0)) or None,
|
|
audio_bitrate=int(audio_stream.get("bit_rate", 0)) or None,
|
|
raw=data,
|
|
)
|