Music_Splitter / video_processor.py
Omar-youssef's picture
updated
9c75488
from pathlib import Path
import subprocess
import os
import streamlit as st
class VideoProcessor:
def __init__(self, input_video, output_dir):
self.input_video = Path(input_video)
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.temp_audio = self.output_dir / "extracted_audio.wav"
self.final_video = self.output_dir / "final_video.mp4"
def extract_audio(self):
"""Extract audio from video file"""
try:
# First, verify the input video file exists and is readable
if not self.input_video.exists():
st.error(f"Input video file not found: {self.input_video}")
return None
# Print file size and check if it's not empty
file_size = os.path.getsize(self.input_video)
#st.info(f"Input video file size: {file_size} bytes")
if file_size == 0:
st.error("Input video file is empty")
return None
# Ensure output directory exists
self.temp_audio.parent.mkdir(parents=True, exist_ok=True)
# Construct FFmpeg command with detailed logging
command = [
"ffmpeg",
"-v", "error", # Change to error to reduce verbose output
"-i", str(self.input_video),
"-vn", # No video
"-acodec", "pcm_s16le", # 16-bit PCM
"-ar", "44100", # 44.1kHz sample rate
"-ac", "2", # Stereo
"-y", # Overwrite output file if it exists
str(self.temp_audio)
]
# Run FFmpeg command and capture output
try:
# Use subprocess.run with timeout to prevent hanging
process = subprocess.run(
command,
capture_output=True,
text=True,
timeout=60 # 60 seconds timeout
)
# Check for any errors
if process.returncode != 0:
st.error(f"FFmpeg error: {process.stderr}")
st.error(f"FFmpeg command: {' '.join(command)}")
return None
except subprocess.TimeoutExpired:
st.error("Audio extraction timed out")
return None
except Exception as e:
st.error(f"Unexpected error during FFmpeg execution: {str(e)}")
return None
# Verify the output audio file exists and is not empty
if not self.temp_audio.exists():
st.error("Audio extraction failed: Output file is missing")
return None
file_size = os.path.getsize(self.temp_audio)
if file_size == 0:
st.error("Audio extraction failed: Output file is empty")
return None
#st.success(f"Audio extracted successfully to {self.temp_audio}")
return str(self.temp_audio)
except Exception as e:
st.error(f"Unexpected error during audio extraction: {str(e)}")
return None
def combine_video_audio(self, vocals_path):
"""Combine original video with vocals only"""
try:
# Verify input files exist
if not self.input_video.exists():
st.error(f"Original video not found: {self.input_video}")
return None
if not Path(vocals_path).exists():
st.error(f"Vocals audio not found: {vocals_path}")
return None
# Construct FFmpeg command
command = [
"ffmpeg",
"-v", "verbose", # Enable verbose logging
"-i", str(self.input_video),
"-i", vocals_path,
"-c:v", "copy", # Copy video stream without re-encoding
"-c:a", "aac", # Use AAC codec for audio
"-b:a", "192k", # Set audio bitrate
"-map", "0:v:0",
"-map", "1:a:0",
"-y", # Overwrite output file if it exists
str(self.final_video)
]
# Run FFmpeg command and capture output
process = subprocess.run(
command,
capture_output=True,
text=True,
check=False
)
# Print FFmpeg output for debugging
print("FFmpeg stdout:", process.stdout)
print("FFmpeg stderr:", process.stderr)
# Check if the command was successful
if process.returncode != 0:
st.error(f"FFmpeg error during video combination: {process.stderr}")
return None
# Verify the output video file exists and is not empty
if not self.final_video.exists() or os.path.getsize(self.final_video) == 0:
st.error("Video combination failed: Output file is missing or empty")
return None
print(f"Video combined successfully: {self.final_video}")
return str(self.final_video)
except Exception as e:
st.error(f"Error during video combination: {str(e)}")
print(f"Exception details: {str(e)}")
return None