使用 ffmpeg 批量转换文件

使用 ffmpeg 批量转换文件

谁能告诉我这样做哪里错了。

这个想法是找到目录中的所有文件并将其转换为 m4v。无论扩展名是什么。然后,一旦转换完成,就从转换后文件中所谓的“相关”部分生成缩略图。然后,一旦完成,就删除原始文件(理想情况下,如果它比原始文件小 - 但是我还没有弄清楚这一点。)我对 shell 脚本非常陌生,所以任何帮助都将不胜感激。

然后我希望将来能将文件名和详细信息添加到 MySQL 数据库中。如果有人对此有任何建议,我将不胜感激。此外,如何添加检查以跳过已经是 m4v 的文件的转换。

#!/bin/bash
#Convert files using ffmpeg
OrDir="/Volumes/Misc/Test/"
NewDir="/Volumes/Misc/Conv2/"

find "$OrDir" -type f -exec /bin/bash -c \
    'f2=$(basename "$1"); \
     ffmpeg -i "$1" -c:v libx264 -crf 23 -preset ultrafast -c:a aac -strict experimental -b:a 192k -ac 2 "${NewDir}${f2%.*}.m4v" ' _ {} \;
     ffmpeg -ss 3 -i "${NewDir}${f2}.m4v" -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr fps=fps=1/600 "${NewDir}pictures/${f2%.*}.jpg"
     rm $1

更新: 在过去的几天里,我一直在研究这个问题,目前我得到的结果是:

#!/bin/bash
#Convert files using ffmpeg

OrDir="/Volumes/Misc/Test"

find "$OrDir" -type f -exec /bin/bash -c \
    'ND="/Volumes/Misc/Convert/"
     f2=$(basename "$1")
     eval $(ffprobe -v error -of flat=s=_ -select_streams v:0 -show_entries stream=height,width "$1")
     size=${streams_stream_0_height}
     if [ "$size" -gt 720 ]
     then
         size=720
     fi
     ffmpeg -y -hide_banner -i "$1" -codec:v libx264 -profile:v high -preset ultrafast -b:v 500k -qmin 10 -qmax 42 -maxrate 1000k -bufsize 1000k -threads 0 -vf "scale=-1:$size" -pass 1 -c:a aac -strict -2 -b:a 128k -f m4v /dev$
     ffmpeg -y -hide_banner -i "$1" -codec:v libx264 -profile:v high -preset ultrafast -b:v 500k -qmin 10 -qmax 42 -maxrate 1000k -bufsize 1000k -threads 0 -vf "scale=-1:$size" -pass 2 -c:a aac -strict -2 -b:a 128k "$ND${f2%.*$
     ffmpeg -hide_banner -i "$ND${f2%.*}.m4v" -vf "select=gt(scene\,0.4), scale=-1:135, fps=1/60" -frames:v 5 -vsync vfr "${ND}pictures/${f2%.*}_%03d.png"
     rm $1
     mysql --host=****** --user=***** --password=****** db << EOF
     INSERT INTO tbl (Name, FileType, Time, AddedDate) VALUES ("${f2%.*}", '.m4v', 0, NOW());
     EOF
     ' _ {} \;

这有两个问题;首先,它并不总是生成缩略图,有时会返回,Output file is empty, nothing was encoded (check -ss / -t / -frames parameters if used)但创建的文件转换完美;其次,mysql 行没有正确执行并返回错误:_: line 12: mysql: command not found我还没有弄清楚如何获取视频的持续时间,以便将其也添加到数据库中。

答案1

如果您打算扩展这个脚本(从您关于数据库的问题来看),我建议您尽可能地进行参数化。

我还建议使用ffmpegthumbnailer生成缩略图,这应该很简单yum install ffmpegthumbnailerapt-get install ffmpegthumbnailer检查选项 - 在我的脚本中,我生成-s0与原始大小相同的缩略图(),但您可能不想要这样。

这个示例脚本应该可以帮助你入门:

#!/bin/bash
# Convert files using ffmpeg
# USE AT YOUR OWN RISK!

# Parameters
OrDir="/tmp/video/"             # Original directory
NewDir="/tmp/video/out/"        # New directory
PicsDir=${NewDir}pictures/
ignore="m4v"                    # ignore single filetype being converted
convto="$ignore"                # in case you want to convert to something else
thumbnailseek=5                 # Seek % at which to generate thumbnail

# Change to original directory
# For each file:
#       check appropriate (exists, not directory, not already same type)
#       convert to $convto type media file (ffmpeg)
#       generate thumbnail (ffmpegthumbnailer)
#       (optional) remove original if new version smaller

cd "$OrDir"
for oldfile in *.mkv; do        # indeed every file; globbing will eat up  spaces properly
    ext=${i##*.}
    # ignore 1) non-existant files 2) directories 3) $ignore-extentioned files
    if [[ ! -e "$oldfile" ]] || [[ -d "$oldfile"  ]] || [[ "$ext" = "$ignore" ]]; then
            continue
    fi

    filename=${oldfile%.*}
    newfile="$NewDir$filename.$convto"
    oFS=$(stat --printf="%s" $oldfile) # old file size

    ffmpeg -y -loglevel quiet -i "$oldfile" -c:v libx264 -crf 23 -preset ultrafast -c:a aac -strict experimental -$
    nFS=$(stat --printf="%s" $newfile) # new file size

    ffmpegthumbnailer -s0 -i "$newfile" -t $thumbnailseek -o "$PicsDir$filename.jpg" &>/dev/null
    if [ "$oFS" -gt "$nFS" ]; then
            #rm -- "$OrDir$oldfile" # AT OWN RISK: uncomment to remove older file if smaller
    fi
done

我不是专家,只要仔细阅读上述代码就会发现这一点。我将自己的变量命名约定与原始代码中的约定混合在一起(我的目的是保持一定的熟悉度);我可以进一步参数化;我在脚本中编入了相当多的假设(例如,OrDir只包含视频文件);一些条件测试可以简化;文件名和目录处理可以统一。

但这不是代码审查。不应该有任何明显的错误,并且它可以在一些我一直在等待的 mkv 上本地运行,就为了等待这样的事情。

如果你打算用 bash 脚本做更多的事情,那么值得阅读一些常见的 bash 陷阱,如果你有时间高级 Bash 脚本指南


对于“SQL 数据库”,需要更多信息才能提供任何建议。什么类型的数据库?SQLite?为什么要使用 SQL,而不是简单的平面文件(CSV 等)?有哪些详细信息?

相关内容