【问题标题】:Bash script: automate ffmpeg encoding for mpeg-dashBash 脚本:自动为 mpeg-dash 编码 ffmpeg
【发布时间】:2018-07-24 00:39:35
【问题描述】:

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

图表:

此脚本检查 fps 一致性,

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

插入频道标志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 期间消除总持续时间的小数? 以及如何检查整体关键帧对齐? 也欢迎我忽略的任何改进!

非常感谢!

马西莫

【问题讨论】:

  • 可以在 ffmpeg-user 邮件列表中询问
  • 请注意,邮件列表仅支持普通的 uscripted ff* 命令。
  • 我想检查连接后的关键帧对齐方式决定任意切割另外两秒我得到 824.012000 秒

标签: bash video ffmpeg mpeg-dash


【解决方案1】:

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

现在

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

ffprobe 测量: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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    相关资源
    最近更新 更多