Batch extract audio with avconv without transcoding

20,372

Solution 1

You can use a simple for loop:

for i in *.mp4; do
    avconv -i "${i}" -map 0:1 -c:a copy "${i%.mp4}.aac"
done

or on one line:

for i in *.mp4; do avconv -i "${i}" -map 0:1 -c:a copy "${i%.mp4}.aac"; done

What is does is run avconv once for every file named like *.mp4 where the filename is stored in the ${i} variable.

${i%.mp4} means ${i} (ie. the filename) with .mp4 stripped off from the end.

Solution 2

Xiao's answer is generally the most useful if you have all the files in one directory; but if there are MP4 files scattered in different directories, you can use this find command to convert them all.

find . -type f -name '*.mp4' -exec bash -c 'avconv -i "$0" -c:a copy "${0/%mp4/m4a}"' {} \;

This uses a slightly different form of bash string substitution at the end: "${0/%mp4/m4a}" tells bash to replace mp4 with m4a, but only if the mp4 is at the end of the string.

Solution 3

To avoid multiple files being processed at the same time (which might use too many resources), use parallel. By default, it only does one job at a time. If you want to use multiple CPU cores in parallel, try parallel -j 4 ... for 4 jobs in parallel. Also check out man parallel.

sudo apt-get install parallel

This line will extract aac audio files from selected videos and put them into m4a containers.

parallel avconv -i '{}' -map 0:1 -c:a copy '{.}.m4a' ::: %F

When working straight in the CLI, substitute%F with the list of your input files. E.g. *.mp4.

Inspired by this answer, by a previous answer to this question, and by evilsoup's comment to the latter (saying: 'raw aac files can't contain metadata; if you want to keep metadata from the original files then use m4a (which is just another name for mp4, but is fairly widely recognised by audio players) instead of aac as a file extension').

I use such commands in Thunar custom actions,

enter image description here

limiting the application to videos that contain aac audio.

enter image description here

To have a terminal window open during processing, which closes at the end, the command can be changed like:

 gnome-terminal -e "parallel avconv -i '{}' -map 0:1 -c:a copy '{.}.m4a' ::: %F"

Solution 4

I extended @Xiao-Long Chen's answer, turning it into a script that skips files when the output file is newer:

#!/bin/bash

for file in *.mp4; do
    OUT="${file/.mp4/.m4a}"

    if [ "$file" == "$OUT" ]; then
        echo "Unable to handle $file" >&2
        exit 1
    fi

    if [ "$OUT" -nt "$file" ]; then
        echo "Skipping $file; output file is newer."
        continue
    fi

    echo "Converting \"$file\" -> \"$OUT\""
    avconv -loglevel warning -i "$file" -map 0:1 -c:a copy "$OUT"
done
Share:
20,372

Related videos on Youtube

oshirowanen
Author by

oshirowanen

Updated on September 18, 2022

Comments

  • oshirowanen
    oshirowanen over 1 year

    I have about 70 mp4 files, and I want to extract the audio files directly without transcoding further. All the mp4 files have aac audio files.

    I understand I can use the following command to extract the audio file from one of the mp4 files:

    avconv -i "INPUT FILE" -map 0:1 -c:a copy "OUTPUT FILE"
    

    How do I extract all the audio files from all the 70 mp4 files, so I end up with 70 aac files?

  • evilsoup
    evilsoup over 11 years
    IIRC, raw aac files can't contain metadata; if you want to keep metadata from the original files then use m4a (which is just another name for mp4, but is fairly widely recognised by audio players) instead of aac as a file extension.
  • Andrew Gunnerson
    Andrew Gunnerson over 11 years
    I never knew that bash had that type of substitution. Awesome :)
  • evilsoup
    evilsoup over 11 years
    @xiao If you leave out the %,it'll do the substitution for the first instance of the string it finds; you can also use # to make it only substitute the string if it's at the start of a variable; so ${0/mp4/m4a} would replace the first instance of mp4 with m4a (which could be a problem if you have really weird filenames); and ${0/#mp4/m4a} will substitute mp4 for m4a, but only if the variable's string value begins with mp4 (no use here, obviously, but it might come in handy elsewhere).
  • sivaprakash
    sivaprakash over 10 years
    What is the -map option for? Why do you choose the 0:1 stream rather than other streams, such as 0:0, 0:2?
  • sivaprakash
    sivaprakash over 10 years
    I dropped the -map option and it works just fine
  • Admin
    Admin over 9 years
    to use this command in Thunar custom actions and similar, it works if added to a script and in Thunar actions: bash /path/to/the/script %F - like here
  • dr. Sybren
    dr. Sybren almost 9 years
    @qed: dropping -map may still cause the video to be regarded when you switch to another output format (if that format can contain both audio and video). It's safer to keep it as-is.
  • johny why
    johny why over 8 years
    i'm surprised you can't just use an asterisk, something like: avconv -i *.m4a -c:a copy *.aac