Search code examples
videoffmpeghttp-live-streaminghls.js

How to convert video to hls with selected audio streams?


I'm trying to convert some videos (in the different formats, e.g., mp4, mkv, avi) with multiple audio streams to HLS with only one audio. I've tried different solutions with ffmpeg but non of them seem to be ideal.

For example ffmpeg -i in.mkv -codec: copy -f hls out.m3u8 from this gist works only if in.mkv has one audio stream (at least this is my understanding).

I've then tried:

ffmpeg -i in.mkv -map 0:v:0 -map -0:a:0 -c copy -f hls out.m3u8

I'm not sure why this solution doesn't work but depending on players and input files the video is not playing correctly (for example with hls.js the absence of the image is surrounded by only occasional sounds).

My next idea was to first convert in.mkv to in_tmp.mkv with only one audio stream and then use the gist above:

ffmpeg -i in.mkv -map 0:v:0 -map -0:a:0 -c copy in_tmp.mkv
ffmpeg -i in_tmp.mkv -c copy -f hls out.m3u8

But the result was identical to my previous attempt. My guess is that there is something wrong with -c copy (but frankly I don't quite understand what I'm doing).

So I end up by using filter_complex with concat:

  ffmpeg -i in.mkv -filter_complex '[0:v:0][0:a:0] concat=n=1:v=1:a=1 [v] [a]' -map '[v]' -map '[a]' -f hls out.m3u8

It looks like it works and the different players I've tried play the output video correctly, but of course it feels suboptimal: it takes a lot of time and the use of concat seem to be very artificial.

So the question is how to convert a video to HLS with only one selected audio stream with or without ffmpeg?


Solution

  • How to convert a video to HLS with only one selected audio stream?

    Most basic command:

    ffmpeg -i input.mkv -c copy -f hls output.m3u8
    

    This will use the default stream selection behavior which will choose one stream per stream type.

    Or manually select the desired streams with -map. This example will select all video streams and optionally select audio stream #3 (note the index start counting from 0) if audio exists:

    ffmpeg -i input.mkv -c copy -map 0:v -map 0:a:3? -f hls output.m3u8
    

    Your command with -map -0:a:0 is a negative mapping which would exclude stream 0:a:0.

    See FFmpeg Wiki: Map for many examples and more info.