Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
ffmpeg command to add .srt based subtitles to an .mkv file
ffmpeg -i in.mkv -f srt -i in.srt -map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy -c:s srt out.mkv
@aaaamirabbas
Copy link

aaaamirabbas commented Feb 26, 2019

Compatible with utf8 :
ffmpeg -i input.mkv -sub_charenc 'UTF-8' -f srt -i input.srt -map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy -c:s srt out.mkv

@RobertoMaurizzi
Copy link

RobertoMaurizzi commented Sep 19, 2019

With the original options for map, I got subs out of sync by around 4 secs. Removing -map completely copies over all the streams and works for most files

ffmpeg -i input.mkv -sub_charenc 'UTF-8' -f srt -i subs.en.srt -map 0 -c:v copy -c:a copy -c:s srt output.mkv

@ttyusupov
Copy link

ttyusupov commented Feb 26, 2020

-map 1:0 is still needed for copying subtitles into output file:

ffmpeg -i input.mkv -sub_charenc 'UTF-8' -f srt -i subs.en.srt -map 0 -map 1:0 -c:v copy -c:a copy -c:s srt output.mkv

@pscopic
Copy link

pscopic commented Mar 18, 2020

-map 1:0 is still needed for copying subtitles into output file:

ffmpeg -i input.mkv -sub_charenc 'UTF-8' -f srt -i subs.en.srt -map 0 -map 1:0 -c:v copy -c:a copy -c:s srt output.mkv

Worked for me without the -map 1:0 so long as I omit the -map 0 too.

@nimahkh
Copy link

nimahkh commented Mar 21, 2020

i made this bash script with your code :
https://gist.github.com/nimahkh/36c0dac31d9cb5363cf356095014524f

@Alex24242424
Copy link

Alex24242424 commented Apr 27, 2020

I used this script I made. I find it more simple and it can simply be changed for other formats:
ffmpeg -i input.mkv -c copy -c:s srt out.mkv

Works very well, and the srt subtitle codec can be changed with other codecs like mov_text for mp4 videos

@SalimF
Copy link

SalimF commented Dec 22, 2020

The first code works well for me from first try, no need to fancy works, this is shell script version

ffmpeg -i $1 -f ass -i $2 -map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy -c:s ass $RANDOM.mkv

e.g name your script Sub and excute it like this

Sub 'movie.mp4' 'sub.ass'
and you're done, you can change ass with srt since I use ass most of time, + I didn;t even need to add UTF8 parameter the sub were embedded perfectly

@godric-cz
Copy link

godric-cz commented Nov 6, 2021

FFmpeg can figure out subtitle type and mapping on it's own, nothing fancy needed (assuming your input does not have subtitles in it already):

ffmpeg -i input.mkv -i subtitles.srt -c copy output.mkv

@eladkarako
Copy link

eladkarako commented Jan 8, 2022

tl;dr

ffmpeg -y -loglevel "repeat+info" 
-i "file:input.mp4" 
-i "file:subtitle.iw.vtt" 
-i "file:subtitle.en.vtt" 
-c copy 
-map 0 -dn -map "-0:s" -map "-0:d"  
-map "1:0" "-metadata:s:s:0" "language=heb" "-metadata:s:s:0" "handler_name=Hebrew"  "-metadata:s:s:0" "title=Hebrew" 
-map "2:0" "-metadata:s:s:1" "language=eng" "-metadata:s:s:1" "handler_name=English" "-metadata:s:s:1" "title=English" 
"file:output.mkv"
why?. the following example embed two subtitles without encoding, Hebrew and English (in a "one go", and in that order).

if you want to embed more than one subtitle stream you must use map,
otherwise ffmpeg's automatic stream selection only takes the first one, of its kind (it does the same for audio/video streams as well).

note: the command is broken over several lines for better readability. linux users add \ at line's end, windows users add ^ at line's end, or just remove all line breaks to make it functional.

