Skip to content

Commit

Permalink
Update video_processing.py
Browse files Browse the repository at this point in the history
  • Loading branch information
bturkus committed Dec 2, 2024
1 parent eaf9308 commit 6e3f44f
Showing 1 changed file with 110 additions and 23 deletions.
133 changes: 110 additions & 23 deletions ami_scripts/video_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,43 +104,129 @@ def transcribe_directory(input_directory, model, output_format):
output_writer(transcription_response, file.stem)


def detect_audio_pan(input_file, probe_duration=60):
"""
Detect whether the audio is isolated to the left or right channel for each audio stream.
Probes only the first `probe_duration` seconds of the file.
"""
# Use ffprobe to get the number of audio streams
ffprobe_command = [
"ffprobe", "-i", str(input_file),
"-show_entries", "stream=index:stream=codec_type",
"-select_streams", "a", "-of", "compact=p=0:nk=1", "-v", "0"
]
ffprobe_result = subprocess.run(ffprobe_command, capture_output=True, text=True)
audio_streams = [int(line.split('|')[0]) for line in ffprobe_result.stdout.splitlines() if "audio" in line]

print(f"Detected {len(audio_streams)} audio streams: {audio_streams} in {input_file}")

# Analyze each audio stream
pan_filters = []
for stream_index in audio_streams:
print(f"Analyzing audio stream: {stream_index}")

# Analyze left channel
left_analysis_command = [
"ffmpeg", "-t", str(probe_duration), "-i", str(input_file),
"-map", f"0:{stream_index}", # Explicitly map the audio stream by index
"-af", "pan=mono|c0=c0,volumedetect", "-f", "null", "-"
]
left_result = subprocess.run(left_analysis_command, capture_output=True, text=True)
left_output = left_result.stderr

# Analyze right channel
right_analysis_command = [
"ffmpeg", "-t", str(probe_duration), "-i", str(input_file),
"-map", f"0:{stream_index}", # Explicitly map the audio stream by index
"-af", "pan=mono|c0=c1,volumedetect", "-f", "null", "-"
]
right_result = subprocess.run(right_analysis_command, capture_output=True, text=True)
right_output = right_result.stderr

# Parse mean volumes
def get_mean_volume(output):
match = re.search(r"mean_volume:\s*(-?\d+(\.\d+)?)", output)
return float(match.group(1)) if match else None

left_mean_volume = get_mean_volume(left_output)
right_mean_volume = get_mean_volume(right_output)

# Debugging output for clarity
print(f"Stream {stream_index} - Left channel mean volume: {left_mean_volume}")
print(f"Stream {stream_index} - Right channel mean volume: {right_mean_volume}")

# Handle cases where volume data is unavailable
if left_mean_volume is None or right_mean_volume is None:
print(f"Stream {stream_index}: Unable to analyze audio. Skipping this stream.")
continue

# Determine if one channel is significantly louder than the other
silence_threshold = -60.0 # dB, adjust as needed
if right_mean_volume > silence_threshold and left_mean_volume <= silence_threshold:
print(f"Stream {stream_index}: Detected right-channel-only audio. Applying right-to-center panning.")
pan_filters.append(f"[0:{stream_index}]pan=stereo|c0=c1|c1=c1[outa{stream_index}]")
elif left_mean_volume > silence_threshold and right_mean_volume <= silence_threshold:
print(f"Stream {stream_index}: Detected left-channel-only audio. Applying left-to-center panning.")
pan_filters.append(f"[0:{stream_index}]pan=stereo|c0=c0|c1=c0[outa{stream_index}]")
else:
print(f"Stream {stream_index}: Audio is balanced or both channels are silent. No panning applied.")

# Combine pan filters for FFmpeg command
return pan_filters


def convert_to_mp4(input_file, input_directory, audio_pan):
output_file_name = f"{input_file.stem.replace('_pm', '')}_sc.mp4"
output_file = input_directory / output_file_name

# Default audio filter
audio_filter = None

# Set audio pan filter based on user input
if audio_pan == "left":
audio_filter = "[0:a]pan=stereo|c0=c0|c1=c0[outa]"
elif audio_pan == "right":
audio_filter = "[0:a]pan=stereo|c0=c1|c1=c1[outa]"
# Detect audio pan automatically if set to "auto"
if audio_pan == "auto":
pan_filters = detect_audio_pan(input_file)
else:
pan_filters = []
if audio_pan == "left":
pan_filters.append("[0:a]pan=stereo|c0=c0|c1=c0[outa]")
elif audio_pan == "right":
pan_filters.append("[0:a]pan=stereo|c0=c1|c1=c1[outa]")

# FFmpeg command setup
command = [
"ffmpeg",
"-i", str(input_file),
"-map", "0:v", "-c:v", "libx264", "-movflags", "faststart", "-pix_fmt", "yuv420p",
"-b:v", "3500000", "-bufsize", "1750000", "-maxrate", "3500000", "-vf", "yadif",
]

# Add audio mapping and filter if specified
if audio_filter:
command.extend([
"-filter_complex", audio_filter,
"-map", "[outa]" # Map the output of the pan filter as the audio stream
])
# Add audio mapping and filters if specified
if pan_filters:
if len(pan_filters) == 1:
# Single audio stream case
# Ensure consistent output label `[outa]`
pan_filters[0] = pan_filters[0].replace("[outa1]", "[outa]")
command.extend([
"-filter_complex", pan_filters[0],
"-map", "[outa]"
])
else:
# Multi-audio stream case
filter_complex = ";".join(pan_filters)
command.extend([
"-filter_complex", filter_complex,
])
for idx in range(len(pan_filters)):
command.extend(["-map", f"[outa{idx}]"])
else:
command.extend([
"-map", "0:a", # Default audio mapping if no pan is specified
])
command.extend(["-map", "0:a", "-c:a", "aac", "-b:a", "320000", "-ar", "48000"])

# Add audio encoding options
command.extend(["-c:a", "aac", "-b:a", "320000", "-ar", "48000", str(output_file)])
# Add output file
command.append(str(output_file))

print(f"FFmpeg command: {' '.join(command)}") # Debugging output
subprocess.check_call(command)
print(f"MP4 created: {output_file}")
return output_file



def convert_mov_file(input_file, input_directory):
"""Convert a MOV file to FFV1 and MP4 formats using FFmpeg"""
Expand Down Expand Up @@ -280,8 +366,10 @@ def main():
parser.add_argument("-o", "--output", help="Path to save csv (optional). If provided, MediaInfo extraction will be performed.", required=False)
parser.add_argument("-m", "--model", default='medium', choices=['tiny', 'base', 'small', 'medium', 'large'], help='The Whisper model to use')
parser.add_argument("-f", "--format", default='vtt', choices=['vtt', 'srt', 'txt', 'json'], help='The subtitle output format to use')
parser.add_argument("-p", "--audio-pan", choices=["left", "right", "none"], default="none", help="Pan audio to center from left or right channel.")

parser.add_argument("-p", "--audio-pan",
choices=["left", "right", "none", "auto"],
default="none",
help="Pan audio to center from left, right, or auto-detect mono audio.")

args = parser.parse_args()

Expand Down Expand Up @@ -362,5 +450,4 @@ def main():
csvwriter.writerows(file_data)

if __name__ == "__main__":
main()

main()

0 comments on commit 6e3f44f

Please sign in to comment.