How to change default audio track using FFmpeg?
I want to change the default audio track from Portuguese to English in the file input.mkv.
The video contains 4 Audio Tracks: Portuguese (Default), Spanish, English and Japanese. I would also like to keep the subtitles.
The information about the video is as follows:
Input #0, matroska,webm, from 'input.mkv': Metadata: encoder : libebml v1.3.10 + libmatroska v1.5.2 creation_time : 2021-01-24T22:56:10.000000Z Duration: 00:26:36.85, start: -0.007000, bitrate: 2157 kb/s Stream #0:0: Video: hevc (Main 10), yuv420p10le(tv), 1920x1080, SAR 1:1 DAR 16:9, 23.98 fps, 23.98 tbr, 1k tbn, 23.98 tbc (default) Metadata: BPS-eng : 1880412 DURATION-eng : 00:24:21.134000000 NUMBER_OF_FRAMES-eng: 35032 NUMBER_OF_BYTES-eng: 343441847 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:1(por): Audio: opus, 48000 Hz, stereo, fltp (default) Metadata: ENCODER : Lavc58.97.100 libopus BPS-eng : 116334 DURATION-eng : 00:24:21.639000000 NUMBER_OF_FRAMES-eng: 73082 NUMBER_OF_BYTES-eng: 21254949 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:2(spa): Audio: opus, 48000 Hz, stereo, fltp Metadata: ENCODER : Lavf55.33.100 BPS-eng : 121447 DURATION-eng : 00:26:36.843000000 NUMBER_OF_FRAMES-eng: 79843 NUMBER_OF_BYTES-eng: 24241492 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:3(eng): Audio: opus, 48000 Hz, stereo, fltp Metadata: BPS-eng : 103565 DURATION-eng : 00:24:21.049000000 NUMBER_OF_FRAMES-eng: 73053 NUMBER_OF_BYTES-eng: 18914357 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:4(jpn): Audio: opus, 48000 Hz, stereo, fltp Metadata: BPS-eng : 104161 DURATION-eng : 00:24:21.138000000 NUMBER_OF_FRAMES-eng: 73057 NUMBER_OF_BYTES-eng: 19024328 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:5(por): Subtitle: ass Metadata: BPS-eng : 79 DURATION-eng : 00:23:59.360000000 NUMBER_OF_FRAMES-eng: 245 NUMBER_OF_BYTES-eng: 14246 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:6(spa): Subtitle: ass Metadata: BPS-eng : 83 DURATION-eng : 00:23:59.360000000 NUMBER_OF_FRAMES-eng: 242 NUMBER_OF_BYTES-eng: 15096 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:7(eng): Subtitle: ass Metadata: title : (Forced) BPS-eng : 435 DURATION-eng : 00:23:05.930000000 NUMBER_OF_FRAMES-eng: 523 NUMBER_OF_BYTES-eng: 75467 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:8(eng): Subtitle: ass Metadata: BPS-eng : 505 DURATION-eng : 00:23:59.390000000 NUMBER_OF_FRAMES-eng: 775 NUMBER_OF_BYTES-eng: 90904 _STATISTICS_WRITING_APP-eng: mkvmerge v45.0.0 ('Heaven') 64-bit _STATISTICS_WRITING_DATE_UTC-eng: 2021-01-24 22:56:10 _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES 1 2 Answers
The ordering of the audio streams can be accomplished using FFmpeg's map and disposition options. Best syntax for this is arguably:
ffmpeg -i input.mkv -map 0:v:0 \ -map 0:a:2 -map 0:a:0 -map 0:a:1 -map 0:a:3 \ -map 0:s -c copy \ -disposition:a:0 default \ reordered.mkvTo unpack this a little:
-map 0:v:0: The first (and only) video stream is selected-map 0:a:1 -map 0:a:0 -map 0:a:2 -map 0:a:3: The audio streams are individually placed. The final digit of each 'set' selects from the 4 audio streams with '0' being the first stream and '3' being the final audio stream. English is of course specified first and is stream 2.-map 0:s: Select all of the subtitle files-c copy: Copy the video, audio and subtitle streams with no re-encoding.-disposition:a:0 default: This sets our required audio stream (English) as the default. Useful if this has been set on another, input audio stream.
This worked well on a test file produced on my system and should work well on yours as well...
Notes...
- Selecting streams with the -map option: Beautifully written FFmpeg trac guide to using FFmpeg's
mapoptions - FFmpeg's Main Options: Scroll down from this link to see the usage and options available for FFmpeg's
dispositionoptions.
I found this thread by asking Google a highly related but slightly different question - which I now have the answer to. So could be someone else with the same issue as mine will also end up here and this might help out someone else at some time.
Our 'Smart' TV has an integrated Mp4 player, and it will play MP3 or AAC sound tracks. I have a load (80 or so) of files which have an AAC soundtrack - but these play at painfully low audio volume (TV volume set at 100% is nowhere near loud enough to hear a lot of the dialog). With oldies in the house with hearing problems and no embedded subs, this makes said videos unwatchable.
So, I wanted a way to use ffmpeg to:
Preserve the original AAC but also add an MP3 sound track, derived from the AAC, but with loudness processing so that it's suitable for TV watching.
Demote the AAC sound track to be the second audio stream, while making the new MP3 audio the default. During the process of experimentation I found that this particular TV player (Panasonic) always defaults to the first audio stream - no matter which is flagged as the default.
As the icing on this cake, I wanted to give each audio stream a proper metadata title.
I could have just demuxed the existing streams and then created the new processed audio and then muxed them all up again, but I was convinced that ffmpeg could do this as one command line - which makes for far neater and faster progress when you have 80 files to do. ffmpeg didn't let me down.
With help from the answers above and other stuff I found, this is the command line I ended up with - works a treat.
ffmpeg -i intest.mp4 -map 0 -disposition:a:0 0 -c:v copy -c:a:0 libmp3lame -metadata:s:a:0 title="MP3-LoudnessProcessed" -metadata:s:a:1 title="OriginalAAC" -filter:a loudnorm -disposition:a:0 default -map 0:a:0 -disposition:a:1 0 outtest.mp4 In this command:
-map 0means select all streams-disposition:a:0 0means, forget that the 1st audio stream is the default audio stream-c:v copy– means transfer the video stream as-is-c:a:0 libmp3lame -metadata:s:a:0 title="mp3-LoudnessProcessed" -filter:a loudnorm -disposition:a:0 defaultmeans make a new MP3 audio stream as stream 0 and title it “Mp3” also do a loudness normalisation on that stream and make it the default audio-map 0:a:0means map the first existing AAC audio stream from the input file. Because this happens last of all, it ends up as the 2nd audio stream (stream 1). Some players always default to the first audio stream (stream 0) – no matter which one is flagged as the default audio, so I needed to be sure the AAC stream was last.-disposition:a:1 0- means forget that the existing audio stream (now audio stream 1) was ever the default. This is likely not actually be needed(??) but does no harm.
ffmpeg never fails to impress - always a way to do what you want. HTH someone else sometime.