Hardcoding Subs with ffmpeg?

36,539

Solution 1

In order to hardcode subtitles, your ffmpeg version needs to be compiled with libass support. Download a static build from https://ffmpeg.org/download.html, and then use:

ffmpeg -i input.wmv -vf "subtitles=sub.srt" \
  -c:v libx264 -crf 20 \
  -c:a aac -b:a 192k
  output.mp4

Here, you set the source of the subtitles filter to the file containing the subtitles. If you want to burn the subtitles of the input video file itself, replace sub.srt with the name of the input video file.

You can change the CRF value to change the video quality/size. More info on CRF here.

More info on burning subtitles can be found on the FFmpeg Wiki.

Note that I replaced the WMV/WMA output from the original question with H.264 and AAC. ffmpeg doesn't have an encoder for recent versions of WMV, so your output would have looked quite bad. And since you're hardcoding the subtitles, you have to re-encode the video anyway.

In the OP's question, there was a typo:

[AVFilterGraph @ 0000000002c5b4a0] No such filter: 'subtitle'
Error opening filters!

The filter is called subtitles with an s. Also, the ffmpeg version was not compiled with --enable-libass, so it could not be used to hardcode subs.

Solution 2

I have successfully tested this command:

ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt" output.mp4

Note: If the output says something about No usable fontconfig configuration file found, using fallback, you must create inside ffmpeg's bin folder a new folder named fonts with a file inside (fonts.conf) that specifies where ffmpeg must look for fonts.

I have used this file in order for it to work (tested on Windows):

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- /etc/fonts/fonts.conf file to configure system font access -->
<fontconfig>

<!-- Font directory list -->

   <dir>./</dir>
   <dir>../fonts</dir>
   <dir>./fonts</dir>
   <dir>~/.fonts</dir>
   <dir>WINDOWSFONTDIR</dir>

<!--
  Accept deprecated 'mono' alias, replacing it with 'monospace'
-->
   <match target="pattern">
      <test qual="any" name="family">
         <string>mono</string>
      </test>
      <edit name="family" mode="assign">
         <string>monospace</string>
      </edit>
   </match>

<!--
  Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
-->
   <match target="pattern">
      <test qual="any" name="family">
         <string>sans serif</string>
      </test>
      <edit name="family" mode="assign">
         <string>sans-serif</string>
      </edit>
   </match>

<!--
  Accept deprecated 'sans' alias, replacing it with 'sans-serif'
-->
   <match target="pattern">
      <test qual="any" name="family">
         <string>sans</string>
      </test>
      <edit name="family" mode="assign">
         <string>sans-serif</string>
      </edit>
   </match>

<!--
  Load local system customization file
-->
   <include ignore_missing="yes">conf.d</include>

<!-- Font cache directory list -->

   <cachedir>WINDOWSTEMPDIR_FONTCONFIG_CACHE</cachedir>
   <cachedir>~/.fontconfig</cachedir>

   <config>
