Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging multiple videos in a template/layout with Python FFMPEG?

I'm currently trying to edit videos with the Python library of FFMPEG. I'm working with multiple file formats, precisely .mp4, .png and text inputs (.txt). The goal is to embed the different video files within a "layout" - for demonstration purposes I tried to design an example picture:

Example

The output is supposed to be a 1920x1080 .mp4 file with the following Elements:

  • Element 3 is the video itself (due to it being a mobile phone screen recording, it's about the size displayed there)
  • Element 1 and 2 are the "boarders", i.e. static pictures (?)
  • Element 4 represents a regularly changing text - input through the python script (probably be read from a .txt file)
  • Element 5 portrays a .png, .svg or alike; in general a "picture" in the broad sense.

What I'm trying to achieve is to create a sort of template file in which I "just" need to input the different .mp4 and .png files, as well as the text and in the end I'll receive a .mp4 file whereas my Python script functions as the navigator sending the data packages to FFMPEG to process the video itself.

I dug into the FFMPEG library as well as the python-specific repository and wasn't able to find such an option. There were lots of articles explaining the usage of "channel layouts" (though these don't seem to fit my need).

In case anyone wants to try on the same versions:

  • python --version: Python 3.7.3
  • pip show ffmpeg: Version: 1.4 (it's the most recent; on an off-topic note: It's not obligatory to use FFMPEG, I'd prefer using this library though if it doesn't offer the functionality I'm looking for, I'd highly appreciate if someone suggested something else)
like image 861
J. M. Arnold Avatar asked Jan 05 '21 14:01

J. M. Arnold


1 Answers

enter image description here

ffmpeg -i left.jpg -i video.mp4 -i right.png -i logo.png -filter_complex "[0]scale=(1920-1080*($width/$height))/2:1080:force_original_aspect_ratio=increase,crop=(1920-1080*($width/$height))/2:1080[left];[1]scale=-2:1080[main];[2]scale=(1920-1080*($width/$height))/2:1080:force_original_aspect_ratio=increase,crop=(1920-1080*($width/$height))/2:1080[right];[left][main][right]hstack=inputs=3[bg];[bg][3]overlay=5:main_h-overlay_h-5:format=auto,drawtext=textfile=text.txt:reload=1:x=w-tw-10:y=h-th-10,format=yuv420p" -movflags +faststart output.mp4

What this does is scale video.mp4 so it is 1080 pixels high and autoscale the width. left.jpg and right.png are scaled to take up the remainder so the result is 1920x1080.

This is a simple example and won't work for all inputs such as if the video.mp4 autoscaled width is bigger than 1920, but you can deal with that by using arithmetic expressions.

$width and $height refer to the size of video.mp4. See Getting video dimension / resolution / width x height from ffmpeg for a Python friendly method using JSON or XML.

See documentation for scale, crop, hstack, drawtext, overlay, and format filters.

A much simpler method is to just add colored bars instead of arbitrary images. See Resizing videos with ffmpeg to fit a specific size.

Change text on the fly by atomically updating text.txt. Or use the subtitles filter instead of drawtext if you want the text to change on certain timestamps (you did not specify what you needed).

Related answers:

  • How to position overlay/watermark/logo with ffmpeg?
  • How to position drawtext text?
  • Vertically or horizontally stack (mosaic) several videos using ffmpeg?
  • Getting video dimension / resolution / width x height from ffmpeg
like image 60
llogan Avatar answered Oct 11 '22 19:10

llogan