如何编写一个通用的 shell 脚本来识别视频文件并根据一些规则使用 FFmpeg 对其进行转码?

如何编写一个通用的 shell 脚本来识别视频文件并根据一些规则使用 FFmpeg 对其进行转码?

我正在尝试获取一个简单的(仅运行几个命令)脚本,该脚本应该读取包含视频文件子文件夹的文件夹,选择未 HEVC 编码的文件夹并将它们传递给ffmpeg,然后 - 比较输入和输出文件,如果输出的大小较大 - 转到下一个文件,或者如果大小较小 - 替换原始文件。

我的逻辑是这样的:

  1. 准备纯txt列表:

    find /folder -type f \( -iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" \) > log.txt
    
  2. 将txt传递给ffprobe

    ffprobe "log.txt" -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1
    

这是ffprobe应该从 接收第 1,2,3 行等的位置log.txt,但是我不知道如何执行此操作,因为ffprobe只接受单个输入。

  1. ffprobe应运行列表并输出非 HEVC 结果log1.txt

  2. 这是log1.txt应该ffmpeg使用系统/tmp文件夹传递到进行转码的位置。我有一个有效的ffmpeg命令,这里的语法对于单个文件来说不是问题。

  3. 比较输入和输出 - 如果输入大于输出 - 替换它。如果输出大于输入 - 丢弃它并继续下一个。

我遇到的问题主要与传递变量(参见 2.)和明确的(5.)有关。我需要一些关于如何处理上述问题的指示,而不是解决方案。

感谢您的阅读。

答案1

您不应该使用 find 来创建文件列表。解析 find 的输出是危险的,应该避免– 特别是当涉及带空格的文件名时。最好准备一个脚本来完成大部分工作,并通过 find 的 exec 参数执行它(受保护的分号是必要的,我还使用单引号来阻止 bash 而不是 find 扩展通配符):

find /folder -type f \( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' \) -exec transcode.sh {} \;

您可以直接在文件上调用 ffprobe 并将输出通过管道传输到 grep 以检查编解码器名称(请注意,我不知道您想要的编解码器的实际名称,请适应):

if ffprobe "$1" -hide_banner -loglevel panic -select_streams v:0 -show_entries stream=codec_name | grep -q 'hvec'
then
  # TODO: do transcoding
fi

转码后可以比较文件大小并采取相应的行动(请注意,我故意将文件存根保留在适当的位置,这样您下次执行脚本时就不会浪费时间和精力再次对文件进行转码):

if [[ $(stat -c%s "$f") -gt $(stat -c%s "$fhvec") ]]
then
  mv "$fhvec" "$f"
else
  truncate -s 0 "$fhvec"
fi

还有一个更一般的警告:仅对不重要的数据(预览、缩略图、代理)执行此操作。 HVEC 是一种功能强大的编码器,但您最终可能会得到包含来自两个不同编码器的压缩伪影的视频。它们可能很小,但看起来也很难看。

相关内容