-
-
Save kurlov/32cbe841ea9d2b299e15297e54ae8971 to your computer and use it in GitHub Desktop.
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 |
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
-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
-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.
i made this bash script with your code :
https://gist.github.com/nimahkh/36c0dac31d9cb5363cf356095014524f
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
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
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
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 maps0
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 usedtitle=עברית
as well. but for compatibility with some old players I've chosentitle=Hebrew
. - input 3:
subtitle.en.vtt
second in the subtitle-list of streams, so index is1
-.....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
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.
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.
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..
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
I've tried all the above options without success... the only thing that happens is that there is a closed caption option listed yet no text is displayed and the file size of the video file was increased.
I'm using both mediainfo and vlc to look at the file info.
I'm running this thru a ubuntu server 22.04.1 LTS
is this supposed to add the CEA-708 metadata for Closed Captioning or is this a different type of embedded text?
I've tried all the above options without success..
This code I use both on my PC and my server, works perfectly, the sub file should be .ass format (use aegisub or even ffmpeg to convert your sub to it)
ffmpeg -loglevel 16 -i input.mp4 -f ass -i sub.ass -brand isom -tag:v avc1 -map 0:0 -map 0:1 -map 1:0 -c:v copy -c:a copy -c:s ass -disposition:s:0 default Fname.mkv
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
I confirm this code is fine.
Thanks.
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