Extract audio using FFmpeg

Using FFmpeg, we can easily extract audio from a video file. But, there is a small inconvenience caused by the unusual way FFmpeg handles output file names. It is compulsory to specify an output file name and this file name must have the correct extension.  FFmpeg uses the extension to determine which format or container to use for the output file.

Extract Audio

Here is the command for extracting audio from a video file.

ffmpeg -i input.mp4 -vn -acodec copy audio.aac

The input file name and the extension will have to be changed as required, the rest of the command can stay the same.

The breakup of the FFmpeg extract command

The above command will work only if the input file contains AAC audio. So we first need to figure out the codec of the audio stream. This can be done using the following command.

ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 input.mp4

In most cases, you can use the audio format returned by the above command as the output file extension. But this does not always work, FFmpeg uses the output file extension to figure out which container or storage format to use. An audio format is different from a container or storage format, even though they are often named the same.

Sometimes the audio format does not have a container format named after it. Among popular formats, PCM and Vorbis are two problematic ones. WAV extension will work for PCM and OGG will work for Vorbis. Since FFmpeg supports numerous formats, it is difficult to have a full list of all the problematic formats. Searching the internet is the only option when faced with an unfamiliar format.

Extract non-default audio stream

If the file has more than one audio track, the previous command will extract only the default audio stream. Use the -map option to extract specific streams. For example, the following command extracts the second audio stream. In the same vein, -map 0:a:2 will extract the third audio stream.

 ffmpeg -i input.mp4 -map 0:a:1 -acodec copy output.aac

Extract and convert

Sometimes we want the extracted audio in a format different from the original.  This may be for reasons like reducing the file size or for compatibility. When we are converting to a new format we don’t need to be bothered about the input audio format. The minimum requirement is to use the appropriate output file extension. From the extension, FFmpeg would figure out which format is needed and use the default encoder for that format. For example, to extract audio and convert it to MP3, use the following command.

ffmpeg -i input.mp4 -vn audio.mp3

You could also specify the audio encoder explicitly like so.

ffmpeg -i input.mp4 -vn -acodec libmp3lame audio.mp3

As far as MP3s are concerned there is no difference between the above commands. This is because libmp3lame is the default MP3 encoder of FFmpeg these days. There may be cases where you want to use an encoder which is different from the default one.

Convert only if required

Converting from one format to another leads to a loss of quality and it takes longer than a  simple extraction. The difference in quality may be marginal depending on the format and settings used. But at least a small decrease in quality would always happen. Use the conversion option only if required. 

Extract Audio without checking audio format

The standard method of extraction is especially inconvenient if we want to do batch processing. Here is a small Python program for extracting audio files without having to check the format first. Please note that it does not work out of the box for all formats; small tweaks to the program will be required in the case of some audio formats. It requires Python 3.5 or above.

""" Extract audio from media files """
import subprocess
import sys
import os


def main(filepath):
    """ Entry point """
    audio_codec = get_audio_codec(filepath)
    # mapping from audio codec to file extension
    audio_formats = {"pcm_s16le": "wav", "pcm_s16be": "wav", "vorbis": "ogg"}
    # get extension matching audio_codec, use audio codec name as default
    extension = audio_formats.get(audio_codec, audio_codec)
    new_name = generate_newname(filepath, extension)
    extract_command = ["ffmpeg", "-i", filepath, "-vn", "-c:a", "copy", new_name]
    subprocess.run(extract_command)


def generate_newname(filepath, extension):
    basename = os.path.splitext(filepath)[0]
    new_name = basename + "." + extension
    i = 1
    while os.path.exists(new_name):
        new_name = new_name = basename + str(i) + "." + extension
        i += 1
    return new_name


def get_audio_codec(filepath):
    """ returns audio codec name of the first audio stream """
    command = [
        "ffprobe",
        "-v",
        "error",
        "-select_streams",
        "a:0",
        "-show_entries",
        "stream=codec_name",
        "-of",
        "csv=p=0",
        filepath,
    ]
    completed_process = subprocess.run(
        command, stdout=subprocess.PIPE, universal_newlines=True
    )
    # For TS files FFprobe seems to return duplicate audio tracks;
    # taking only one
    return completed_process.stdout.split("\n")[0]


if __name__ == "__main__":
    main(sys.argv[1])

How to run

Supply the path to the audio file as the argument. On Linux, it is usually python3 which you need to run.

python ff_extract_audio.py "C:\Users\av\Videos\input.mp4"

Limitations:-

Only the first audio track is extracted

The program extracts only the first audio track from the file. Extracting all the tracks is not currently supported.

Needs tweaking to work with some formats

With most audio formats, the program simply finds the input file’s audio format using the FFprobe command shown earlier. It then proceeds to use that as the file extension. As mentioned earlier, this trick does always work. For example, an audio format like pcm_s16le is not a valid file extension recognized by FFmpeg. Similarly, you may want to use an extension which is different from the audio format name. For example, AAC can be stored in an audio-video container like MP4. By default, FFmpeg uses Audio Data Transport Stream (ADTS) for AAC.

If you need to use an extension that is different from the audio format, you have to modify the audio_formats dictionary in the program. This dictionary contains a mapping from audio format to file extension. For example to use MP4 extension for AAC, modify the following line:-

audio_formats = {"pcm_s16le": "wav", "pcm_s16be": "wav", "vorbis": "ogg"}

To this:-

audio_formats = {"pcm_s16le": "wav", "pcm_s16be": "wav", "vorbis": "ogg", "aac":"mp4"}

Batch Extract

The Python script can be used to batch extract audio from multiple files. Here is a DOS example. CD into the directory containing the media files and run the following command. Adjust the path to the Python script as required. The command extracts audio from all files in the current directory.

for %X in (*.*) do ( python D:\Python\ff_extract_audio.py "%X" )

What if we want to process only certain types of files? The following command extracts audio from files with mp4 and mkv extensions. Adjust the file filter as per your requirement.

for %X in (*.mkv,*.mp4) do ( python D:\Python\ff_extract_audio.py "%X" )

Leave a Comment

Your email address will not be published. Required fields are marked *