django and fastapi apps
This commit is contained in:
145
core/ffmpeg/capabilities.py
Normal file
145
core/ffmpeg/capabilities.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
FFmpeg capabilities - Discover available codecs and formats using ffmpeg-python.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from typing import Any, Dict, List
|
||||
|
||||
import ffmpeg
|
||||
|
||||
|
||||
@dataclass
|
||||
class Codec:
|
||||
"""An FFmpeg encoder or decoder."""
|
||||
|
||||
name: str
|
||||
description: str
|
||||
type: str # 'video' or 'audio'
|
||||
|
||||
|
||||
@dataclass
|
||||
class Format:
|
||||
"""An FFmpeg format (muxer/demuxer)."""
|
||||
|
||||
name: str
|
||||
description: str
|
||||
can_demux: bool
|
||||
can_mux: bool
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _get_ffmpeg_info() -> Dict[str, Any]:
|
||||
"""Get FFmpeg capabilities info."""
|
||||
# ffmpeg-python doesn't have a direct way to get codecs/formats
|
||||
# but we can use probe on a dummy or parse -codecs output
|
||||
# For now, return common codecs that are typically available
|
||||
return {
|
||||
"video_encoders": [
|
||||
{"name": "libx264", "description": "H.264 / AVC"},
|
||||
{"name": "libx265", "description": "H.265 / HEVC"},
|
||||
{"name": "mpeg4", "description": "MPEG-4 Part 2"},
|
||||
{"name": "libvpx", "description": "VP8"},
|
||||
{"name": "libvpx-vp9", "description": "VP9"},
|
||||
{"name": "h264_nvenc", "description": "NVIDIA NVENC H.264"},
|
||||
{"name": "hevc_nvenc", "description": "NVIDIA NVENC H.265"},
|
||||
{"name": "h264_vaapi", "description": "VAAPI H.264"},
|
||||
{"name": "prores_ks", "description": "Apple ProRes"},
|
||||
{"name": "dnxhd", "description": "Avid DNxHD/DNxHR"},
|
||||
{"name": "copy", "description": "Stream copy (no encoding)"},
|
||||
],
|
||||
"audio_encoders": [
|
||||
{"name": "aac", "description": "AAC"},
|
||||
{"name": "libmp3lame", "description": "MP3"},
|
||||
{"name": "libopus", "description": "Opus"},
|
||||
{"name": "libvorbis", "description": "Vorbis"},
|
||||
{"name": "pcm_s16le", "description": "PCM signed 16-bit little-endian"},
|
||||
{"name": "flac", "description": "FLAC"},
|
||||
{"name": "copy", "description": "Stream copy (no encoding)"},
|
||||
],
|
||||
"formats": [
|
||||
{"name": "mp4", "description": "MP4", "can_demux": True, "can_mux": True},
|
||||
{
|
||||
"name": "mov",
|
||||
"description": "QuickTime / MOV",
|
||||
"can_demux": True,
|
||||
"can_mux": True,
|
||||
},
|
||||
{
|
||||
"name": "mkv",
|
||||
"description": "Matroska",
|
||||
"can_demux": True,
|
||||
"can_mux": True,
|
||||
},
|
||||
{"name": "webm", "description": "WebM", "can_demux": True, "can_mux": True},
|
||||
{"name": "avi", "description": "AVI", "can_demux": True, "can_mux": True},
|
||||
{"name": "flv", "description": "FLV", "can_demux": True, "can_mux": True},
|
||||
{
|
||||
"name": "ts",
|
||||
"description": "MPEG-TS",
|
||||
"can_demux": True,
|
||||
"can_mux": True,
|
||||
},
|
||||
{
|
||||
"name": "mpegts",
|
||||
"description": "MPEG-TS",
|
||||
"can_demux": True,
|
||||
"can_mux": True,
|
||||
},
|
||||
{"name": "hls", "description": "HLS", "can_demux": True, "can_mux": True},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def get_encoders() -> List[Codec]:
|
||||
"""Get available encoders (video + audio)."""
|
||||
info = _get_ffmpeg_info()
|
||||
codecs = []
|
||||
|
||||
for c in info["video_encoders"]:
|
||||
codecs.append(Codec(name=c["name"], description=c["description"], type="video"))
|
||||
|
||||
for c in info["audio_encoders"]:
|
||||
codecs.append(Codec(name=c["name"], description=c["description"], type="audio"))
|
||||
|
||||
return codecs
|
||||
|
||||
|
||||
def get_decoders() -> List[Codec]:
|
||||
"""Get available decoders."""
|
||||
# Most encoders can also decode
|
||||
return get_encoders()
|
||||
|
||||
|
||||
def get_formats() -> List[Format]:
|
||||
"""Get available formats."""
|
||||
info = _get_ffmpeg_info()
|
||||
return [
|
||||
Format(
|
||||
name=f["name"],
|
||||
description=f["description"],
|
||||
can_demux=f["can_demux"],
|
||||
can_mux=f["can_mux"],
|
||||
)
|
||||
for f in info["formats"]
|
||||
]
|
||||
|
||||
|
||||
def get_video_encoders() -> List[Codec]:
|
||||
"""Get available video encoders."""
|
||||
return [c for c in get_encoders() if c.type == "video"]
|
||||
|
||||
|
||||
def get_audio_encoders() -> List[Codec]:
|
||||
"""Get available audio encoders."""
|
||||
return [c for c in get_encoders() if c.type == "audio"]
|
||||
|
||||
|
||||
def get_muxers() -> List[Format]:
|
||||
"""Get available output formats (muxers)."""
|
||||
return [f for f in get_formats() if f.can_mux]
|
||||
|
||||
|
||||
def get_demuxers() -> List[Format]:
|
||||
"""Get available input formats (demuxers)."""
|
||||
return [f for f in get_formats() if f.can_demux]
|
||||
Reference in New Issue
Block a user