我正在编写一个 bash 文件来创建视频编码和串联,以供 dash 实时流媒体使用,
基本上,它读取输入视频文件夹,将所有视频编码为三种分辨率格式,然后将它们连接起来创建三个适应集。
DIAGRAM:
该脚本检查 fps 一致性,
如果输入不是 1920 x 1080p,则强制/缩放分辨率,
插入频道标志png,
剪切所有视频输入的末尾,以使它们以闭合 gop 结束,这可以确保不存在具有不同长度的音频和视频轨道的视频。
ISSUE:
实际上,我不确定串联过程是否尊重编码后的闭合 GOP 对齐。
我还尝试剪切串联结果的末尾,以便使其在封闭的 gop 上也没有小数点地完成,但我无法擦除总持续时间中的所有小数点:
total duration in seconds: 826.795000
total duration corrected in seconds: 826
但ffprobe测得的真实持续时间是
824.044000
我尝试检查关键帧与 mp4box 的对齐情况,他们是否教过但没有任何结果:
MP4Box -info TRACK_ID source1.mp4 2>&1 | grep GOP
这是我第一次使用“视频脚本”,可能我不知道要为 TRACK_ID 提供什么输入
重击脚本:
#!/bin/bash
#CANCAT 0.2
cd input
times=()
fps=()
for f in *.mp4; do
_t=$(ffprobe -i "$f" -show_entries format=duration -v quiet -of csv="p=0")
times+=("$_t")
_f=$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \\(.*\\) fp.*/\\1/p")
fps+=("$_f")
done
#SUM ALL DURATIONS
TOTALDURATION=$( echo "${times[@]}" | sed 's/ /+/g' | bc )
#DELETE DECIMAL
DURROUND=$(echo "$TOTALDURATION" | cut -d'.' -f1)
#GET REST OF DIVISION BY 2 AS GOP
TOTDELTA="$((DURROUND%2))"
#SUBTRACT DELTA FROM TOTAL DURATION
TOTDUR="$(($DURROUND-$TOTDELTA))"
#GET NUMBER OF ELEMENTS IN FPS ARRAY
tLen=${#fps[@]}
#CHECK FPS EQUALITY
for tLen in "${fps[@]:1}"; do
if [[ $tLen != ${fps[0]} ]]; then
printf "WARNING: VIDEO’S FRAME-RATE 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
#GET DURATION OF EACH VIDEO
DUR="$(ffprobe -i "$f" -show_entries format=duration -v quiet -of csv="p=0")"
DUR=$(echo "$DUR" | cut -d'.' -f1) # DELETE DECIMAL
#GET FPS OF EACH VIDEO
FPS="$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \(.*\) fp.*/\1/p")"
#ROUND FPS OF EACH VIDEO
FPSC=$( echo "($FPS+0.5)/1" | bc )
#REMOVE EXTENSION FROM VIDEO FILE NAME
NAME=$(echo "$f" | cut -d'.' -f1)
#GET GOP
GOP="$((FPSC*2))"
DELTADUR="$((DUR%2))"
DUR="$(($DUR-$DELTADUR))"
#ENCODE 1080p
ffmpeg -y -i "$f" -i ../logo/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 -crf 22 -t $DUR -filter_complex "[0:v][1:v]overlay=main_w-overlay_w-10:10,scale=1920:1080,setsar=1" ../buffer/${NAME}-1080.mp4
#ENCODE 720p
ffmpeg -y -i ../buffer/${NAME}-1080.mp4 -c:a aac -b:a 256k -ar 48000 -ac 2 -async 1 -c:v libx264 -x264opts keyint=$GOP:min-keyint=$GOP:no-scenecut -bf 0 -s 1280x720 -r $FPSC -b:v 2400k -maxrate 2400k -bufsize 1500k -profile:v main -crf 22 -t $DUR ../buffer/${NAME}-720.mp4
#ENCODE 360p
ffmpeg -y -i ../buffer/${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 -crf 22 -t $DUR ../buffer/${NAME}-360.mp4
done
#enter in buffer
cd ..
cd buffer
#CONCAT 1080 SET
# with a bash for loop
for f in ./*1080.mp4; do echo "file '$f'" >> 1080list.txt; done
ffmpeg -f concat -safe 0 -i 1080list.txt -t $TOTDUR -c copy ../output/1080set.mp4
#CONCAT 720 SET
# with a bash for loop
for f in ./*720.mp4; do echo "file '$f'" >> 720list.txt; done
ffmpeg -f concat -safe 0 -i 720list.txt -t $TOTDUR -c copy ../output/720set.mp4
#CONCAT 360 SET
# with a bash for loop
for f in ./*360.mp4; do echo "file '$f'" >> 360list.txt; done
ffmpeg -f concat -safe 0 -i 360list.txt -t $TOTDUR -c copy ../output/360set.mp4
#CLEAN BUFFER
rm *.mp4
rm *.txt
echo "CONCAT COMPLETED:"
echo "frame-rate: $fps"
echo "total duration in seconds: $TOTALDURATION"
echo "total duration corrected in seconds: $TOTDUR"
带有相关文件夹的完整文件:
带有文件夹的 BASH 脚本 https://www.sendspace.com/file/fe57fv
结果视频 https://www.sendspace.com/file/wkv5h1
有人可以帮助我理解为什么我无法消除 concat 期间总持续时间的小数部分?
以及如何检查整体关键帧对齐情况?
也欢迎我忽略的任何改进!
多谢!
Massimo