Use ffmpeg to add text subtitles [closed]
Asked Answered
D

9

227

I am trying to add text subtitles to an .mp4 container using ffmpeg:

ffmpeg -i input.mp4 -i input.srt -map 0.0 -map 0.1 -map 1.0 output.mp4

When I am trying to run this line, it gives me an error :

Nmber of stream maps must match number of output streams.

If I try to change the mp4 to mkv (although mp4 supports text subtitles), like this:

ffmpeg -i input.mp4 -i input.srt -map 0.0 -map 0.1 -map 1.0 output.mkv

It correctly maps the streams, but gives an error :

Encoder (codec id 94210) not found for output stream #0.2

When I launch

ffmpeg -codecs

I can see that srt codec is supported as decoder and encoder, however I am not sure what is used for mp4 and mkv subs encoding, and whether I need to switch it on or compile separately.

Dorothadorothea answered 29/12, 2011 at 20:4 Comment(1)
It looks like this question has run its course and remains useful, can this be moved to Super User?Churlish
F
342

NOTE: This solution adds the subtitles to the video as a separate optional (and user-controlled) subtitle track.

ffmpeg -i infile.mp4 -i infile.srt -c copy -c:s mov_text outfile.mp4

-vf subtitles=infile.srt will not work with -c copy


The order of -c copy -c:s mov_text is important. You are telling FFmpeg:

  1. Video: copy, Audio: copy, Subtitle: copy
  2. Subtitle: mov_text

If you reverse them, you are telling FFmpeg:

  1. Subtitle: mov_text
  2. Video: copy, Audio: copy, Subtitle: copy

Alternatively you could just use -c:v copy -c:a copy -c:s mov_text in any order.

