From 4958c503dd9b5d7f490802319af3fcfd19d7e825 Mon Sep 17 00:00:00 2001 From: Scott Register Date: Sat, 26 Jul 2025 16:02:07 -0700 Subject: [PATCH] please merge --- vr180_matting/video_processor.py | 87 ++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/vr180_matting/video_processor.py b/vr180_matting/video_processor.py index d9e4dcd..e2a2d5b 100644 --- a/vr180_matting/video_processor.py +++ b/vr180_matting/video_processor.py @@ -398,39 +398,35 @@ class VideoProcessor: overlap_frames: Number of overlapping frames audio_source: Audio source file for final video """ - from .streaming_video_writer import StreamingVideoWriter - if not chunk_files: raise ValueError("No chunk files to merge") print(f"🎬 Streaming merge: {len(chunk_files)} chunks → {output_path}") - # Initialize streaming writer - writer = StreamingVideoWriter( - output_path=output_path, - fps=self.video_info['fps'], - audio_source=audio_source - ) + # Use simple concatenation approach - load and merge all frames sequentially + all_frames = [] try: # Process each chunk without accumulation for i, chunk_file in enumerate(chunk_files): - print(f"📼 Processing chunk {i+1}/{len(chunk_files)}: {chunk_file.name}") + print(f"📼 Loading 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)) frames = chunk_data['frames'].tolist() # Convert to list of arrays chunk_data.close() - # Write chunk with streaming writer - writer.write_chunk( - frames=frames, - chunk_index=i, - overlap_frames=overlap_frames if i > 0 else 0, - blend_with_previous=(i > 0 and overlap_frames > 0) - ) + # Handle overlap blending (simple approach - skip overlapping frames from previous chunks) + if i > 0 and overlap_frames > 0: + # Skip the first overlap_frames from this chunk (they overlap with previous) + frames = frames[overlap_frames:] + print(f" ✂️ Skipped {overlap_frames} overlapping frames") - # Immediately free memory + # Add frames to final sequence + all_frames.extend(frames) + print(f" ✅ Added {len(frames)} frames (total: {len(all_frames)})") + + # Immediately free chunk memory del frames, chunk_data # Delete chunk file to free disk space @@ -443,16 +439,67 @@ class VideoProcessor: # Aggressive cleanup every chunk self._aggressive_memory_cleanup(f"After processing chunk {i}") - # Finalize the video - writer.finalize() + # Save final video using existing method + print(f"📹 Saving final video with {len(all_frames)} frames...") + self.save_video(all_frames, output_path) + + # Add audio if provided + if audio_source: + self._add_audio_to_video(output_path, audio_source) except Exception as e: print(f"❌ Streaming merge failed: {e}") - writer.cleanup() + # Cleanup + if 'all_frames' in locals(): + del all_frames + gc.collect() raise + finally: + # Cleanup + if 'all_frames' in locals(): + del all_frames + gc.collect() + print(f"✅ Streaming merge complete: {output_path}") + def _add_audio_to_video(self, video_path: str, audio_source: str): + """Add audio to video using ffmpeg""" + import subprocess + import tempfile + + try: + # Create temporary file for output with audio + temp_path = Path(video_path).with_suffix('.temp.mp4') + + cmd = [ + 'ffmpeg', '-y', + '-i', str(video_path), # Input video (no audio) + '-i', str(audio_source), # Input audio source + '-c:v', 'copy', # Copy video without re-encoding + '-c:a', 'aac', # Encode audio as AAC + '-map', '0:v:0', # Map video from first input + '-map', '1:a:0', # Map audio from second input + '-shortest', # Match shortest stream duration + str(temp_path) + ] + + print(f"🎵 Adding audio: {audio_source} → {video_path}") + result = subprocess.run(cmd, capture_output=True, text=True) + + if result.returncode != 0: + print(f"⚠️ Audio addition failed: {result.stderr}") + # Keep original video without audio + return + + # Replace original with audio version + Path(video_path).unlink() + temp_path.rename(video_path) + print(f"✅ Audio added successfully") + + except Exception as e: + print(f"⚠️ Could not add audio: {e}") + def merge_overlapping_chunks(self, chunk_results: List[List[np.ndarray]], overlap_frames: int) -> List[np.ndarray]: