ffmpeg:检查视频文件夹与bash文件的一致性
我编写了一个小的bash文件,用于读取文件夹、生成播放列表、连接、添加徽标并对dash ready的大视频结果进行编码,我希望通过检查所有视频的一致性来实现它:它们是否具有相同的fps、相同的分辨率、相同的时基等。 以下是我的情况:ffmpeg:检查视频文件夹与bash文件的一致性,bash,video,ffmpeg,mpeg-dash,Bash,Video,Ffmpeg,Mpeg Dash,我编写了一个小的bash文件,用于读取文件夹、生成播放列表、连接、添加徽标并对dash ready的大视频结果进行编码,我希望通过检查所有视频的一致性来实现它:它们是否具有相同的fps、相同的分辨率、相同的时基等。 以下是我的情况: #!/bin/bash # CONCAT DEMUXER #This demuxer reads a list of #files and other directives from a text file and demuxes them one after th
#!/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 ($1 * 3600) + ($2 * 60) + $3 }')
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 ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
done
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
我希望在处理之前检查视频是否具有相同的fps和相同的分辨率
谢谢
马西莫Bash
有人在这个问题中发布了一个获取视频持续时间的示例:
他的做法是:
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
以下是一些很好的例子:
您可以将第一个视频的结果保存在变量中,并将所有其他视频与第一个视频进行比较。
如果需要,可以给你更多的例子
但我可以推荐另一种方式:nodejs
NodeJS
如果您熟悉JavaScript,只需编写一个NodeJS脚本。在我看来,代码更容易编写
您需要安装NodeJS。在您的项目中,使用npm安装安装fluent-ffmpeg——保存fluent-ffmpeg
在您选择的js文件中编写脚本,并使用node script.js
从bash脚本运行脚本
从视频文件中查找所需信息的代码段如下所示:
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视频转换为输出目录,并在以下情况下连接它们:
#!/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
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
以下是一些很好的例子:
您可以将第一个视频的结果保存在变量中,并将所有其他视频与第一个视频进行比较。
如果需要,可以给你更多的例子
但我可以推荐另一种方式:nodejs
NodeJS
如果您熟悉JavaScript,只需编写一个NodeJS脚本。在我看来,代码更容易编写
您需要安装NodeJS。在您的项目中,使用npm安装安装fluent-ffmpeg——保存fluent-ffmpeg
在您选择的js文件中编写脚本,并使用node script.js
从bash脚本运行脚本
从视频文件中查找所需信息的代码段如下所示:
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视频转换为输出目录,并在以下情况下连接它们:
#!/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
#!/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 ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
_f=$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*/\1/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\0" "${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($1, A, ":"); split(A[3], B, "."); print 3600*A[1] + 60*A[2] + B[1] }')"
FPS="$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*/\1/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
嗨,你在想什么?是原始的,可以在代码经济的情况下编写更多代码,但似乎有效:
#!/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 ($1 * 3600) + ($2 * 60) + $3 }')
times+=("$_t")
_f=$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*/\1/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\0" "${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($1, A, ":"); split(A[3], B, "."); print 3600*A[1] + 60*A[2] + B[1] }')"
FPS="$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*/\1/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
感谢Uwe,我多次听说node.js,但我从未研究过它,正如你所知,我想在一个bash文件中集成所有必要的操作,以使视频concat准备就绪,但我首先遇到了有关音频视频同步的问题:因为不是所有视频都有音频轨道,只要视频,我使用ffmpeg上的-t剪切它们,使其以i帧结束,但如果有多个视频出现此问题,则会导致音视频同步出现故障,我希望解释我自己。。出于这个原因,我认为暂时放弃这个意图太难实现自动化me@MassimoVantaggio不要放弃,这并不像你想的那么难。无需验证相同的参数,只需重新编码所有视频。我发布了一个完整的bash脚本示例,请参见更新的答案。使用您提供的两个视频进行测试,效果良好。只需在包含输入视频的目录中运行脚本,就可以在输出文件夹中获得concat.mp4。重新调节需要一些时间…您希望我在调试完媒体服务器后立即学习node.js。。谢谢你,我们!感谢Uwe,我多次听说node.js,但我从未研究过它,正如你所知,我想在一个bash文件中集成所有必要的操作,以使视频concat准备就绪,但我首先遇到了有关音频视频同步的问题:因为不是所有视频都有音频轨道,只要视频,我使用ffmpeg上的-t剪切它们,使其以i帧结束,但如果有多个视频出现此问题,则会导致音视频同步出现故障,我希望解释我自己。。出于这个原因,我认为暂时放弃这个意图太难实现自动化me@MassimoVantaggio不要放弃,这并不像你想的那么难。无需验证相同的参数,只需重新编码所有视频。我发布了一个完整的bash脚本示例,请参见更新的答案。使用您提供的两个视频进行测试,效果良好。只需在包含输入视频的目录中运行脚本,就可以在输出文件夹中获得concat.mp4。重新调节需要一些时间…您希望我在调试完媒体服务器后立即学习node.js。。谢谢你,我们!你应该检查你的脚本。它将帮助你发现问题。谢谢,我只是尝试一下。你应该检查你的脚本。它会帮你找到问题。谢谢,我只是试试