Featherweight answered 11/7, 2013 at 2:53 Comment(9)
This method add subtitle to file as one of stream, so need player support to show subtitle(such as VLC)Obtect
Yes @sunk818 that's what this means. This adds the subtitle as a track that can be enabled or disabled as long as the player supports it. Mr. Hyde and Paul ffmpeg can also add the subtitles ontop of the video itself, and in those cases you would control things like font and positioning.Excide
.srt files must be imported with -c:s copy not with -c:s mov_text.Absentee
@TomRussell -c copy does video, audio and subtitles from the original, -c:v copy -c:a copy just does video and audio so then it doesn't matter the order you add the subtitles.Cabalistic
@machineghost: you made an edit to this post, which was rolled back. Since the post author has gotten themselves suspended permanently, you may restore your version if you wish (it's not my area, so I will leave it for you/others).Dahabeah
What's mov_text for?Joellejoellen
use -c:v copy -c:a copy -c:s mov_text, or ffmpeg will warn you Multiple -c, -codec, -acodec, -vcodec, -scodec or -dcodec options specified for stream 2, only the last option '-c:s mov_text' will be used..Fleabitten
Error number -40 occuredCarrot
ffmpeg -i infile.mp4 -i infile.srt -c copy -c:s mov_text metadata:s:s:0 language=eng outfile.mp4 to set the metadata for the first subtitle stream, and language=eng specifies that the language of the subtitle track is EnglishRunthrough
S
175

NOTE: This solution "burns the subtitles" into the video, so that every viewer of the video will be forced to see them.

If your ffmpeg has libass enabled at compile time, you can directly do:

ffmpeg -i mymovie.mp4 -vf subtitles=subtitles.srt mysubtitledmovie.mp4

This is the case e.g. for Ubuntu 20.10, you can check if ffmpeg --version has --enable-libass.

Otherwise, you can the libass library (make sure your ffmpeg install has the library in the configuration --enable-libass).

First convert the subtitles to .ass format:

ffmpeg -i subtitles.srt subtitles.ass

Then add them using a video filter:

ffmpeg -i mymovie.mp4 -vf ass=subtitles.ass mysubtitledmovie.mp4
Straticulate answered 29/10, 2012 at 15:55 Comment(10)
This will "burn them into" the video, meaning you can't turn them off in the player. This is different to adding them as a subtitle stream which can be read by the player and displayed if the viewer wants them.Somnifacient
Thanks very much for this solution. Is there anyway to specify the size of the characters?Ecg
Take a look at this answer: #21363834. You will probably want to set the font in the subtitle file itself, otherwise using the subtitle filter, you could force_style to set the Font: ffmpeg.org/ffmpeg-filters.html#subtitles-1Straticulate
This will be useful when adding subtitle for videos somewhere like Instagram. Somewhere like Instagram viewer that user has no ability to listen to sound or video is in another language, then user can read the subtitle insteadAlveolus
Install libass extensions if missing on Debian systems with `apt update && apt install libass-dev".Lenrow
Keywords for this would be to "add hardsubs" or "to hardsub a video"Nullification
Notably you can do this in one step: ffmpeg -i mymovie.mp4 -vf subtitles=subtitles.srt mysubtitledmovie.mp4. You still need ffmpeg compiled with libass though.Sohn
I've uploaded some convenient test files for this at: askubuntu.com/questions/785508/how-to-merge-subtitle-to-video/…Gaylor
Great solution! Is it possible to add other parameters to compress the video?Pascual
Interesting subtitles={...} does not accept any directory entry. I learned that the hard way here. I kept getting "could not parse" strange errors. I had to make sure that my subtitles file was in the same directory that I was running the 'command'.Brister
M
88

You are trying to mux subtitles as a subtitle stream. It is easy but different syntax is used for MP4 (or M4V) and MKV. In both cases you must specify video and audio codec, or just copy stream if you just want to add subtitle.

MP4:

ffmpeg -i input.mp4 -f srt -i input.srt \
-map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy \
-c:s mov_text output.mp4

MKV:

ffmpeg -i input.mp4 -f srt -i input.srt \
-map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy \
-c:s srt  output.mkv
Milanmilanese answered 22/10, 2015 at 20:13 Comment(10)
Is it possible to add more than one subtitle? Will this softsub be recognized as language unknown?Scurlock
Yes, it is. I've just tested it for MKV:Milanmilanese
First add another input: -i input2.srt. Second, map that as 2nd stream: -map 2:0. Finally, select encoder for 2nd subtitle stream (the same as the first one): -c:s srt. The complete example\ ffmpeg -i input.mp4 -f srt -i input.srt -i input2.srt\ -map 0:0 -map 0:1 -map 1:0 -map 2:0 -c:v copy -c:a copy \ -c:s srt -c:s srt output.mkvMilanmilanese
And to add language metadata (insert before output file) "-metadata:s:s:0 language=eng"Scurlock
how come the subtitles in the original file are excluded when i "rewrap" mkv files as mp4 files (ffmpeg -i film.mkv -vcodec copy -acodec copy film.mp4)?? the original mkv has subtitles but the output in mp4 format doesn't. what's going on? what am i not doing correctly?Recuperate
see above, when muxing mp4, filter mov_text is used (subtitle streams are incompatible in mp4 and mkv), so the original subtitle stream from mkv is not recognized.Milanmilanese
My problem is that I get error "Packet with invalid duration -5323 in stream 1". Is there a workaround? Maybe it is related to two previous errors "Codec for stream 0 does not use global headers but container fo rmat requires global headers" and "Codec for stream 1 does not use global headers but container format requires global headers"?Alphabetical
@Milanmilanese can add watermark logo with filter-complex with subtitle srt file?Schoenberg
Why all those map and the -f? Just ffmpeg -i input.mkv -i input.srt -c:v copy -c:a copy -c:s srt output.mkv works fine.Electromagnetic
@Electromagnetic If you don't use mapping, then adding additional subtitles would overwrite the existing ones.Barbary
A
14

MKV container supports video and audio codecs Virtually anything and also supports subtitles and DVD menus. So you can just copy codecs from input video to output video with MKV container with subtitles. First you should convert SRT to ASS subtitle format

ffmpeg -i input.srt input.ass

and embed ASS subtitles to video

ffmpeg -i input.mp4 -i input.ass -c:v copy -c:a copy -c:s copy -map 0:0 -map 0:1 -map 1:0 -y out.mkv

Also worked with VMW file.

ffmpeg -i input.wmv -i input.ass -c:v copy -c:a copy -c:s copy -map 0:0 -map 0:1 -map 1:0 -y out.mkv

see the wiki page Comparison of container formats

Anabel answered 18/6, 2014 at 20:8 Comment(1)
H.V. not really relevant, it's always welcome to see more solutions than one.Carol
H
13

ffmpeg supports the mov_text subtitle encoder which is about the only one supported in an MP4 container and playable by iTunes, Quicktime, iOS etc.

Your line would read:

ffmpeg -i input.mp4 -i input.srt -map 0:0 -map 0:1 -map 1:0 -c:s mov_text output.mp4

Henrie answered 26/11, 2013 at 19:37 Comment(1)
note that this will re-encode the video and audio. Use -c:v copy -c:a copy to copy them.Somnifacient
A
7

I tried using MP4Box for this task, but it couldn't handle the M4V I was dealing with. I had success embedding the SRT as soft subtitles with ffmpeg with the following command line:

ffmpeg -i input.m4v -i input.srt -vcodec copy -acodec copy -scodec copy -map 0:0 -map 0:1 -map 1:0 -y output.mkv

Like you I had to use an MKV output file - I wasn't able to create an M4V file.

Agneta answered 4/12, 2012 at 11:42 Comment(0)
S
6

I will provide a simple and general answer that works with any number of audios and srt subtitles and respects the metadata that may include the mkv container. So it will even add the images the matroska may include as attachments (though not another types AFAIK) and convert them to tracks; you will not be able to watch but they will be there (you can demux them). Ah, and if the mkv has chapters the mp4 too.

ffmpeg -i <mkv-input> -c copy -map 0 -c:s mov_text <mp4-output>

As you can see, it's all about the -map 0, that tells FFmpeg to add all the tracks, which includes metadata, chapters, attachments, etc. If there is an unrecognized "track" (mkv allows to attach any type of file), it will end with an error.

You can create a simple batch mkv2mp4.bat, if you usually do this, to create an mp4 with the same name as the mkv. It would be better with error control, a different output name, etc., but you get the point.

@ffmpeg -i %1 -c copy -map 0 -c:s mov_text "%~n1.mp4"

Now you can simply run

mkv2mp4 "Video with subtitles etc.mkv"

And it will create "Video with subtitles etc.mp4" with the maximum of information included.

Spatula answered 4/5, 2018 at 11:16 Comment(2)
thanks , your answer is so helpfulZombie
Yes, exactly what ffmpeg settings I would expect. Except, the input TS file has Stream #0:3[0x1200](eng): Subtitle: hdmv_pgs_subtitle ([144][0][0][0] / 0x0090) Stream #0:4[0x1201](eng): Subtitle: hdmv_pgs_subtitle ([144][0][0][0] / 0x0090), 1920x1080 and then complains about<br/> Subtitle encoding currently only possible from text to text or bitmap to bitmap Your process above would make more sense to me if you went TS->MKV->MP4???Carroll
L
-1

Simple Example:

videoSource=test.mp4
videoEncoded=test2.mp4
videoSubtitle=test.srt
videoFontSize=24
ffmpeg -i "$videoSource" -vf subtitles="$videoSubtitle":force_style='Fontsize="$videoFontSize"' "$videoEncoded"

Only replace the linux variables

Laomedon answered 18/11, 2016 at 16:32 Comment(1)
Care to elaborate?Mourn
I
-6

This is the reason why mkv is such a good container, especially now that it's mature:

mkvmerge -o output.mkv video.mp4 subtitle.srt
Izaak answered 20/4, 2015 at 0:12 Comment(1)
Care to comment on why your approach would fix the OP's problem?Albertoalberts

© 2022 - 2024 — McMap. All rights reserved.