Skip to content

Tips: To keep subtitle streams when converting video

suntong edited this page Dec 1, 2019 · 7 revisions

References

(NB, edited from https://askubuntu.com/a/214351/843820)

Softsubs

For all formats that support streaming text format subtitles:

Basic example using default stream selection behavior while stream copying the audio:

ffmpeg -i input.mkv -c copy -c:s copy output.mp4

Example to stream copy all of the video and audio streams, convert the all text based subtitle input streams (SRT, ASS, VTT, etc) to the streaming text format, and set the language for the first two subtitle streams.

ffmpeg -i input.mkv -map 0 -c copy -c:s copy -metadata:s:s:0 language=eng -metadata:s:s:1 language=ipk output.mp4

Same as above but re-encode the video and audio to formats compatible with the MP4 container (H.264 video:

ffmpeg -i input.mkv -map 0 -c:v libx264 -c:a aac -c:s mov_text -metadata:s:s:0 language=eng -metadata:s:s:1 language=ipk output.mp4

Same as above but use the -map option to choose the first video stream, second audio stream, and third subtitle stream:

ffmpeg -i input.mkv -map 0:v:0 -map 0:a:1 -map 0:s:2 -c:v libx264 -c:a aac -c:s mov_text -metadata:s:s:0 language=eng output.mp4

Ref:

Hardsubs

Text based subtitle format inputs

Use the subtitles filter to "burn-in" text based subtitle formats (SRT, ASS, VTT, etc). Note that this requires re-encoding, so it will by much slower than using softsubs.

See FFmpeg Wiki: Subtitles

No subs

To disable subtitle output/recording, use -sn.

Other subtitle related references

Example: subtitle streams copy when encoding with ffcvt

Starting with Version 1.3.2 (builds later than 2019-01-06), ffcvt supports subtitle streams copy by default when encoding to the default WebM(VP9) format. Here is an example:

$ ffmpeg -i Sample-with-Subtitle.mkv 
Input #0, matroska,webm, from 'Sample-with-Subtitle.mkv':
  Metadata:
    encoder         : libebml v1.3.6 + libmatroska v1.4.9
    creation_time   : 2018-07-17 15:23:05
  Duration: 00:52:55.17, start: 0.000000, bitrate: 9105 kb/s
    Stream #0:0: Video: hevc (Main), yuv420p(tv, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 23.98 tbc (default)
    Metadata:
      BPS-eng         : 8879131
      DURATION-eng    : 00:52:55.172000000
      NUMBER_OF_FRAMES-eng: 76128
      NUMBER_OF_BYTES-eng: 3524096033
      _STATISTICS_WRITING_APP-eng: mkvmerge v25.0.0 ('Prog Noir') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2018-07-17 15:23:05
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
    Stream #0:1(eng): Audio: eac3, 48000 Hz, stereo, fltp, 224 kb/s (default)
    Metadata:
      BPS-eng         : 224000
      DURATION-eng    : 00:52:55.136000000
      NUMBER_OF_FRAMES-eng: 99223
      NUMBER_OF_BYTES-eng: 88903808
      _STATISTICS_WRITING_APP-eng: mkvmerge v25.0.0 ('Prog Noir') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2018-07-17 15:23:05
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
    Stream #0:2(eng): Subtitle: subrip
    Metadata:
      BPS-eng         : 91
      DURATION-eng    : 00:52:00.418000000
      NUMBER_OF_FRAMES-eng: 966
      NUMBER_OF_BYTES-eng: 35651
      _STATISTICS_WRITING_APP-eng: mkvmerge v25.0.0 ('Prog Noir') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2018-07-17 15:23:05
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

So the Sample-with-Subtitle.mkv has a (subrip) text subtitle stream.
Now try to transcode to the default WebM(VP9) format using ffcvt:

$ ffcvt -f Sample-with-Subtitle.mkv -force -- -ss 00:02:50 -t 0:3:00
== Transcoding: Sample-with-Subtitle.mkv
] -i Sample-with-Subtitle.mkv -c:a libopus -b:a 64k -c:s copy -c:v libvpx-vp9 -b:v 0 -crf 37 -y -ss 00:02:50 -t 0:3:00 Sample-with-Subtitle_.mkv
. . . 

$ ffmpeg -i Sample-with-Subtitle_.mkv 
Input #0, matroska,webm, from 'Sample-with-Subtitle_.mkv':
  Metadata:
    ENCODER         : Lavf56.36.100
  Duration: N/A, start: 0.007000, bitrate: N/A
    Stream #0:0: Video: vp9 (Profile 0), yuv420p(tv), 1920x1080, SAR 1:1 DAR 16:9, 23.98 fps, 23.98 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      BPS-eng         : 8879131
      DURATION-eng    : 00:52:55.172000000
      NUMBER_OF_FRAMES-eng: 76128
      NUMBER_OF_BYTES-eng: 3524096033
      _STATISTICS_WRITING_APP-eng: mkvmerge v25.0.0 ('Prog Noir') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2018-07-17 15:23:05
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      ENCODER         : Lavc56.41.100 libvpx-vp9
    Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      LANGUAGE        : eng
      BPS-eng         : 224000
      DURATION-eng    : 00:52:55.136000000
      NUMBER_OF_FRAMES-eng: 99223
      NUMBER_OF_BYTES-eng: 88903808
      _STATISTICS_WRITING_APP-eng: mkvmerge v25.0.0 ('Prog Noir') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2018-07-17 15:23:05
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
      ENCODER         : Lavc56.41.100 libopus
    Stream #0:2(eng): Subtitle: subrip
    Metadata:
      LANGUAGE        : eng
      BPS-eng         : 91
      DURATION-eng    : 00:52:00.418000000
      NUMBER_OF_FRAMES-eng: 966
      NUMBER_OF_BYTES-eng: 35651
      _STATISTICS_WRITING_APP-eng: mkvmerge v25.0.0 ('Prog Noir') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2018-07-17 15:23:05
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

Note that

  • ffcvt supports subtitle streams copy by blindly inserting -c:s copy into the ffmpeg command line, to do the subtitle streams copy. It will copy the subtitle meta-data as well (see above result). If the original subtitle meta-data (e.g., language setting) was wrong somehow, you can use -metadata:s:s:0 language=eng to override it.
  • In order to support subtitle streams copy, the default format of the WebM(VP9) video extension has to be changed. If keep using the .webm extension, ffmpeg will complain about the following then abort:
$ ffmpeg -i Sample-with-Subtitle.mkv -c:a libopus -b:a 64k -c:v libvpx-vp9 -b:v 0 -crf 37 -c:s copy -ss 00:02:50 -t 0:3:00 Sample-with-Subtitle_.webm
[libvpx-vp9 @ 0x4066320] v1.4.0-823-g4110a27
[webm @ 0x40ae020] Codec for stream 2 does not use global headers but container format requires global headers
[webm @ 0x40ae020] Only VP8 or VP9 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM.
Output #0, webm, to 'Sample-with-Subtitle_.webm':
. . .
Stream mapping:
  Stream #0:0 -> #0:0 (hevc (native) -> vp9 (libvpx-vp9))
  Stream #0:1 -> #0:1 (eac3 (native) -> opus (libopus))
  Stream #0:2 -> #0:2 (copy)
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument
  • For videos that don't have subtitle streams at all, ffcvt(ffmpeg) will carry on without erroring out:
$ ffcvt -f tears_of_steel_720p.mov -force -- -t 0:0:30

== Transcoding: tears_of_steel_720p.mov
] -i tears_of_steel_720p.mov -c:a libopus -b:a 64k -c:s copy -c:v libvpx-vp9 -b:v 0 -crf 37 -y -t 0:0:30 tears_of_steel_720p_.mkv

Done.
Org Size: 363455 KB
New Size: 2564 KB
Saved:    99% with 360891 KB
Time: 2m43.937355268s at 2019-01-06 21:15:26
. . . 

$ ffmpeg -i tears_of_steel_720p_.mkv
Input #0, matroska,webm, from 'tears_of_steel_720p_.mkv':
  Metadata:
    COMPATIBLE_BRANDS: qt  
    MAJOR_BRAND     : qt  
    MINOR_VERSION   : 512
    ENCODER         : Lavf56.36.100
  Duration: 00:00:30.01, start: 0.007000, bitrate: 700 kb/s
    Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv), 1280x534, SAR 1:1 DAR 640:267, 24 fps, 24 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      LANGUAGE        : eng
      HANDLER_NAME    : DataHandler
      ENCODER         : Lavc56.41.100 libvpx-vp9
    Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default)
    Metadata:
      LANGUAGE        : eng
      HANDLER_NAME    : DataHandler
      ENCODER         : Lavc56.41.100 libopus