<!--
  These are the default Unicode chars that are expected to be blank
  in fonts.  All other blank chars are assumed to be broken and
  won't appear in the resulting charsets
 -->
      <blank>
         <int>0x0020</int>   <!-- SPACE -->
         <int>0x00A0</int>   <!-- NO-BREAK SPACE -->
         <int>0x00AD</int>   <!-- SOFT HYPHEN -->
         <int>0x034F</int>   <!-- COMBINING GRAPHEME JOINER -->
         <int>0x0600</int>   <!-- ARABIC NUMBER SIGN -->
         <int>0x0601</int>   <!-- ARABIC SIGN SANAH -->
         <int>0x0602</int>   <!-- ARABIC FOOTNOTE MARKER -->
         <int>0x0603</int>   <!-- ARABIC SIGN SAFHA -->
         <int>0x06DD</int>   <!-- ARABIC END OF AYAH -->
         <int>0x070F</int>   <!-- SYRIAC ABBREVIATION MARK -->
         <int>0x115F</int>   <!-- HANGUL CHOSEONG FILLER -->
         <int>0x1160</int>   <!-- HANGUL JUNGSEONG FILLER -->
         <int>0x1680</int>   <!-- OGHAM SPACE MARK -->
         <int>0x17B4</int>   <!-- KHMER VOWEL INHERENT AQ -->
         <int>0x17B5</int>   <!-- KHMER VOWEL INHERENT AA -->
         <int>0x180E</int>   <!-- MONGOLIAN VOWEL SEPARATOR -->
         <int>0x2000</int>   <!-- EN QUAD -->
         <int>0x2001</int>   <!-- EM QUAD -->
         <int>0x2002</int>   <!-- EN SPACE -->
         <int>0x2003</int>   <!-- EM SPACE -->
         <int>0x2004</int>   <!-- THREE-PER-EM SPACE -->
         <int>0x2005</int>   <!-- FOUR-PER-EM SPACE -->
         <int>0x2006</int>   <!-- SIX-PER-EM SPACE -->
         <int>0x2007</int>   <!-- FIGURE SPACE -->
         <int>0x2008</int>   <!-- PUNCTUATION SPACE -->
         <int>0x2009</int>   <!-- THIN SPACE -->
         <int>0x200A</int>   <!-- HAIR SPACE -->
         <int>0x200B</int>   <!-- ZERO WIDTH SPACE -->
         <int>0x200C</int>   <!-- ZERO WIDTH NON-JOINER -->
         <int>0x200D</int>   <!-- ZERO WIDTH JOINER -->
         <int>0x200E</int>   <!-- LEFT-TO-RIGHT MARK -->
         <int>0x200F</int>   <!-- RIGHT-TO-LEFT MARK -->
         <int>0x2028</int>   <!-- LINE SEPARATOR -->
         <int>0x2029</int>   <!-- PARAGRAPH SEPARATOR -->
         <int>0x202A</int>   <!-- LEFT-TO-RIGHT EMBEDDING -->
         <int>0x202B</int>   <!-- RIGHT-TO-LEFT EMBEDDING -->
         <int>0x202C</int>   <!-- POP DIRECTIONAL FORMATTING -->
         <int>0x202D</int>   <!-- LEFT-TO-RIGHT OVERRIDE -->
         <int>0x202E</int>   <!-- RIGHT-TO-LEFT OVERRIDE -->
         <int>0x202F</int>   <!-- NARROW NO-BREAK SPACE -->
         <int>0x205F</int>   <!-- MEDIUM MATHEMATICAL SPACE -->
         <int>0x2060</int>   <!-- WORD JOINER -->
         <int>0x2061</int>   <!-- FUNCTION APPLICATION -->
         <int>0x2062</int>   <!-- INVISIBLE TIMES -->
         <int>0x2063</int>   <!-- INVISIBLE SEPARATOR -->
         <int>0x206A</int>   <!-- INHIBIT SYMMETRIC SWAPPING -->
         <int>0x206B</int>   <!-- ACTIVATE SYMMETRIC SWAPPING -->
         <int>0x206C</int>   <!-- INHIBIT ARABIC FORM SHAPING -->
         <int>0x206D</int>   <!-- ACTIVATE ARABIC FORM SHAPING -->
         <int>0x206E</int>   <!-- NATIONAL DIGIT SHAPES -->
         <int>0x206F</int>   <!-- NOMINAL DIGIT SHAPES -->
         <int>0x2800</int>   <!-- BRAILLE PATTERN BLANK -->
         <int>0x3000</int>   <!-- IDEOGRAPHIC SPACE -->
         <int>0x3164</int>   <!-- HANGUL FILLER -->
         <int>0xFEFF</int>   <!-- ZERO WIDTH NO-BREAK SPACE -->
         <int>0xFFA0</int>   <!-- HALFWIDTH HANGUL FILLER -->
         <int>0xFFF9</int>   <!-- INTERLINEAR ANNOTATION ANCHOR -->
         <int>0xFFFA</int>   <!-- INTERLINEAR ANNOTATION SEPARATOR -->
         <int>0xFFFB</int>   <!-- INTERLINEAR ANNOTATION TERMINATOR -->
      </blank>
<!--
  Rescan configuration every 30 seconds when FcFontSetList is called
 -->
      <rescan>
         <int>30</int>
      </rescan>
   </config>

</fontconfig>
Share:
36,539

Related videos on Youtube

1234asdf12399
Author by

1234asdf12399

Updated on September 18, 2022

