[FFmpeg-user] How to embed subtitles into video using Python

Jim DeLaHunt list+ffmpeg-user at jdlh.com
Wed Jul 6 23:36:30 EEST 2022

On 2022-07-06 02:46, Pavel Yermolenko via ffmpeg-user wrote:

> Hello,
> I'm looking for a command format to embed subtitles into video (not to 
> burn them).
> This command, that I found somewhere on the web works fine - the 
> subtitles are just embedded into video, quite rapid process.
> ffmpeg -i video.mp4 -i video.srt -map 0:v -map 0:a -c copy -map 1 
> -c:s:0 mov_text -metadata:s:s:0 language=fra output.mp4
> I need to process many files in batch mode, so I decided to use Python.
Hello, Pavel. I am Jim. I have done quite a bit of work recently with 
Python programs which call FFmpeg. Let me see if I can help.

> In Python there is ffmeg support package: *ffmpeg-python*. 
> ffmpeg-python 0.2.0 <https://pypi.org/project/ffmpeg-python/>
> Unfortunately in the documentation [there] is no examples on how to 
> process subtitles.
For what it is worth, I looked at using the ffmpeg-python package for my 
work, and decided it did not do what I wanted. I construct my FFmpeg 
invocation as a Python list of strings, and invoke it using 
`subprocess.run()`. This is also what Carl Zwanzig suggests.

> What option in the command I wrote at the beginning causes the 
> subtitles to be embedded as metadata, and not rendered with particular 
> frames?

I believe that in your example ffmpeg command above, it is `-c:s:0 
mov_text` which embeds the subtitles in the output, using the mov_text 
codec, with supporting roles by `-metadata:s:s:0 language=fra` and `-map 
1`. In the bad example you posted, the command uses the subtitles filter 
instead, and it burns subtitles into video frame instead of embedding 
subtitle text in metadata.

See <http://ffmpeg.org/ffmpeg-all.html#Main-options> for a description 
of the `-c` and `-metadata` options. See 
<http://ffmpeg.org/ffmpeg-all.html#Advanced-options> for a description 
of the `-map` option.

But perhaps you are asking, how to specify those options via the 
*ffmpeg-python* package?  You are right, the documentation does not 
describe this well. The clue seems to be in the .run() and .run_async() 
function documentation: "**kwargs – keyword-arguments passed to 
get_args()". (See: <https://kkroening.github.io/ffmpeg-python/#ffmpeg.run>).

So I guess that this asks you to do either (and stand by for a 
discussion of the really big problem with this):

     .get_args(map='0:v', map='0:a', c='copy', map='1', 
'c:s:0'='mov_text', 'metadata:s:s:0'='language=fra') ***Big problem!

Or, because .run() and .run_async() take keyword args,

     .run(map='0:v', map='0:a', c='copy', map='1', 'c:s:0'='mov_text', 
'metadata:s:s:0'='language=fra') ***Big problem!

There is, of course, a big problem with this list of keyword args. That 
is that the syntax of Python keyword args is more limited than the 
syntax of ffmpeg command-line options. It is not valid to have the same 
key used multiple times in a kwargs group, but this FFmpeg command line 
uses `-map` three times.  It is not valid to have colons in keyword 
names, but this FFmpeg command line uses options like `-c:s:0`.

It might be that the author of `ffmpeg-python` thought about this 
problem, and has a solution. Finding it will probably require reading 
the source code. I have not taken the time to do this.  So I don't know 
how to solve the problem. My answer to these limitations, for my 
program, was to invoke FFmpeg directly using Python's `subprocess.run()`.

If you find out how `ffmpeg-python` deals with this limitation, I 
encourage you to post the answer here. It would be good for the archives 
of this list to have the answer. Also, consider making a pull request at 
the GitHub repo for `ffmpeg-python` which improves the documentation to 
answer this question. That will help future people in your situation, 
and in mine.

I hope this is helpful for you.

     --Jim DeLaHunt, Vancouver, Canada

More information about the ffmpeg-user mailing list