typed-ffmpeg
typed-ffmpeg copied to clipboard
How to change filter_complex
Please tell me how to implement the following.
I have a list of videos, they are of different sizes, and I need to overlay them on the main video. I composed the following FFmpeg command:
ffmpeg \
-i main_video.mp4 \
-f concat -safe 0 -i list.txt \
-filter_complex \
"[1:v]scale=1280x720:force_original_aspect_ratio=decrease,setsar=1[scaled]; \
[scaled]concat=n=1:v=1:a=0[fg]; \
[0:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1[bg]; \
[bg][fg]overlay=(W-w)/2:(H-h)/2:shortest=1[outv]; \
[0:a]volume=0.5[bg_audio]; \
[1:a]concat=n=1:v=0:a=1,volume=1.5[concat_audio]; \
[bg_audio][concat_audio]amix=inputs=2:duration=longest:dropout_transition=2[a]" \
-map "[outv]" \
-map "[a]" \
-c:v libx264 -crf 18 -preset fast \
-c:a aac -b:a 192k \
output.mp4
After that, I wrote a Python script using the library:
input_concat = ffmpeg.input(
filename="list.txt",
f="concat",
extra_options={"safe": 0},
)
scaled_video = input_concat.video.scale(
w=1280,
h=720,
force_original_aspect_ratio="decrease",
).setsar(max=1)
foreground = ffmpeg.filters.concat(scaled_video, n=1, v=1, a=0)
main_video_input = ffmpeg.input(filename=main_video_path)
background = (
main_video_input.video
.scale(w=1920, h=1080, force_original_aspect_ratio="decrease")
.pad(width=1920, height=1080, x="(ow-iw)/2", y="(oh-ih)/2")
.boxblur(luma_radius=10)
.setsar(max=1)
)
output_video = ffmpeg.filters.overlay(
background,
foreground.video(0),
x="(W-w)/2", y="(H-h)/2",
shortest=1,
ts_sync_mode=1,
)
# Concatenate audio
background_audio = main_video_input.audio.volume(volume=0.5)
concat_audio = input_concat.audio.volume(volume=1.5)
output_audio = ffmpeg.filters.amix(
background_audio,
concat_audio,
inputs=2,
duration="longest",
dropout_transition=2,
)
f = (
ffmpeg.output(
output_video,
output_audio,
filename=final_output_path,
vcodec="libx264",
acodec="aac",
r=self.FPS,
b=self.BITRATE,
extra_options={
"crf": 18,
"preset": "fast",
},
t=10,
)
.overwrite_output()
)
f.run(
overwrite_output=True,
capture_stderr=True,
capture_stdout=True,
)
As a result, I get the following FFmpeg command:
ffmpeg \
-y -t 10 \
-i test_video.mp4 \
-f concat -safe 0 -i list.txt \
-filter_complex \
"[0:v]scale=w=1920:h=1080:force_original_aspect_ratio=decrease[s0]; \
[1:v]scale=w=1280:h=720:force_original_aspect_ratio=decrease[s1]; \
[0:a]volume=volume=0.5[s2]; \
[1:a]volume=volume=1.5[s3]; \
[s0]pad=1920:1080:(ow-iw)/2:(oh-ih)/2[s4]; \
[s1]setsar=1[s5]; \
[s4]boxblur=10[s7]; \
[s5]concat=n=1:v=1:a=0[s8]; \
[s7]setsar=1[s9]; \
[s2][s3]amix=inputs=2:duration=longest:dropout_transition=2[s6]; \
[s9][s8]overlay=x=(W-w)/2:y=(H-h)/2:shortest=1[s10]" \
-map '[s10]' -map '[s6]' -r 25 \
-vcodec libx264 -b 10485760k -acodec aac -crf 18 \
-preset fast \
video_gen.mp4
However, it doesn’t work as intended—the overlaid videos last only 1 second and abruptly cut off. I figured out that the problem lies in the following: these lines need to be swapped:
[1:v]scale=w=1280:h=720:force_original_aspect_ratio=decrease[s1];
[0:v]scale=w=1920:h=1080:force_original_aspect_ratio=decrease[s0];
As soon as I swap them, everything starts working. How can I do this using the library?
Also, while working with the library, the following question arose.
As you can see from my command, I need to specify setsar=1, but in the library, the .setsar() method has several parameters: sar and max. How can I specify setsar=1?
Can I pass the entire foreground stream here instead of just video(0)?
output_video = ffmpeg.filters.overlay(
background,
foreground.video(0),
x="(W-w)/2", y="(H-h)/2",
shortest=1,
ts_sync_mode=1,
)
I checked the issues and examples, and the input method used to have a safe parameter, but now it's missing. How can I specify it? Through extra_options?