gpt4 book ai didi

Bash 脚本 : automate ffmpeg encoding for mpeg-dash

转载 作者:行者123 更新时间:2023-11-29 09:29:23 25 4
gpt4 key购买 nike

我正在编写一个 bash 文件来创建视频编码和连接以供 dash 直播流使用,基本上它读取一个输入视频文件夹,将所有视频编码为三种分辨率格式,然后将它们连接起来创建三个适应集。

图表:

enter image description here

此脚本检查 fps 一致性,

如果输入不是 1920 x 1080p,则强制/缩放分辨率,

插入 channel 标志png,

剪切所有视频输入的结尾,使它们以封闭的 gop 结束,以确保不存在具有不同长度的音频和视频轨道的视频。

问题:

实际上,我不确定串联过程是否遵守编码后的封闭 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 提供什么输入

BASH 脚本:

#!/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 SCRIPT WITH FOLDERS

RESULT VIDEO

有人可以帮助我理解为什么我不能在 concat 期间消除总持续时间的小数点吗?以及如何检查整体关键帧对齐?也欢迎任何我忽略的改进!

非常感谢!

马西莫

最佳答案

我明白算法中有一个很大的错误:总时长是在单个视频剪切过程之前计算的,所以总时长总是比有效连接时长更长,我修正了它,

现在

total duration in seconds: 824.044000
total duration corrected in seconds: 824

ffprobe measure:824.012000,我无法在没有小数的情况下获取它并检查整体关键帧对齐。

#!/bin/bash
#CANCAT 0.2

cd input
fps=()
# GET FPS OF ALL VIDEOS INTO ARRAY
for f in *.mp4; do

_f=$(ffmpeg -i "$f" 2>&1 | sed -n "s/.*, \\(.*\\) fp.*/\\1/p")
fps+=("$_f")
done

#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
times=()
for f in *1080.mp4; do
_t=$(ffprobe -i "$f" -show_entries format=duration -v quiet -of csv="p=0")
times+=("$_t")
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))"


#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 脚本 : automate ffmpeg encoding for mpeg-dash,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48770268/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com