Skip to content

Instantly share code, notes, and snippets.

@berndverst
Last active March 29, 2024 09:27
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save berndverst/8e1b8321926426ded9555c15a2c0c837 to your computer and use it in GitHub Desktop.
Save berndverst/8e1b8321926426ded9555c15a2c0c837 to your computer and use it in GitHub Desktop.
Script to quickly merge captions into mp4 H.264 (or HEVC/H.265) video as selectable or burned in subtitles from command-line

Add captions to MP4 videos as subtitles

Requirements

FFMpeg must be installed.

Instructions:

Inputs

  • Input video: MP4 in H.264 or HEVC/H.265
  • Captions file: SRT or VTT/WebVTT

Note: If you do not have a captions file upload your MP4 video to YouTube and generate automated captions. Then download the SRT file. Alternatively, if you have a Microsoft Stream subscription upload the video and download the WebVTT captions file.

Selectable subtitles

These subtitles can be toggled on or off. You can even have multiple subtitlte tracks for different languages or commentary.

selectable

# Replace with your input video and subtitle file
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLES=~/Desktop/deployingwebapps.vtt

ffmpeg -i $INFILE -i $SUBTITLES -c copy -c:s mov_text -metadata:s:s:0 language=eng outfile_selectable.mp4

Multiple languages

selectmulti

# Replace with your input video and subtitle files
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLESENG=~/Desktop/english.vtt
SUBTITLEGER=~/Desktop/german.vtt
SUBTITLESSPA=~/Desktop/spanish.vtt

ffmpeg -i $INFILE -i $SUBTITLESENG -i $SUBTITLESGER -i $SUBTITLESSPA -map 0 -map 1:s -map 2:s -map 3:s -c copy -c:s mov_text -c:s mov_text c:s mov_text -metadata:s:s:0 language=eng -metadata:s:s:1 language=ger -metadata:s:s:2 language=spa outfile_selectable_multi.mp4

Burned in subtitles

burnedin

Since we need to rerender the video we use hardware acceleration.

For H.264 with hardware encoding on Mac

# Replace with your input video and subtitle file
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLES=~/Desktop/deployingwebapps.vtt

ffmpeg -i $SUBTITLES temp.ass && \
BITRATE=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 $INFILE) && \
ffmpeg -i $INFILE -vf ass=temp.ass -vcodec h264_videotoolbox -b:v $BITRATE -c:a copy output_burnedin.mp4

For H.264 with hardware encoding on Windows/Linux with NVIDIA GPU

# Replace with your input video and subtitle file
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLES=~/Desktop/deployingwebapps.vtt

ffmpeg -i $SUBTITLES temp.ass && \
BITRATE=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 $INFILE) && \
ffmpeg -i $INFILE -vf ass=temp.ass -vcodec h264_nvenc -b:v $BITRATE -c:a copy output_burnedin.mp4

For H.265/HEVC with hardware encoding on Mac

# Replace with your input video and subtitle file
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLES=~/Desktop/deployingwebapps.vtt

ffmpeg -i $SUBTITLES temp.ass && \
BITRATE=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 $INFILE) && \
ffmpeg -i $INFILE -vcodec hevc_videotoolbox -tag:v hvc1 -b:v $BITRATE -c:a copy -vf ass=temp.ass output_burnedin.mp4

For H.265/HEVC with hardware encoding on Windows/Linux with NVIDIA GPU

# Replace with your input video and subtitle file
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLES=~/Desktop/deployingwebapps.vtt

ffmpeg -i $SUBTITLES temp.ass && \
BITRATE=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 $INFILE) && \
ffmpeg -i $INFILE -vcodec hevc_nvenc -tag:v hvc1 -b:v $BITRATE -c:a copy -vf ass=temp.ass output_burnedin.mp4

NOTE: HEVC / H.265 hardware encoding can be slow and produce much larger file. For this reason consider using software encoding.

# Replace with your input video and subtitle file
INFILE=~/Desktop/deployingwebapps.mp4
SUBTITLES=~/Desktop/deployingwebapps.vtt

ffmpeg -i $SUBTITLES temp.ass && \
BITRATE=$(ffprobe -v error -select_streams v:0 -show_entries stream=bit_rate -of default=noprint_wrappers=1:nokey=1 $INFILE) && \
ffmpeg -i $INFILE -vcodec libx265 -tag:v hvc1 -b:v $BITRATE -c:a copy -vf ass=temp.ass output_burnedin.mp4

If the source video was in H.264 format you can also use the H.265 command to produce a final video in H.265/HEVC format. Note that since H.265 is 25-50% more efficient you should be able to reduce the Bitrate for the same quality video.

@TheOnlyWayUp
Copy link

Thanks a ton!

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