mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
Enhanced FFmpeg Integration:
Added robust error handling and logging Improved binary verification and initialization Added proper GPU detection and hardware acceleration Optimized encoding parameters for different content types Improved File Operations: Added retry mechanisms for file operations Enhanced temporary directory management Improved cleanup of failed downloads Added proper permission handling Enhanced Queue Management: Fixed queue manager initialization Added better error recovery Improved status tracking and logging Enhanced cleanup of failed items Better Error Handling: Added comprehensive exception hierarchy Improved error logging and reporting Added fallback mechanisms for failures Enhanced error recovery strategies
This commit is contained in:
@@ -1,6 +1,186 @@
|
||||
"""FFmpeg management package"""
|
||||
"""FFmpeg module initialization"""
|
||||
|
||||
from videoarchiver.ffmpeg.exceptions import FFmpegError, GPUError, DownloadError
|
||||
from videoarchiver.ffmpeg.ffmpeg_manager import FFmpegManager
|
||||
import logging
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
__all__ = ['FFmpegManager', 'FFmpegError', 'GPUError', 'DownloadError']
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
|
||||
logger = logging.getLogger("VideoArchiver")
|
||||
|
||||
# Import components after logging is configured
|
||||
from .ffmpeg_manager import FFmpegManager
|
||||
from .video_analyzer import VideoAnalyzer
|
||||
from .gpu_detector import GPUDetector
|
||||
from .encoder_params import EncoderParams
|
||||
from .ffmpeg_downloader import FFmpegDownloader
|
||||
from .exceptions import (
|
||||
FFmpegError,
|
||||
DownloadError,
|
||||
VerificationError,
|
||||
EncodingError,
|
||||
AnalysisError,
|
||||
GPUError,
|
||||
HardwareAccelerationError,
|
||||
FFmpegNotFoundError,
|
||||
FFprobeError,
|
||||
CompressionError,
|
||||
FormatError,
|
||||
PermissionError,
|
||||
TimeoutError,
|
||||
ResourceError,
|
||||
QualityError,
|
||||
AudioError,
|
||||
BitrateError,
|
||||
)
|
||||
|
||||
class FFmpeg:
|
||||
"""Main FFmpeg interface"""
|
||||
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, base_dir: Optional[Path] = None):
|
||||
"""Singleton pattern to ensure only one FFmpeg instance"""
|
||||
if cls._instance is None:
|
||||
cls._instance = super(FFmpeg, cls).__new__(cls)
|
||||
cls._instance._initialized = False
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, base_dir: Optional[Path] = None):
|
||||
"""Initialize FFmpeg interface
|
||||
|
||||
Args:
|
||||
base_dir: Optional base directory for FFmpeg files. If not provided,
|
||||
will use the default directory in the module.
|
||||
"""
|
||||
# Skip initialization if already done
|
||||
if self._initialized:
|
||||
return
|
||||
|
||||
try:
|
||||
self._manager = FFmpegManager()
|
||||
logger.info(f"FFmpeg initialized at {self._manager.get_ffmpeg_path()}")
|
||||
logger.info(f"GPU support: {self._manager.gpu_info}")
|
||||
self._initialized = True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize FFmpeg interface: {e}")
|
||||
raise FFmpegError(f"FFmpeg initialization failed: {e}")
|
||||
|
||||
@property
|
||||
def ffmpeg_path(self) -> Path:
|
||||
"""Get path to FFmpeg binary"""
|
||||
return Path(self._manager.get_ffmpeg_path())
|
||||
|
||||
@property
|
||||
def gpu_info(self) -> Dict[str, bool]:
|
||||
"""Get GPU information"""
|
||||
return self._manager.gpu_info
|
||||
|
||||
def analyze_video(self, input_path: str) -> Dict[str, Any]:
|
||||
"""Analyze video content
|
||||
|
||||
Args:
|
||||
input_path: Path to input video file
|
||||
|
||||
Returns:
|
||||
Dict containing video analysis results
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(input_path):
|
||||
raise FileNotFoundError(f"Input file not found: {input_path}")
|
||||
return self._manager.analyze_video(input_path)
|
||||
except Exception as e:
|
||||
logger.error(f"Video analysis failed: {e}")
|
||||
raise AnalysisError(f"Failed to analyze video: {e}")
|
||||
|
||||
def get_compression_params(self, input_path: str, target_size_mb: int) -> Dict[str, str]:
|
||||
"""Get optimal compression parameters
|
||||
|
||||
Args:
|
||||
input_path: Path to input video file
|
||||
target_size_mb: Target file size in megabytes
|
||||
|
||||
Returns:
|
||||
Dict containing FFmpeg encoding parameters
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists(input_path):
|
||||
raise FileNotFoundError(f"Input file not found: {input_path}")
|
||||
return self._manager.get_compression_params(input_path, target_size_mb)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get compression parameters: {e}")
|
||||
raise EncodingError(f"Failed to get compression parameters: {e}")
|
||||
|
||||
def force_download(self) -> bool:
|
||||
"""Force re-download of FFmpeg binary
|
||||
|
||||
Returns:
|
||||
bool: True if download successful, False otherwise
|
||||
"""
|
||||
try:
|
||||
return self._manager.force_download()
|
||||
except Exception as e:
|
||||
logger.error(f"Force download failed: {e}")
|
||||
raise DownloadError(f"Failed to force download FFmpeg: {e}")
|
||||
|
||||
@property
|
||||
def version(self) -> str:
|
||||
"""Get FFmpeg version"""
|
||||
try:
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
[str(self.ffmpeg_path), "-version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.split()[2]
|
||||
raise FFmpegError(f"FFmpeg version check failed: {result.stderr}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get FFmpeg version: {e}")
|
||||
raise FFmpegError(f"Failed to get FFmpeg version: {e}")
|
||||
|
||||
# Initialize default instance
|
||||
try:
|
||||
ffmpeg = FFmpeg()
|
||||
logger.info(f"Default FFmpeg instance initialized (version {ffmpeg.version})")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize default FFmpeg instance: {e}")
|
||||
ffmpeg = None
|
||||
|
||||
__all__ = [
|
||||
'FFmpeg',
|
||||
'ffmpeg',
|
||||
'FFmpegManager',
|
||||
'VideoAnalyzer',
|
||||
'GPUDetector',
|
||||
'EncoderParams',
|
||||
'FFmpegDownloader',
|
||||
'FFmpegError',
|
||||
'DownloadError',
|
||||
'VerificationError',
|
||||
'EncodingError',
|
||||
'AnalysisError',
|
||||
'GPUError',
|
||||
'HardwareAccelerationError',
|
||||
'FFmpegNotFoundError',
|
||||
'FFprobeError',
|
||||
'CompressionError',
|
||||
'FormatError',
|
||||
'PermissionError',
|
||||
'TimeoutError',
|
||||
'ResourceError',
|
||||
'QualityError',
|
||||
'AudioError',
|
||||
'BitrateError',
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user