django and fastapi apps
This commit is contained in:
92
core/ffmpeg/probe.py
Normal file
92
core/ffmpeg/probe.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
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,
|
||||
)
|
||||
Reference in New Issue
Block a user