note: vtt is like srt, commonly used by youtube. you can use any of your existing subtitles 'as is' though.

  • input 1: input.mp4 (the map command maps 0 which means this file and whatever streams it contains first, using automatic assignment, it then runs a little cleanup to make sure no existing subtitles were left in it, so the next indexing addressing to the external subtitles is correct .
  • input 2: subtitle.iw.vtt this is the first of the subtitle streams, its index is zero based so .....s:0, it is getting a proper 3 letter language code from ISO-639-1, and a label (you can write anything you like in it, even name it locally, I could have used title=עברית as well. but for compatibility with some old players I've chosen title=Hebrew.
  • input 3: subtitle.en.vtt second in the subtitle-list of streams, so index is 1 - .....s:1.
  • output: output.mkv.
note about indexing: I know the indexing might seem a bit confusing, first, remember it is zero based, so 0 is first, 1 is second, 2 is third, ...

next:

-map 0, -map "1:0", -map "2:0" are the original input (-i ...) files 'as whole', with whatever streams they have in them,

the indexes in "-metadata:s:s:0", "-metadata:s:s:1" are limited with :s so that means they are used in the list of subtitles "collected" from all the inputs together, potentially including all the subtitles already embedded in the video file.

to avoid collecting any unknown amount of subtitles from the first input, -map "-0:s" is used, ignoring all subtitle-streams from the first input.

b.t.w. this how YT-DLP (youtube-dl fork) is embedding subtitles, it fixes a lot of quirks.

yt-dlp's subtitle embedding related, python code, for ffmpeg

https://github.com/yt-dlp/yt-dlp/blob/1209b6ca5b720a2cd035ff86040bfb1fea7ac6c9/yt_dlp/postprocessor/ffmpeg.py#L591-L667

https://github.com/yt-dlp/yt-dlp/blob/1209b6ca5b720a2cd035ff86040bfb1fea7ac6c9/yt_dlp/postprocessor/ffmpeg.py#L648-L659

if you already have subtitles you want to keep you can extract them with -na -nv mysubtitle.srt (you can choose your extension) and embed them properly again (with language code and such) along with the new ones. you can also avoid the deletion of data and existing subtitles, but then you need to remember to shift the index of the added subtitles acording to how many subtitles are already embedded, and it is bad scripting. it is better to extract them in what ever format you want. if you are working on some subtitles with more data, such as colors, or placements over video (.ASS) which are commonly used in translated anime, to translate letters street signs etc.. make sure to keep the same format otherwise you'll loose that data and only keep the text of the translation. you can often check what subtitle type is being used with ffmpeg or vlc or media player classic.

ffmpeg_embed_vtt_subtitles_by_muxing_without_encoding

and you can always use -c:s copy subtitle_of_unknown_format.txt instead and figure it out later using a text editor or the great subtitle workshop program.

source


another example with more languages:

ffmpeg -y -loglevel "repeat+info" 
-i "file:my_input_video.mkv" 
-i "file:subtitle.en.vtt" 
-i "file:subtitle.iw.vtt" 
-i "file:subtitle.ja.vtt" 
-i "file:subtitle.ko.vtt" 
-map 0 
-c copy 
-dn -ignore_unknown -map "-0:s" 
-map "1:0" "-metadata:s:s:0" "language=eng" "-metadata:s:s:0" "handler_name=English"  "-metadata:s:s:0" "title=English" 
-map "2:0" "-metadata:s:s:1" "language=heb" "-metadata:s:s:1" "handler_name=Hebrew"   "-metadata:s:s:1" "title=Hebrew" 
-map "3:0" "-metadata:s:s:2" "language=jpn" "-metadata:s:s:2" "handler_name=Japanese" "-metadata:s:s:2" "title=Japanese" 
-map "4:0" "-metadata:s:s:3" "language=kor" "-metadata:s:s:3" "handler_name=Korean"   "-metadata:s:s:3" "title=Korean" 
-movflags "+faststart" 
"file:my_output_video.mkv"

edit:

default subtitle to play

(optional) use -disposition to set a default subtitle,
and it does not even have to be the first one,
for example: -disposition:s:s:5 forced will make your sixth subtitle stream the default one to play.

note: you can use this to make other streams the default ones to open as well...

-disposition:s:a:3 forced for the fourth audio stream,

-disposition:s:v:0 forced for the first video stream..

@akostadinov
Copy link

akostadinov commented Feb 17, 2022

To just add subtitles to file without removing any subtitles it is very easy:

ffmpeg -i input.mkv -i input.srt -map 0 -map 1 -c copy output.mkv

-map x selects all streams from a file so all streams from both files get into the output file.

See the very conscious and simple documentation https://trac.ffmpeg.org/wiki/Map

P.S. Thanks @eladkarako for the metadata usage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment