web-dev-qa-db-fra.com

Double extension de fichier avec FFmpeg

J'essaie de faire passer par FFmpeg tous les fichiers et sous-dossiers sous le chemin d'accès dans lequel je lance la commande, afin de convertir tout fichier MKV en conteneur MP4.

La commande ci-dessous fonctionne, mais le nouveau fichier MP4 créé a toujours l'extension MKV en plus de la nouvelle extension MP4.

find ./ -iname '*.avi' -o -iname '*.mkv' -exec bash -c 'ffmpeg -i "{}" -vcodec copy -acodec copy "{}".mp4' \;

Par exemple :

abcd.mkv (original file)  
abcd.mkv.mp4 (new file)

Comment ajuster la commande pour se débarrasser de l'extension de fichier d'origine?

3
Andy Pittas

Il existe un moyen plus simple de le faire, en plaçant votre commande ffmpeg dans un script bash et en utilisant bash tools. Au lieu de:

find ./ -iname '*.avi' -o -iname '*.mkv' -exec \
    bash -c 'ffmpeg -i "{}" -vcodec copy -acodec copy "{}".mp4' \;

Utilisez find et xargs pour transmettre une liste des noms de fichiers (y compris les noms de fichiers avec des espaces) à, par exemple, $HOME/bin/fixthem (lecture man find;man xargs):

find . -type f -iname '*.avi' -o -iname '*.mkv' -print0  |\
    xargs -0 -r $HOME/bin/fixthem

Avec $HOME/bin/fixthem étant quelque chose comme (et chmod +x 'd):

Remarque: non testé, mais exécuté par /usr/bin/shellcheck.

#!/bin/bash
# convert the *.mkv and *.avi files to .mp4

# determine my name
me=$0
me=${me##*/}

# -h or --help 
help () {
    cat >&2 <<EOF
${me} [-h|--help] [-d|--debug] [-v|--verbose] [-n|--noaction] file file ...
${me}: -h or --help      This message
${me}: -d or --debug     List the commands we execute, as we process
${me}:                   the files.
${me}: -v or --verbose   List the filenames we process, as we process
${me}:                   the files.
${me}: -n or --noaction  Don't actually execute the commands. Used in
${me}:                   connection with --debug for testing.
${me}: -r or --remove    Remove the input file unless --debug is set.
EOF
    exit 2
}

declare -i debug=0 verbose=0 noaction=0 remove=0

# from /usr/share/doc/util-linux/examples/getopt-parse.bash 2015-Sep-06

TEMP=$(getopt -o dhvnr --long debug,help,verbose,noaction,remove \
     -n 'fixthem.bash' -- "$@")

if [[ $? != 0 ]] ; then echo "${me} --help for help." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
        -d|--debug) debug=1; shift;;
        -h|--help) help; shift;;
        -v|--verbose) verbose=1; shift;;
        -n|--noaction) noaction=1; shift;;
        -r|--remove) remove=1; shift;;
        --) shift; break;;
        *) echo "Internal error! ${me} --help for help";exit 1;;
    esac
done

# actual processing begins here
while [[ $# -gt 0 ]] ; do
      infile="$1"
      shift
      nameonly="${infile%.*}"
      outfile="${nameonly}.mp4"
      [[ "$verbose" -ne 0 ]] && echo "$infile -> $outfile" >&2
      command="ffmpeg -i \"$infile\" -vcodec copy -acodec copy \"$outfile\""
      [[ "$debug" -ne 0 ]] && echo "command" >&2
      [[ "$noaction" -ne 0 ]] || eval "$command"
      if [[ "$remove" -ne 0 ]] ; then
      v=""
      [[ "$verbose " -ne 0 ]] && v="-v"
      if [[ "$debug" -ne 0 ]] ; then
          echo "rm \"$infile\"" >&2
      else
          rm $v "$infile"
      fi
      fi
done

exit 0
0
waltinator

Si vous souhaitez conserver votre syntaxe existante (ce qui a probablement du sens pour vous telle qu'elle est), la légère modification suivante devrait conserver ce sens pendant que aussi accomplit le changement de nom de fichier requis:

find -iname '*.avi' -o -iname '*.mkv' -exec \
    bash -c 'ffmpeg -i "{}" -codec copy \
    $(echo "{}" | sed -r 's/.{3}$/mp4/')' \;

Notez que j'ai aussi simplifié votre syntaxe copy avec FFmpeg ...

2
andrew.46