Files
Pac-cogs/videoarchiver/ffmpeg/__init__.py
pacnpal 8503fc6fdd 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
2024-11-15 03:21:25 +00:00

187 lines
5.5 KiB
Python

"""FFmpeg module initialization"""
import logging
import sys
import os
from pathlib import Path
from typing import Dict, Any, Optional
# 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',
]