This commit is contained in:
2025-07-27 08:34:57 -07:00
parent 9faaf4ed57
commit 4cc14bc0a9
4 changed files with 62 additions and 12 deletions

View File

@@ -11,6 +11,28 @@ import atexit
import warnings
def test_nvenc_support() -> bool:
"""Test if NVENC encoding is available"""
try:
# Quick test with a 1-frame video
cmd = [
'ffmpeg', '-f', 'lavfi', '-i', 'testsrc=duration=0.1:size=320x240:rate=1',
'-c:v', 'h264_nvenc', '-t', '0.1', '-f', 'null', '-'
]
result = subprocess.run(
cmd,
capture_output=True,
timeout=10,
text=True
)
return result.returncode == 0
except (subprocess.TimeoutExpired, FileNotFoundError):
return False
class StreamingFrameWriter:
"""Write frames directly to ffmpeg via pipe for memory-efficient output"""
@@ -36,6 +58,16 @@ class StreamingFrameWriter:
self.frames_written = 0
self.ffmpeg_process = None
# Test NVENC support if GPU codec requested
if video_codec in ['h264_nvenc', 'hevc_nvenc']:
print(f"🔍 Testing NVENC support...")
if not test_nvenc_support():
print(f"❌ NVENC not available, switching to CPU encoding")
video_codec = 'libx264'
quality_preset = 'medium'
else:
print(f"✅ NVENC available")
# Build ffmpeg command
self.ffmpeg_cmd = self._build_ffmpeg_command(
video_codec, quality_preset, crf
@@ -134,23 +166,39 @@ class StreamingFrameWriter:
# Test if ffmpeg starts successfully (quick check)
import time
time.sleep(0.1) # Give ffmpeg time to fail if it's going to
time.sleep(0.2) # Give ffmpeg time to fail if it's going to
if self.ffmpeg_process.poll() is not None:
# Process already died - read error
stderr = self.ffmpeg_process.stderr.read().decode()
raise RuntimeError(f"FFmpeg failed immediately: {stderr}")
# Check for specific NVENC errors and provide better feedback
if 'nvenc' in ' '.join(self.ffmpeg_cmd):
if 'unsupported device' in stderr.lower():
print(f"❌ NVENC not available on this GPU - switching to CPU encoding")
elif 'cannot load' in stderr.lower() or 'not found' in stderr.lower():
print(f"❌ NVENC drivers not available - switching to CPU encoding")
else:
print(f"❌ NVENC encoding failed: {stderr}")
# Try CPU fallback
print(f"🔄 Falling back to CPU encoding (libx264)...")
self.ffmpeg_cmd = self._build_ffmpeg_command('libx264', 'medium', 18)
return self._start_ffmpeg()
else:
raise RuntimeError(f"FFmpeg failed: {stderr}")
# Set process to ignore SIGINT (Ctrl+C) - we'll handle it
if hasattr(signal, 'pthread_sigmask'):
signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGINT])
except Exception as e:
# Try CPU fallback if GPU encoding fails
# Final fallback if everything fails
if 'nvenc' in ' '.join(self.ffmpeg_cmd):
print(f"⚠️ GPU encoding failed, trying CPU fallback...")
print(f"⚠️ GPU encoding failed with error: {e}")
print(f"🔄 Falling back to CPU encoding...")
self.ffmpeg_cmd = self._build_ffmpeg_command('libx264', 'medium', 18)
self._start_ffmpeg()
return self._start_ffmpeg()
else:
raise RuntimeError(f"Failed to start ffmpeg: {e}")

View File

@@ -83,9 +83,10 @@ class SAM2StreamingProcessor:
# Set to eval mode
self.predictor.eval()
# Enable FP16 if requested
# Note: FP16 conversion can cause type mismatches with compiled models
# Let SAM2 handle precision internally via build_sam2_video_predictor options
if self.fp16 and self.device.type == 'cuda':
self.predictor = self.predictor.half()
print(" FP16 enabled via SAM2 internal settings")
except Exception as e:
raise RuntimeError(f"Failed to initialize SAM2 predictor: {e}")