216

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.

Michel
  • 490
  • 4
  • 11
0-alpha
  • 3,281
  • 5
  • 20
  • 12
  • It looks like this question has run its course and remains useful, can this be moved to Super User? – John May 30 '23 at 16:14

9 Answers9

325

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.

machineghost
  • 33,529
  • 30
  • 159
  • 234
Zombo
  • 1
  • 62
  • 391
  • 407
  • 20
    This method add subtitle to file as one of stream, so need player support to show subtitle(such as VLC) – BollMose Sep 28 '15 at 07:59
  • 5
    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. – Boushley Feb 10 '16 at 17:07
  • 6
    .srt files must be imported with `-c:s copy` not with `-c:s mov_text`. – GetFree Jun 22 '19 at 18:27
  • 1
    @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. – InternetHobo Jul 12 '21 at 00:10
  • @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). – halfer May 22 '22 at 20:15
  • What's `mov_text` for? – theonlygusti Sep 12 '22 at 14:09
  • 1
    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.`. – schemacs Nov 17 '22 at 00:47
  • `Error number -40 occured` – ivan866 Jan 26 '23 at 10:19
168

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
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
HdN8
  • 2,953
  • 3
  • 24
  • 26
  • 60
    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. – stib Nov 14 '14 at 09:03
  • 4
    Thanks very much for this solution. Is there anyway to specify the size of the characters? – user1319182 Apr 12 '15 at 00:26
  • 1
    Take a look at this answer: http://stackoverflow.com/questions/21363334/how-to-add-font-size-in-subtitles-in-ffmpeg-video-filter. 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: http://ffmpeg.org/ffmpeg-filters.html#subtitles-1 – HdN8 Apr 27 '15 at 16:00
  • 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 instead – Mamrezo Jun 28 '19 at 18:59
  • 1
    Install `libass` extensions if missing on Debian systems with `apt update && apt install libass-dev". – Sopalajo de Arrierez Sep 06 '19 at 21:51
  • Keywords for this would be to "add hardsubs" or "to hardsub a video" – Fabián Jan 23 '20 at 18:11
  • 4
    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. – Migwell Apr 13 '20 at 04:59
  • I've uploaded some convenient test files for this at: https://askubuntu.com/questions/785508/how-to-merge-subtitle-to-video/1273657#1273657 – Ciro Santilli OurBigBook.com Sep 08 '20 at 22:14
  • This is fabulous! Thanks! – Oliver Zhang Jan 12 '21 at 01:33
  • Great solution! Is it possible to add other parameters to compress the video? – Emmanuel Goldstein Mar 25 '21 at 13:08
83

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
dotokija
  • 1,002
  • 7
  • 10
  • 5
    Is it possible to add more than one subtitle? Will this softsub be recognized as language unknown? – Patrick Jan 12 '16 at 05:37
  • 1
    Yes, it is. I've just tested it for MKV: – dotokija Jan 13 '16 at 16:06
  • 11
    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.mkv – dotokija Jan 13 '16 at 16:15
  • 24
    And to add language metadata (insert before output file) "-metadata:s:s:0 language=eng" – Patrick Jan 14 '16 at 13:00
  • 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? – oldboy Sep 14 '17 at 01:32
  • 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. – dotokija Sep 15 '17 at 06:50
  • 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"? – Pygmalion Oct 06 '17 at 17:55
  • @dotokija can add watermark logo with filter-complex with subtitle srt file? – Hisham Sep 08 '19 at 06:17
  • 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. – user136036 Feb 19 '21 at 12:49
  • 2
    @user136036 If you don't use mapping, then adding additional subtitles would overwrite the existing ones. – m33ts4k0z May 13 '22 at 21:34
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

khan
  • 4,479
  • 1
  • 15
  • 9
12

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

Trynkiewicz Mariusz
  • 2,722
  • 3
  • 21
  • 27
Mirko Klemm
  • 2,048
  • 1
  • 23
  • 22
  • 1
    note that this will re-encode the video and audio. Use -c:v copy -c:a copy to copy them. – stib Sep 17 '21 at 07:03
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.

Chiara Coetzee
  • 4,201
  • 1
  • 24
  • 20
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.

cdlvcdlv
  • 952
  • 1
  • 9
  • 22
  • thanks , your answer is so helpful – Amin Rezaew Apr 25 '22 at 16:25
  • 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
    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???
    – Hans Schulze Jan 16 '23 at 22:56
-2

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

-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
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38