memory stuff
This commit is contained in:
@@ -3,8 +3,8 @@ input:
|
|||||||
|
|
||||||
processing:
|
processing:
|
||||||
scale_factor: 0.5 # A40 can handle 0.5 well
|
scale_factor: 0.5 # A40 can handle 0.5 well
|
||||||
chunk_size: 0 # Auto-calculate based on A40's 48GB VRAM
|
chunk_size: 200 # Smaller chunks to prevent OOM (was auto-calculated to 423)
|
||||||
overlap_frames: 60
|
overlap_frames: 30 # Reduced overlap
|
||||||
|
|
||||||
detection:
|
detection:
|
||||||
confidence_threshold: 0.7
|
confidence_threshold: 0.7
|
||||||
|
|||||||
@@ -65,18 +65,25 @@ class VR180Processor(VideoProcessor):
|
|||||||
Returns:
|
Returns:
|
||||||
Tuple of (left_eye_frame, right_eye_frame)
|
Tuple of (left_eye_frame, right_eye_frame)
|
||||||
"""
|
"""
|
||||||
if self.sbs_split_point == 0:
|
# Always calculate split point based on current frame width
|
||||||
self.sbs_split_point = frame.shape[1] // 2
|
# This handles scaled frames correctly
|
||||||
|
|
||||||
# Debug: Check if split point is valid for this frame
|
|
||||||
frame_width = frame.shape[1]
|
frame_width = frame.shape[1]
|
||||||
if self.sbs_split_point >= frame_width:
|
current_split_point = frame_width // 2
|
||||||
print(f"WARNING: Split point {self.sbs_split_point} >= frame width {frame_width}")
|
|
||||||
self.sbs_split_point = frame_width // 2
|
|
||||||
print(f"Adjusted split point to {self.sbs_split_point}")
|
|
||||||
|
|
||||||
left_eye = frame[:, :self.sbs_split_point]
|
# Debug info on first use
|
||||||
right_eye = frame[:, self.sbs_split_point:]
|
if self.sbs_split_point == 0:
|
||||||
|
print(f"Frame dimensions: {frame.shape[1]}x{frame.shape[0]}")
|
||||||
|
print(f"Split point: {current_split_point}")
|
||||||
|
self.sbs_split_point = current_split_point # Store for reference
|
||||||
|
|
||||||
|
left_eye = frame[:, :current_split_point]
|
||||||
|
right_eye = frame[:, current_split_point:]
|
||||||
|
|
||||||
|
# Validate both eyes have content
|
||||||
|
if left_eye.size == 0:
|
||||||
|
raise RuntimeError(f"Left eye frame is empty after split (frame width: {frame_width})")
|
||||||
|
if right_eye.size == 0:
|
||||||
|
raise RuntimeError(f"Right eye frame is empty after split (frame width: {frame_width})")
|
||||||
|
|
||||||
return left_eye, right_eye
|
return left_eye, right_eye
|
||||||
|
|
||||||
@@ -189,7 +196,7 @@ class VR180Processor(VideoProcessor):
|
|||||||
temp_frames_dir = temp_video_path.parent / f"frames_{temp_video_path.stem}"
|
temp_frames_dir = temp_video_path.parent / f"frames_{temp_video_path.stem}"
|
||||||
temp_frames_dir.mkdir(exist_ok=True)
|
temp_frames_dir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
# Save frames as individual images
|
# Save frames as individual images (using JPEG for smaller file size)
|
||||||
print("Saving frames as images...")
|
print("Saving frames as images...")
|
||||||
for i, frame in enumerate(eye_frames):
|
for i, frame in enumerate(eye_frames):
|
||||||
# Check if frame is empty
|
# Check if frame is empty
|
||||||
@@ -204,8 +211,10 @@ class VR180Processor(VideoProcessor):
|
|||||||
if i == 0:
|
if i == 0:
|
||||||
print(f"First frame to save: shape={frame.shape}, dtype={frame.dtype}, empty={frame.size == 0}")
|
print(f"First frame to save: shape={frame.shape}, dtype={frame.dtype}, empty={frame.size == 0}")
|
||||||
|
|
||||||
frame_path = temp_frames_dir / f"frame_{i:06d}.png"
|
# Use JPEG instead of PNG for smaller files (faster I/O, less disk space)
|
||||||
success = cv2.imwrite(str(frame_path), frame)
|
frame_path = temp_frames_dir / f"frame_{i:06d}.jpg"
|
||||||
|
# Use high quality JPEG to minimize compression artifacts
|
||||||
|
success = cv2.imwrite(str(frame_path), frame, [cv2.IMWRITE_JPEG_QUALITY, 95])
|
||||||
if not success:
|
if not success:
|
||||||
print(f"Frame {i} details: shape={frame.shape}, dtype={frame.dtype}, size={frame.size}")
|
print(f"Frame {i} details: shape={frame.shape}, dtype={frame.dtype}, size={frame.size}")
|
||||||
raise RuntimeError(f"Failed to save frame {i} as image")
|
raise RuntimeError(f"Failed to save frame {i} as image")
|
||||||
@@ -213,22 +222,53 @@ class VR180Processor(VideoProcessor):
|
|||||||
if i % 50 == 0:
|
if i % 50 == 0:
|
||||||
print(f"Saved {i}/{len(eye_frames)} frames")
|
print(f"Saved {i}/{len(eye_frames)} frames")
|
||||||
|
|
||||||
|
# Force garbage collection every 100 frames to free memory
|
||||||
|
if i % 100 == 0:
|
||||||
|
import gc
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
# Use ffmpeg to create video from images
|
# Use ffmpeg to create video from images
|
||||||
import subprocess
|
import subprocess
|
||||||
# Use the original video's framerate - access through parent class
|
# Use the original video's framerate - access through parent class
|
||||||
original_fps = self.fps if hasattr(self, 'fps') else 30.0
|
original_fps = self.fps if hasattr(self, 'fps') else 30.0
|
||||||
print(f"Using framerate: {original_fps} fps")
|
print(f"Using framerate: {original_fps} fps")
|
||||||
ffmpeg_cmd = [
|
# Try GPU encoding first, fallback to CPU
|
||||||
|
gpu_cmd = [
|
||||||
'ffmpeg', '-y', # -y to overwrite output file
|
'ffmpeg', '-y', # -y to overwrite output file
|
||||||
'-framerate', str(original_fps),
|
'-framerate', str(original_fps),
|
||||||
'-i', str(temp_frames_dir / 'frame_%06d.png'),
|
'-i', str(temp_frames_dir / 'frame_%06d.jpg'),
|
||||||
'-c:v', 'libx264',
|
'-c:v', 'h264_nvenc', # NVIDIA GPU encoder
|
||||||
|
'-preset', 'fast', # GPU preset
|
||||||
|
'-cq', '18', # Quality for GPU encoding
|
||||||
'-pix_fmt', 'yuv420p',
|
'-pix_fmt', 'yuv420p',
|
||||||
'-crf', '18', # Higher quality (lower CRF)
|
|
||||||
'-preset', 'slow', # Better compression
|
|
||||||
str(temp_video_path)
|
str(temp_video_path)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
cpu_cmd = [
|
||||||
|
'ffmpeg', '-y', # -y to overwrite output file
|
||||||
|
'-framerate', str(original_fps),
|
||||||
|
'-i', str(temp_frames_dir / 'frame_%06d.jpg'),
|
||||||
|
'-c:v', 'libx264', # CPU encoder
|
||||||
|
'-pix_fmt', 'yuv420p',
|
||||||
|
'-crf', '18', # Quality for CPU encoding
|
||||||
|
'-preset', 'medium',
|
||||||
|
str(temp_video_path)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Try GPU first
|
||||||
|
print(f"Trying GPU encoding: {' '.join(gpu_cmd)}")
|
||||||
|
result = subprocess.run(gpu_cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print("GPU encoding failed, trying CPU...")
|
||||||
|
print(f"GPU error: {result.stderr}")
|
||||||
|
ffmpeg_cmd = cpu_cmd
|
||||||
|
print(f"Using CPU encoding: {' '.join(ffmpeg_cmd)}")
|
||||||
|
result = subprocess.run(ffmpeg_cmd, capture_output=True, text=True)
|
||||||
|
else:
|
||||||
|
print("GPU encoding successful!")
|
||||||
|
ffmpeg_cmd = gpu_cmd
|
||||||
|
|
||||||
print(f"Running ffmpeg: {' '.join(ffmpeg_cmd)}")
|
print(f"Running ffmpeg: {' '.join(ffmpeg_cmd)}")
|
||||||
result = subprocess.run(ffmpeg_cmd, capture_output=True, text=True)
|
result = subprocess.run(ffmpeg_cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user