please merge
This commit is contained in:
@@ -398,39 +398,35 @@ class VideoProcessor:
|
|||||||
overlap_frames: Number of overlapping frames
|
overlap_frames: Number of overlapping frames
|
||||||
audio_source: Audio source file for final video
|
audio_source: Audio source file for final video
|
||||||
"""
|
"""
|
||||||
from .streaming_video_writer import StreamingVideoWriter
|
|
||||||
|
|
||||||
if not chunk_files:
|
if not chunk_files:
|
||||||
raise ValueError("No chunk files to merge")
|
raise ValueError("No chunk files to merge")
|
||||||
|
|
||||||
print(f"🎬 Streaming merge: {len(chunk_files)} chunks → {output_path}")
|
print(f"🎬 Streaming merge: {len(chunk_files)} chunks → {output_path}")
|
||||||
|
|
||||||
# Initialize streaming writer
|
# Use simple concatenation approach - load and merge all frames sequentially
|
||||||
writer = StreamingVideoWriter(
|
all_frames = []
|
||||||
output_path=output_path,
|
|
||||||
fps=self.video_info['fps'],
|
|
||||||
audio_source=audio_source
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Process each chunk without accumulation
|
# Process each chunk without accumulation
|
||||||
for i, chunk_file in enumerate(chunk_files):
|
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)
|
# Load chunk (this is the only copy in memory)
|
||||||
chunk_data = np.load(str(chunk_file))
|
chunk_data = np.load(str(chunk_file))
|
||||||
frames = chunk_data['frames'].tolist() # Convert to list of arrays
|
frames = chunk_data['frames'].tolist() # Convert to list of arrays
|
||||||
chunk_data.close()
|
chunk_data.close()
|
||||||
|
|
||||||
# Write chunk with streaming writer
|
# Handle overlap blending (simple approach - skip overlapping frames from previous chunks)
|
||||||
writer.write_chunk(
|
if i > 0 and overlap_frames > 0:
|
||||||
frames=frames,
|
# Skip the first overlap_frames from this chunk (they overlap with previous)
|
||||||
chunk_index=i,
|
frames = frames[overlap_frames:]
|
||||||
overlap_frames=overlap_frames if i > 0 else 0,
|
print(f" ✂️ Skipped {overlap_frames} overlapping frames")
|
||||||
blend_with_previous=(i > 0 and overlap_frames > 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
# 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
|
del frames, chunk_data
|
||||||
|
|
||||||
# Delete chunk file to free disk space
|
# Delete chunk file to free disk space
|
||||||
@@ -443,16 +439,67 @@ class VideoProcessor:
|
|||||||
# Aggressive cleanup every chunk
|
# Aggressive cleanup every chunk
|
||||||
self._aggressive_memory_cleanup(f"After processing chunk {i}")
|
self._aggressive_memory_cleanup(f"After processing chunk {i}")
|
||||||
|
|
||||||
# Finalize the video
|
# Save final video using existing method
|
||||||
writer.finalize()
|
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:
|
except Exception as e:
|
||||||
print(f"❌ Streaming merge failed: {e}")
|
print(f"❌ Streaming merge failed: {e}")
|
||||||
writer.cleanup()
|
# Cleanup
|
||||||
|
if 'all_frames' in locals():
|
||||||
|
del all_frames
|
||||||
|
gc.collect()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
if 'all_frames' in locals():
|
||||||
|
del all_frames
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
print(f"✅ Streaming merge complete: {output_path}")
|
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,
|
def merge_overlapping_chunks(self,
|
||||||
chunk_results: List[List[np.ndarray]],
|
chunk_results: List[List[np.ndarray]],
|
||||||
overlap_frames: int) -> List[np.ndarray]:
|
overlap_frames: int) -> List[np.ndarray]:
|
||||||
|
|||||||
Reference in New Issue
Block a user