ffmpeg:检查视频文件夹与 bash 文件的一致性
ffmpeg: check video folder conformance with bash file
我写了一个小 bash 文件来读取文件夹、生成播放列表、连接、添加徽标并对大视频结果进行编码以准备好破折号,我想通过在所有视频之前检查来实现它一致性:如果它们具有相同的 fps、相同的分辨率、相同的时基等。 下面我的情况:
#!/bin/bash
# CONCAT DEMUXER
#This demuxer reads a list of #files and other directives from a text file and demuxes them one after the other, as if #all their packets had been muxed together. All files must have the same streams (same #codecs, same time base, etc.) but can be wrapped in different container formats.
times=()
for f in *.mp4; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ( * 3600) + ( * 60) + }')
times+=("$_t")
done
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
printf "file '%s'\n" *.mp4 > playlist.txt
ffmpeg -auto_convert 1 -f concat -safe 0 -i playlist.txt -c:a aac -b:a 384k -ar 48000 -ac 2 -async 1 -c:v libx264 -x264opts 'keyint=50:min-keyint=50:no-scenecut' -r 25 -b:v 2400k -maxrate 2400k -bufsize 1200k -vf "scale=-1:432" -vf "movie=stable.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:10 [out]" -t $TOTALDURATION out.mp4
#clear
echo “VIDEO CONCAT COMPLETED”
例如下面我发现这个 bash 计算文件夹视频的总持续时间
times=()
for f in *.mp4; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ( * 3600) + ( * 60) + }')
times+=("$_t")
done
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
我想在处理之前检查视频是否具有相同的 fps 和相同的分辨率 谢谢 马西莫
Bash
有人在此问题中发布了一个获取视频时长的示例: ffmpeg how do I get the duration onto the node.js?
他的做法是:
ffmpeg -i input.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//
在我看来你应该使用 ffprobe 而不是 ffmpeg。更好的语法:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4
可以在这里找到很好的例子:https://trac.ffmpeg.org/wiki/FFprobeTips
您可以将第一个视频的结果保存在一个变量中,并将所有其他视频与第一个视频进行比较。 如果需要可以给你更多的例子。
但我可以推荐另一种方式:nodejs
NodeJS
如果你熟悉JavaScript,写一个NodeJS脚本就可以了。我认为代码更容易编写。
您需要安装NodeJS。在您的项目中使用 npm install --save fluent-ffmpeg
.
https://github.com/fluent-ffmpeg/node-fluent-ffmpeg
在您选择的 js 文件中编写您的脚本,并使用 node script.js
.
从您的视频文件中查找所需信息的代码片段可能如下所示:
var ffmpeg = require('fluent-ffmpeg');
ffmpeg.ffprobe('./input.mp4', function(err, metadata) {
//console.dir(metadata); // all metadata
console.log(metadata.format.duration);
console.log(metadata.streams[0].width);
console.log(metadata.streams[0].height);
console.log(metadata.streams[0].r_frame_rate);
console.log(metadata.streams[0].time_base);
//... use first console.dir to get all possible informations
});
更新BASH
这里是一个完整的例子,将一个目录中的所有 mp4 视频转换到一个 output 目录并在之后连接它们:
#!/bin/bash
SCALE="768:432"
FPS="25"
mkdir -p ./output/
for i in *.mp4;
do name=`echo $i | cut -d'.' -f1`;
echo $name;
ffmpeg -i "$i" -c:v libx264 -preset slow -crf 22 -vf scale=$SCALE -framerate $FPS -c:a aac -b:a 128k -f mp4 "output/${name}.mp4";
done
printf "file '%s'\n" ./output/*.mp4 > ./playlist.txt
ffmpeg -f concat -safe 0 -i ./playlist.txt -c copy ./output/concat.mp4
- 宽度、高度和帧率被设置为一个定义的值以使连接成为可能
- 视频编码的预设是慢,所以重新编码真的很慢;)
- 必要时可以增加音频比特率,例如增加到 192k
嗨@Uwe 你在想什么?是原始的,可以在代码经济中编写更多但似乎有效:
#!/bin/bash
times=()
fps=()
for f in *.mp4; do
_t=$(ffmpeg -i "$f" 2>&1 | grep "Duration" | grep -o " [0-9:.]*, " | head -n1 | tr ',' ' ' | awk -F: '{ print ( * 3600) + ( * 60) + }')
times+=("$_t")
_f=$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*//p")
fps+=(“$_f”)
done
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
tLen=${#fps[@]}
for tLen in "${fps[@]:1}"; do
if [[ $tLen != ${fps[0]} ]]; then
printf “WARNING: VIDEO’S FRAME-RATE (fps) ARE NOT EQUALS, THE PROCESS CAN’T START.”
printf "%s[=10=]" "${fps[@]}" |
sort -zu |
xargs -0 printf " %s"
printf "\n"
exit 1
fi
done
for f in *.mp4; do
DUR="$(ffmpeg -i "$f" 2>&1 | grep "Duration"| cut -d ' ' -f 4 | sed s/,// | sed 's@\..*@@g' | awk '{ split(, A, ":"); split(A[3], B, "."); print 3600*A[1] + 60*A[2] + B[1] }')"
FPS="$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*//p")"
FPSC=$( echo "($FPS+0.5)/1" | bc )
NAME=$(echo "$f" | cut -d'.' -f1)
GOP="$((FPSC*2))"
DURM="$((DUR%2))"
FDUR="$(($DUR-$DURM))"
ffmpeg -y -i "$f" -i logo.png -c:a aac -b:a 384k -ar 48000 -ac 2 -async 1 -c:v libx264 -x264opts keyint=$GOP:min-keyint=$GOP:no-scenecut -bf 0 -r $FPSC -b:v 4800k -maxrate 4800k -bufsize 3000k -profile:v main -t $FDUR -filter_complex "[0:v][1:v]overlay=main_w-overlay_w-10:10,scale=1920:1080,setsar=1" ${NAME}-1080.mp4
ffmpeg -y -i ${NAME}-720.mp4 -c:a aac -b:a 128k -ar 48000 -ac 2 -async 1 -c:v libx264 -x264opts keyint=$GOP:min-keyint=$GOP:no-scenecut -bf 0 -s 640x360 -r $FPSC -b:v 800k -maxrate 800k -bufsize 500k -profile:v main -t $FDUR ${NAME}-360.mp4
done
# with a bash for loop
for f in ./*1080.mp4; do echo "file '$f'" >> 1080list.txt; done
# or with printf
printf "file '%s'\n" ./*1080.mp4 > 1080list.txt
ffmpeg -f concat -safe 0 -i 1080list.txt -c copy 1080set.mp4
# with a bash for loop
for f in ./*360.mp4; do echo "file '$f'" >> 360list.txt; done
# or with printf
printf "file '%s'\n" ./*360.mp4 > 360list.txt
ffmpeg -f concat -safe 0 -i 360list.txt -c copy 360set.mp4
rm *1080.mp4
rm *.txt
rm *360.mp4
echo $TOTALDURATION