fix concat
This commit is contained in:
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user