Loading page...Загружаем страницу...正在加载页面...
AtlasRepo

Adding a timed overlay and an end card to vertical videos with one ffmpeg call (Python)

Description and use

Add a banner from 3 s to the end and a 3.5‑second end card to vertical videos in a single ffmpeg call, without modifying the renderer.

Problem

Add a banner from 3 s to the end and a 3.5‑second end card to a rendered vertical video without modifying the renderer.

Outcome

Each 40‑second clip is processed in 10–20 s on a normal desktop CPU, adding the banner from 3 s onward and a 3.5‑s silent end card in a single encode.

Workflow

  • Probe source for width, height, fps, and audio sample rate.
  • Prepare inputs: rendered video, end‑card PNG, silence audio, banner PNG.
  • Build ffmpeg filter graph: scale banner, overlay from t=3, scale end card, normalize formats, concat video and audio streams.
  • Execute single ffmpeg command via subprocess.
  • Move original file to name.noend.mp4 and overwrite only on success to ensure idempotence.

Evidence

Doing it as a post‑process step keeps the renderer simple and lets me swap the banner content later.

Source

Mistake 1: the comma inside enable= gte(t,3) looks fine, but inside -filter_complex the comma is a filter separator, so ffmpeg splits the expression and fails with a confusing parse error. Escape it as gte(t\,3).

Source

Mistake 2: concat needs every video segment to have the same size, frame rate, pixel format and sample aspect ratio. Normalising both sides with scale=…,fps=…,format=yuv420p,setsar=1 fixed every "Input link parameters do not match" error I got.

Source

Mistake 3: audio channel layout. My renderer writes mono 24 kHz audio. I first generated the silence as cl=stereo, and concat complained about mismatched audio. Generate the silence with the same sample rate and layout as the source (anullsrc=r=24000:cl=mono).

Source

The function above writes to a new file. In the pipeline I move the original to name.noend.mp4 first and only overwrite on success. If the process ever crashes halfway, the original is still there, and the presence of that file also makes the step idempotent: if it exists, the video was already processed, so skip it.

Source

  • Record date: 2026-10-19T16:41:33.266Z