Search code examples
ffmpeghttp-live-streamingm3u8

Converting MP4 into m3u8 with multiple subtitle tracks using ffmpeg


I'm currently working on a video pipeline that will take in an mp4 file and n number of webvtt files and outputting an m3u8 file with selectable subtitle tracks, and I'm having some difficulty figuring out the correct incantations with ffmpeg.

The following is the command I'm using right now to test everything out before integrating it into my project:

ffmpeg -i sample.mp4 -i sample-vtt-en.vtt -i sample-vtt-es.vtt \
  -map 0:v -map 0:a -map 1 -map 2 \
  -c:v copy -c:a copy -c:s webvtt \
  -metadata:s:s:0 language=en \
  -metadata:s:s:1 language=es \
  -start_number 0 -hls_time 10 -hls_list_size 0 -f hls \
  -master_pl_name master.m3u8 \
  out/sample.m3u8

When running the above, I get the following error

[webvtt @ 0x7fb6c6075a00] Exactly one WebVTT stream is needed.
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument
Error initializing output stream 0:3 --
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
  Stream #1:0 -> #0:2 (webvtt (native) -> webvtt (native))
  Stream #2:0 -> #0:3 (webvtt (native) -> webvtt (native))
    Last message repeated 1 times

Additionally, when I process this with a single webvtt file, it doesn't error out, but the output isn't quite right. The biggest issue is the master playlist does not contain any subtitle information and doesn't recognize any of the tracks. The sample.m3u8 playlist does seem to understand about the subtitle tracks, but they are split in all kinds of odd ways.

Can someone help me out with what I'm trying to accomplish?


Solution

  • It appears that the HLS muxer currently does not allow variant streams that only contain subtitles. I don't use HLS, so you'll want to investigate further in case I'm wrong, or if you're a reader in the future the situation may have changed.

    Sub-optimal workaround is to add audio to the variant stream with the -var_stream_map HLS muxer option. Something like:

    ffmpeg -i sample.mp4 -i sample-vtt-en.vtt -i sample-vtt-es.vtt \
      -map 0:v -map 0:a -map 0:a -map 1 -map 2 \
      -c:v copy -c:a copy -c:s webvtt \
      -metadata:s:s:0 language=en \
      -metadata:s:s:1 language=es \
      -start_number 0 -hls_time 10 -hls_list_size 0 -f hls \
      -var_stream_map "v:0,name:video a:0,s:0,language:eng,name:english a:1,s:1,language:spa,name:espanol"
      -master_pl_name master.m3u8 \
      out/sample.m3u8