mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
162 lines
5.4 KiB
Python
162 lines
5.4 KiB
Python
"""Module for verifying FFmpeg functionality"""
|
|
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional
|
|
|
|
# try:
|
|
# Try relative imports first
|
|
from .exceptions import (
|
|
TimeoutError,
|
|
VerificationError,
|
|
EncodingError,
|
|
handle_ffmpeg_error,
|
|
)
|
|
|
|
# except ImportError:
|
|
# Fall back to absolute imports if relative imports fail
|
|
# from videoarchiver.ffmpeg.exceptions import (
|
|
# TimeoutError,
|
|
# VerificationError,
|
|
# EncodingError,
|
|
# handle_ffmpeg_error
|
|
# )
|
|
|
|
logger = logging.getLogger("FFmpegVerification")
|
|
|
|
|
|
class VerificationManager:
|
|
"""Handles verification of FFmpeg functionality"""
|
|
|
|
def __init__(self, process_manager):
|
|
self.process_manager = process_manager
|
|
|
|
def verify_ffmpeg(
|
|
self, ffmpeg_path: Path, ffprobe_path: Path, gpu_info: Dict[str, bool]
|
|
) -> None:
|
|
"""Verify FFmpeg functionality with comprehensive checks
|
|
|
|
Args:
|
|
ffmpeg_path: Path to FFmpeg binary
|
|
ffprobe_path: Path to FFprobe binary
|
|
gpu_info: Dictionary of GPU availability
|
|
|
|
Raises:
|
|
VerificationError: If verification fails
|
|
TimeoutError: If verification times out
|
|
EncodingError: If required encoders are missing
|
|
"""
|
|
try:
|
|
# Check FFmpeg version
|
|
self._verify_ffmpeg_version(ffmpeg_path)
|
|
|
|
# Check FFprobe version
|
|
self._verify_ffprobe_version(ffprobe_path)
|
|
|
|
# Check FFmpeg capabilities
|
|
self._verify_ffmpeg_capabilities(ffmpeg_path, gpu_info)
|
|
|
|
logger.info("FFmpeg verification completed successfully")
|
|
|
|
except Exception as e:
|
|
logger.error(f"FFmpeg verification failed: {e}")
|
|
if isinstance(e, (TimeoutError, EncodingError, VerificationError)):
|
|
raise
|
|
raise VerificationError(f"FFmpeg verification failed: {e}")
|
|
|
|
def _verify_ffmpeg_version(self, ffmpeg_path: Path) -> None:
|
|
"""Verify FFmpeg version"""
|
|
try:
|
|
result = self._execute_command(
|
|
[str(ffmpeg_path), "-version"], "FFmpeg version check"
|
|
)
|
|
logger.info(f"FFmpeg version: {result.stdout.split()[2]}")
|
|
except Exception as e:
|
|
raise VerificationError(f"FFmpeg version check failed: {e}")
|
|
|
|
def _verify_ffprobe_version(self, ffprobe_path: Path) -> None:
|
|
"""Verify FFprobe version"""
|
|
try:
|
|
result = self._execute_command(
|
|
[str(ffprobe_path), "-version"], "FFprobe version check"
|
|
)
|
|
logger.info(f"FFprobe version: {result.stdout.split()[2]}")
|
|
except Exception as e:
|
|
raise VerificationError(f"FFprobe version check failed: {e}")
|
|
|
|
def _verify_ffmpeg_capabilities(
|
|
self, ffmpeg_path: Path, gpu_info: Dict[str, bool]
|
|
) -> None:
|
|
"""Verify FFmpeg capabilities and encoders"""
|
|
try:
|
|
result = self._execute_command(
|
|
[str(ffmpeg_path), "-hide_banner", "-encoders"],
|
|
"FFmpeg capabilities check",
|
|
)
|
|
|
|
# Verify required encoders
|
|
required_encoders = self._get_required_encoders(gpu_info)
|
|
available_encoders = result.stdout.lower()
|
|
|
|
missing_encoders = [
|
|
encoder
|
|
for encoder in required_encoders
|
|
if encoder not in available_encoders
|
|
]
|
|
|
|
if missing_encoders:
|
|
logger.warning(f"Missing encoders: {', '.join(missing_encoders)}")
|
|
if "libx264" in missing_encoders:
|
|
raise EncodingError("Required encoder libx264 not available")
|
|
|
|
except Exception as e:
|
|
if isinstance(e, EncodingError):
|
|
raise
|
|
raise VerificationError(f"FFmpeg capabilities check failed: {e}")
|
|
|
|
def _execute_command(
|
|
self, command: List[str], operation: str, timeout: int = 10
|
|
) -> subprocess.CompletedProcess:
|
|
"""Execute a command with proper error handling"""
|
|
try:
|
|
result = self.process_manager.execute_command(
|
|
command, timeout=timeout, check=False
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
error = handle_ffmpeg_error(result.stderr)
|
|
logger.error(f"{operation} failed: {result.stderr}")
|
|
raise error
|
|
|
|
return result
|
|
|
|
except subprocess.TimeoutExpired:
|
|
raise TimeoutError(f"{operation} timed out")
|
|
except Exception as e:
|
|
if isinstance(e, (TimeoutError, EncodingError)):
|
|
raise
|
|
raise VerificationError(f"{operation} failed: {e}")
|
|
|
|
def _get_required_encoders(self, gpu_info: Dict[str, bool]) -> List[str]:
|
|
"""Get list of required encoders based on GPU availability"""
|
|
required_encoders = ["libx264"]
|
|
|
|
if gpu_info["nvidia"]:
|
|
required_encoders.append("h264_nvenc")
|
|
elif gpu_info["amd"]:
|
|
required_encoders.append("h264_amf")
|
|
elif gpu_info["intel"]:
|
|
required_encoders.append("h264_qsv")
|
|
|
|
return required_encoders
|
|
|
|
def verify_binary_permissions(self, binary_path: Path) -> None:
|
|
"""Verify and set binary permissions"""
|
|
try:
|
|
if os.name != "nt": # Not Windows
|
|
os.chmod(str(binary_path), 0o755)
|
|
except Exception as e:
|
|
raise VerificationError(f"Failed to set binary permissions: {e}")
|