使用 FFmpeg 进行双文件扩展

使用 FFmpeg 进行双文件扩展

我正在尝试让 FFmpeg 遍历我运行命令的路径下的所有文件和子文件夹,将任何 MKV 文件转换为 MP4 容器。

我已经运行了下面的命令,但是创建的新 MP4 文件除了新的 MP4 扩展名外,仍然具有 MKV 扩展名。

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

例如 :

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

如何调整命令以摆脱原始文件扩展名?

答案1

如果你希望保持你的现存的语法(这对你来说可能很有意义)以下轻微的修改应该保留这个含义,而完成所需的文件名重命名:

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

请注意,我也简化使用 FFmpeg 的语法copy...

答案2

有一种更简单的方法可以做到这一点,即将ffmpeg命令放入bash脚本并使用bash工具。而不是:

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

使用findxargs传递文件名列表(包括带空格的文件名),例如$HOME/bin/fixthem(读取man find;man xargs):

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

类似于$HOME/bin/fixthem(和chmod +x'd):

注意:未经测试,但可以运行/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

答案3

另一种方法是,如果您的文件名没有空格,换行符或其他奇怪的字符:

for file in $(find -iname '*.avi' -o -iname '*.mkv')

do
ffmpeg -i $file -codec copy ${file%%.*}.mp4
done

这将删除最后一个点 (.) 后的所有扩展名,然后添加.mp4。如果文件名中可能存在空格,请改用以下命令:

find . -iname '*.avi' -o -iname '*.mkv' -print0 | while read -d $'\0' file;

do
  ffmpeg -nostdin -i "$file" -codec copy ${file%%.*}.mp4
done

答案4

由于处理大量代码有点麻烦,所以我只是在编码开始之前添加了一个重命名命令并删除了.mp4扩展。

ren Troc*.mp4 Troc*.
for %%a in ("Troc*.") do "F:\Dropbox\PortableApps\ffmpeg" -i "%%a" -c:v libx264  -crf 22 -c:a aac -b:a 128k "%%a(ff).mp4"

这是我的文件夹的屏幕截图:

经过调整名称的文件的缩略图显示正确

相关内容