fix concat

This commit is contained in:
2025-07-26 16:29:59 -07:00
parent 4958c503dd
commit fa945b9c3e

View File

@@ -401,15 +401,19 @@ class VideoProcessor:
if not chunk_files:
raise ValueError("No chunk files to merge")
print(f"🎬 Streaming merge: {len(chunk_files)} chunks → {output_path}")
print(f"🎬 TRUE Streaming merge: {len(chunk_files)} chunks → {output_path}")
# Use simple concatenation approach - load and merge all frames sequentially
all_frames = []
# Create temporary directory for frame images
import tempfile
temp_frames_dir = Path(tempfile.mkdtemp(prefix="merge_frames_"))
frame_counter = 0
try:
# Process each chunk without accumulation
print(f"📁 Using temp frames dir: {temp_frames_dir}")
# Process each chunk and save frames directly to disk
for i, chunk_file in enumerate(chunk_files):
print(f"📼 Loading chunk {i+1}/{len(chunk_files)}: {chunk_file.name}")
print(f"📼 Processing chunk {i+1}/{len(chunk_files)}: {chunk_file.name}")
# Load chunk (this is the only copy in memory)
chunk_data = np.load(str(chunk_file))
@@ -422,9 +426,16 @@ class VideoProcessor:
frames = frames[overlap_frames:]
print(f" ✂️ Skipped {overlap_frames} overlapping frames")
# Add frames to final sequence
all_frames.extend(frames)
print(f" ✅ Added {len(frames)} frames (total: {len(all_frames)})")
# Save frames directly to disk (no accumulation in memory)
for frame in frames:
frame_path = temp_frames_dir / f"frame_{frame_counter: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:
raise RuntimeError(f"Failed to save frame {frame_counter}")
frame_counter += 1
print(f" ✅ Saved {len(frames)} frames to disk (total: {frame_counter})")
# Immediately free chunk memory
del frames, chunk_data
@@ -439,9 +450,9 @@ class VideoProcessor:
# Aggressive cleanup every chunk
self._aggressive_memory_cleanup(f"After processing chunk {i}")
# Save final video using existing method
print(f"📹 Saving final video with {len(all_frames)} frames...")
self.save_video(all_frames, output_path)
# Create final video directly from frame images using ffmpeg
print(f"📹 Creating final video from {frame_counter} frames...")
self._create_video_from_frames(temp_frames_dir, Path(output_path), frame_counter)
# Add audio if provided
if audio_source:
@@ -449,19 +460,72 @@ class VideoProcessor:
except Exception as e:
print(f"❌ Streaming merge failed: {e}")
# Cleanup
if 'all_frames' in locals():
del all_frames
gc.collect()
raise
finally:
# Cleanup
if 'all_frames' in locals():
del all_frames
# Cleanup temporary frames directory
try:
if temp_frames_dir.exists():
import shutil
shutil.rmtree(temp_frames_dir)
print(f"🗑️ Cleaned up temp frames dir: {temp_frames_dir}")
except Exception as e:
print(f"⚠️ Could not cleanup temp frames dir: {e}")
# Memory cleanup
gc.collect()
print(f"✅ Streaming merge complete: {output_path}")
print(f" TRUE Streaming merge complete: {output_path}")
def _create_video_from_frames(self, frames_dir: Path, output_path: Path, frame_count: int):
"""Create video directly from frame images using ffmpeg (memory efficient)"""
import subprocess
frame_pattern = str(frames_dir / "frame_%06d.jpg")
fps = self.video_info['fps'] if hasattr(self, 'video_info') and self.video_info else 30.0
print(f"🎬 Creating video with ffmpeg: {frame_count} frames at {fps} fps")
# Use GPU encoding if available, fallback to CPU
gpu_cmd = [
'ffmpeg', '-y', # -y to overwrite output file
'-framerate', str(fps),
'-i', frame_pattern,
'-c:v', 'h264_nvenc', # NVIDIA GPU encoder
'-preset', 'fast',
'-cq', '18', # Quality for GPU encoding
'-pix_fmt', 'yuv420p',
str(output_path)
]
cpu_cmd = [
'ffmpeg', '-y', # -y to overwrite output file
'-framerate', str(fps),
'-i', frame_pattern,
'-c:v', 'libx264', # CPU encoder
'-preset', 'medium',
'-crf', '18', # Quality for CPU encoding
'-pix_fmt', 'yuv420p',
str(output_path)
]
# Try GPU first
print(f"🚀 Trying GPU encoding...")
result = subprocess.run(gpu_cmd, capture_output=True, text=True)
if result.returncode != 0:
print("⚠️ GPU encoding failed, using CPU...")
print(f"🔄 CPU encoding...")
result = subprocess.run(cpu_cmd, capture_output=True, text=True)
else:
print("✅ GPU encoding successful!")
if result.returncode != 0:
print(f"❌ FFmpeg stdout: {result.stdout}")
print(f"❌ FFmpeg stderr: {result.stderr}")
raise RuntimeError(f"FFmpeg failed with return code {result.returncode}")
print(f"✅ Video created successfully: {output_path}")
def _add_audio_to_video(self, video_path: str, audio_source: str):
"""Add audio to video using ffmpeg"""