Replacing video audio using ffmpeg

Up until recently I used Quicktime to switch audio tracks for the odd music and showreel video, but since it will no longer be updated for Windows, and can possibly lead to your PC getting the clap, I figured I'd better find an alternative option. Enter ffmpeg. It's a very powerful, free command line tool that I'd previously only worked with in tandem with some sort of GUI or partner app, and had never really tried to work with it on its own due to its bewildering plethora of options. But after a little trial and error I've settled on the following commands to replace audio streams in video files, (re)encoding where necessary, and avoiding video transcoding if possible in order to retain video image quality.

I installed ffmpeg using Chocolatey, a very useful package manager for Windows, similar in operation to those you'd find on Linux (well, it's not quite as good as APT or DNF/YUM, say, but it's the best we've got at the moment).

In Windows 10, you can shift-right click in the Explorer directory that houses your video file to open a command window (just select the very handy 'Open command window here' option).

Firstly, if you'd like to strip the audio from a video file, you can use this command:

ffmpeg -i INPUT.mp4 -codec copy -an OUTPUT.mp4

Specifying the INPUT and OUTPUT files accordingly, with file extension (needless to say, it doesn't have to be .mp4).

  • -i precedes the file you wish to strip the audio from.
  • -codec copy is to send the video stream to the output file without transcoding, which will maintain video quality, as well as save you loads of time not having to crunch video.
  • -an will remove the audio file. Similarly, you could use -vn to remove a video stream instead.

Then you can add your audio track by typing:

ffmpeg -i INPUT.mp4 -i AUDIO.wav -shortest -c:v copy -c:a aac -b:a 256k OUTPUT.mp4

As you can see, I have two input streams to be muxed together, the silent video file and the audio wav, to the output file at the end of the command. But there are a couple of other handy commands involved this time.

-c is a shorthand of the -codec command we used in the first example, and is used here to specify the audio and video codecs individually. As before, the video is passed through, but I've chosen to encode the audio as an aac file instead of simply adding the wav audio to the video, and have specified the audio bitrate using -b:a.

The -shortest option will truncate whichever stream between the audio and video is longest down to the length of the shortest. This is handy for crudely chopping audio down to the video length, say.

So far so good, but you might be wondering if you can just combine those two commands into a single command for even quicker results. Absolutely:

ffmpeg -i INPUT.mp4 -i AUDIO.wav -map 0:0 -map 1:0 -c:v copy -c:a aac -b:a 256k -shortest OUTPUT.mp4

This time we use the -map commands to specify which streams from the input files respectively should be included the output file. Any stream not explicitly specified will be ignored. I think the left side of the map option denotes the input file index (according to the order in which they were typed in the command), and the right side is the stream ID within the file. You can always check the stream IDs by running ffmpeg specifying only an input file and no output, which will just list all the streams in the media file. Similarly, you could also check the streams in something like VideoLAN, too.

Anyway, I hope this post is useful. If nothing else, it's a good way for me to consolidate tips for myself (isn't that termed 'Ako', or something?) and help me remember for future use.

© 2002–2023 Christopher Leary
Header image: Understory cover art, by Guy Warley.