ffmpeg 跨子目录中的 .avi 文件

ffmpeg 跨子目录中的 .avi 文件

情况:

  • 运行 macOS 10.13.6 并使用 bash 5.0.17(1)
  • 许多包含多个文件的子目录。
  • 需要过滤掉子目录中具有特定扩展名(.avi)的文件。
  • 需要处理所有 .avi 文件并使用 .mp4 重新混合ffmpegffmpeg使用以下语法进行重新混合:ffmpeg -i in.avi -c copy out.mp4
  • 输出格式:与源 .avi 文件位于同一文件夹中,并使用相同的文件名(除了 .avi 扩展名)

文件结构示例:

$ find . -maxdepth 2
.
./abc
./abc/abc.avi
./xyz
./xyz/xyz.avi.mp4
./123
./123/123.avi

在这种情况下,我想过滤掉文件./abc/abc.avi./123/123.avi,我可以使用正则表达式 和 来做到这一点find

$ find -E . -iregex ".*\.avi"
./abc/abc.avi
./123/123.avi

所需的重新混合.mp4输出文件名将是:

./abc/abc.mp4
./123/123.mp4

我怎么能够:

  1. 使用脚本,通过一个命令将所有这些.avi文件重新混合到.mp4容器中?我不确定如何将 的输出通过管道传输find到 的输入ffmpeg,并同时指定所需的输出文件名。
  2. 删除原始.avi文件,但前提是 remux 成功?

答案1

我不是 Arch Linux 的用户ffmpeg,我是在bashArch Linux 的环境中写这个答案的,但是你的两个要求可以在 FreeBSD 和 MacOS-X 上得到满足,例如:

$ from=avi; to=mp4; 
$ find -E . -type f -iregex ".*\.avi" -execdir \
  sh -c 'file=$(basename $3); (ffmpeg -i $file.$1 -c copy $file.$2) 2>/dev/null && \rm $3' shellproc "$from" "$to" {} \;

在上面的一行中:

  • -type f之前包括了-iregex ....它应该通过stat仅“常规文件”类型的文件来节省您的时间。
  • $1代表$from
  • $2代表$to
  • $3代表,即你的命令{}的结果find
  • shellprocin...shellproc "$from" "$to" {} \;只是一个任意标记,用于标识使用以下命令执行的 shell 进程sh -c 'file=$(basename $3); (ffmpeg -i $file.$1 -c copy $file.$2) 2>/dev/null && \rm $3'。该标签将为所述 shell 输出的任何错误消息添加前缀。这就是它的功能。

有几种可能的方法可以实现您想要的功能。我建议你看一下回答作者:Kusalananda,了解(更多)更多关于find ... -exec...的语法。

答案2

归功于Cbhihe的回答,因为它让我走上了正确的道路。由于基线在 Mac 上的工作方式以及文件名中空格的处理,我需要更改一些内容。

macOSfind使用有点特殊的语法。您可以使用以下单行:

find -E . -type f -iregex ".*\.avi" -execdir bash -c 'in=$1; out=${in%.*}.mp4; (ffmpeg -y -i "$in" -c copy "$out") 2>/dev/null && \rm "$in"' shellproc {} \;

  • find -E . -type f -iregex ".*\.avi"搜索文件:
    • .表示搜索当前目录,
    • -E表示允许使用正则表达式的扩展查找,
    • -iregex ".*\.avi"搜索此路径中的所有“.aviz”文件,包括子目录。
  • -execdir bash -c '<COMMAND>' shellproc {} \;使用 bash shell 对每个搜索结果执行命令,从与搜索结果相同的目录执行。文件名作为参数 $1 传递。
  • in=$1; out=${in%.*}.mp4; (ffmpeg -y -i "$in" -c copy "$out") 2>/dev/null && \rm "$in"定义输入和输出文件名,运行 ffmpeg 进行重新混合并抑制详细的 ffmpeg 输出,并仅在重新混合成功完成时删除输入文件。

在 Linux 系统上,find语法略有不同:

find . -type f -regex ".*\.avi" -execdir bash -c 'in=$1; out=${in%.*}.mp4; (ffmpeg -y -i "$in" -c copy "$out") 2>/dev/null && \rm "$in"' shellproc {} \;

相关内容