Comments

  • 1234asdf12399
    1234asdf12399 almost 2 years

    Is it possible to hardcode subs with ffmpeg? By hardcode, I mean overlaying the subtitles as pictures on top of the video, and would be unremovable because they would be a part of the video. I tried to convert the subtitle to .ass and then tried to encode it, but ffmpeg does not do anything, and returns the same file. I used VLC to encode them, but it just embeds them in the video file itself and does not include them as pictured direclty overlayed on the video. My end result should be something like this:

    enter image description here

    Created fonts.conf, then retried:

    Z:\New folder>ffmpeg -i input.wmv -vf "subtitle=sub.srt" output.wmv ffmpeg version N-69247-g85d7e02 Copyright (c) 2000-2015 the FFmpeg developers built on Jan 25 2015 02:18:48 with gcc 4.9.2 (GCC) configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r libavutil 54. 17.100 / 54. 17.100 libavcodec 56. 20.100 / 56. 20.100 libavformat 56. 19.100 / 56. 19.100 libavdevice 56. 4.100 / 56. 4.100 libavfilter 5. 8.101 / 5. 8.101 libswscale 3. 1.101 / 3. 1.101 libswresample 1. 1.100 / 1. 1.100 libpostproc 53. 3.100 / 53. 3.100 Guessed Channel Layout for Input Stream #0.1 : stereo Input #0, asf, from 'input.wmv': Metadata: major_brand : isom minor_version : 1 compatible_brands: isomavc1 encoder : Lavf56.15.101 PRIVATE/TotalBitrate: 628000 WM/VideoHeight : 240 WM/VideoWidth : 320 WM/VideoFrameRate: 0 title : input Duration: 01:47:53.77, start: 0.000000, bitrate: 656 kb/s Stream #0:0: Video: wmv2 (WMV2 / 0x32564D57), yuv420p, 320x240, SAR 120:67 DAR 160:67, 25 fps, 25 tbr, 1k tbn, 1k tbc Stream #0:1: Audio: wmav2 (a[1][0][0] / 0x0161), 44100 Hz, 2 channels, fltp, 128 kb/s [AVFilterGraph @ 0000000002c5b4a0] No such filter: 'subtitle' Error opening filters!

    I replaced "subtitle=sub.srt" with subtitle="sub.srt" and subtitle=sub.srt and got the same result.

    I converted the subtitle to .ass: ffmpeg -i sub.srt sub.ass

    Then I used -vf ass=sub.ass and the video encoded, but without subtitles.

    I pasted exactly the same code given by in fonts.conf.

    Also, how can I choose fonts? Should I use drawtext?

    • slhck
      slhck over 9 years
      Please show the commands you've tried and the full command line output.
    • Rajib
      Rajib over 9 years
      "but it just embeds them in the video file itself and does not include them as pictured direclty overlayed on the video". What do you mean?
    • 1234asdf12399
      1234asdf12399 over 9 years
      @slhck the commands I used were: ffmpeg -i subtitle.srt subtitle.ass ffmpeg -i input.mp4 -vf ass=subtitle.ass output.mp4
    • 1234asdf12399
      1234asdf12399 over 9 years
      @rajib I mean that the subtitles are just embedded inside the video file, and can be turned on or off. I am looking for a way to include them in the video permanently.
    • slhck
      slhck over 9 years
      Like I said, please show the command line output of these commands as well (the second one would be more interesting). You can edit your question to add the full log (starting with "ffmpeg version…" until the last line that you get when the encode is finished).
    • 1234asdf12399
      1234asdf12399 over 9 years
      @slhck I did not include the command line output because it is nothing different. The process completes, but subtitles are not hardcoded. All I usually get is the input video as the output video.
    • slhck
      slhck over 9 years
      The process doesn't complete.. Do you see the error?
  • 1234asdf12399
    1234asdf12399 over 9 years
    How do I select a particular font? Is changing the color and size possible? Should I use this:drawtext=fontfile=arial.ttf
  • 1234asdf12399
    1234asdf12399 over 9 years
    @slhck pointed out that the command should be: ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt" output.mp4
  • 1234asdf12399
    1234asdf12399 over 9 years
    What would be the difference in the code if I used .ass subs? Is changing the font, and its size possible?
  • slhck
    slhck over 9 years
    I suppose so. Not much of a subtitle expert, but using a proper subtitle editor would probably enable you to change the ASS subtitles to your liking.
  • 1234asdf12399
    1234asdf12399 over 9 years
    YES! This worked! To change the subtitle size, color, etc just open the .ass file in a text editor and change the values manuallly. ffmpeg automatically uses the font default to the .ass file.
  • slhck
    slhck over 9 years
    Note the filter name being "subtitles", not "subtitle"
  • ranjeet
    ranjeet over 5 years
    This was very useful to me today. I needed to add some overlay message on top of a screencapture video. Using a video editor and merging two video streams seemed daunting task. Then I thought of using subtitles and you showed a simple way of doing it. I already had an .mp4 and wanted an .mp4 output so that worked out very well as well
  • Shayan
    Shayan about 5 years
    I didn't get the font error, the command worked nicely, just note that you have to be in the folder that the srt file is located in, "subtitles=C:\Users\user\Videos\sub.srt" won't work.
  • Ninh Pham
    Ninh Pham over 3 years
    For someone who uses along with -ss <time> -to <time> to extract a part of video then makes sure the subtitle time should follow the time of the output (which starts from 00:00) not the original video.
  • Grimeire
    Grimeire over 2 years
    What about if the subs are already in the video file and i want to force them to be hardcoded?
  • slhck
    slhck over 2 years
    @Grimeire In that case you have to use the video name as the source of the subtitles filter, e.g. ffmpeg -i video.mkv -vf "subtitles=video.mkv" output.mkv