2019年2月11日月曜日

動画圧縮し直しスクリプトを直した

ここで使った動画は、このカメラ HC-V480MSを使って撮影して、以前書いたshell-scriptなどを使って、作成した。
ひさしぶりにこのscriptを使ったので、すっかり忘れていたので、吐くメッセージをよく読みながら作業した。
そのとき、ビットレート8192Kbpsで圧縮されているのに気がついた。

このビットレートは、動画のサイズや秒あたりのフレーム数(フレームレート)が不明なときに使う、いわばデフォルト値だ。
実際にそれら情報をffprobeで読みだして、レートを手計算すると、全然違う値になる。
すなわち、うまく処理できずにデフォルト値で動作してしまっているのだ。

よく見ると、カメラで作ったH.264動画のときのffprobeの出力フォーマットが微妙に違うので、サイズやフレームレートを正しく抽出できていなかった。
というわけで、もう少し上手く扱えるようにscriptを直した。
#!/bin/bash
SRCFILE=$1
DSTFILE=$2
if [ -z "$DSTFILE" ]; then
  BASENAME=$(basename $SRCFILE)
  DSTFILE=${BASENAME%.*}.mp4
fi
#---------------------------------------------------------------#
#  Extract informations from source video.   #
#---------------------------------------------------------------#
CREATION_TIME=""
ENCODER=""
videoFormat=""

while read s; do
    s=$(echo $s | sed -e "s/^ *//g");

    if [[ "$s" == creation_time\ :* ]]; then
        if [ -n "$CREATION_TIME" ]; then
     echo "creation_time duplicated. Discard candidate $CREATION_TIME"
        fi
 CREATION_TIME=$( echo $s | sed -e "s/^[ \t]*creation_time[ \t]\+:[ \t]\+//g" )
    fi

    if [[ "$s" == encoder\ :* ]]; then
 ENCODER=$( echo $s | sed -e "s/^[ \t]*encoder[ \t]\+:[ \t]\+//g" )
    fi

    if [[ "$s" == Stream\ *:\ Video:* ]]; then
 videoFormat=$( echo $s | sed -e "s/^[ \t]*Stream \+#.*: \+Video: \+//g" )
    fi
done < <( ffprobe ${SRCFILE} 2>&1 )


echo creation_time=$CREATION_TIME, ENCODER=$ENCODER, videoFormat=$videoFormat

#exit 0
#CREATION_TIME=$(ffprobe $SRCFILE 2>&1 | grep "creation_time" | head -n 1 | sed -e "s/[ \t]*creation_time[ \t]*:[ \t]*//g")

echo SRC: $SRCFILE
echo DST: $DSTFILE
if [ -z "$CREATION_TIME" ]; then
    echo "No \"creation_time\" metadata. use ctime."
    CREATION_TIME=$(stat "$SRCFILE" | grep "^Change:" | head -n 1 | sed -e "s/^Change:[ \t]*//g" | sed -e "s/\.[0-9]* +.*$//g")
fi
echo CERATION_TIME: \""$CREATION_TIME"\"

#---------------------------------------------------------------#
# Auto bitrate       #
#   H.264には、エンコード品質を表すBPP(Bit Per Pixel)という #
#   指標がある。      #
#   BPPを用いて、ビットレートは以下のように計算される。  #
#        #
#                       BPP x fps x width x height  #
#     bitrate[kbps] = ------------------------------  #
#                                  1000                         #
#                                                               #
#   H.264のBPPは、動画の動きの速さと、品質で以下のように #
#   決まっている。      #
#          |               品  質                         #
#                |---------+---------+---------+--------        #
#                |   最高  |   高    |   中    |   低           #
#     -----------+---------+---------+---------+--------        #
#       高  速   |  0.225  |  0.175  |  0.125  |  0.100         #
#       中  速   |  0.200  |  0.150  |  0.100  |  0.075         #
#       低  速   |  0.175  |  0.125  |  0.075  |  0.050         #
#                                                               #
#           高速: スポーツまたはミュージックビデオ  #
#           中速: 映画      #
#           低速: ナレータ(ニュースや演説など)                  #
#                                                               #
#---------------------------------------------------------------#
#videoFormat=$( ffprobe ${SRCFILE} 2>&1 | \
#               grep "Stream \+#[0-9]:[0-9]: \+Video: \+" | \
#        sed -e "s/^ \+Stream \+#[0-9]:[0-9]: \+Video: \+//g" );

bpp="0.225"
width=$(echo ${videoFormat}  | sed -e 's/^.*, \+\([0-9]\+\)x[0-9]\+ .*$/\1/g' )
height=$(echo ${videoFormat} | sed -e 's/^.*, \+[0-9]\+x\([0-9]\+\) .*$/\1/g' )
fps=$(echo ${videoFormat}    | sed -e 's/^.*, \+\([0-9.]\+\) \+fps,.*$/\1/g' )

if [ -z "$width" -o -z "$height" -o -z "$fps" ]; then
    echo "cann't get information for bitrate. Use 8192kbps"
    vBitrate=8192k
else 
    echo "bpp=$bpp, width=$width, height=$height, fps=$fps"
    vBitrate=$(echo "scale=0; $bpp * $width * $height * $fps / 1000" | bc)"k"
fi

echo "bitrate=${vBitrate}"
#exit 0

#---------------------------------------------------------------#
# Convert video format      #
#---------------------------------------------------------------#
ffmpeg -i $SRCFILE -nostdin -y -acodec libvo_aacenc -profile:a aac_low -ab 128k -ar 44100 -ac 2 -vcodec libx264 -profile:v main -b:v ${vBitrate} -pix_fmt yuv420p -f mp4 -metadata "creation_time"="$CREATION_TIME" -metadata "encoder"="$ENCODER" $DSTFILE

# No audio
#ffmpeg -i $SRCFILE -nostdin -vcodec libx264 -profile:v main -b:v ${vBitrate} -pix_fmt yuv420p -f mp4 -metadata "creation_time"="$CREATION_TIME" -metadata "encoder"="$ENCODER" -map 0:0 $DSTFILE

touch -r ${SRCFILE} ${DSTFILE}

2019/07/04 一部の動画で、画面のサイズ取得が正しく動作しない。
新しいやつは、これ。

0 件のコメント:

コメントを投稿