2018年2月8日木曜日

古い動画ファイルを整理した#1

この記事を書いた後で、時間があるときにNASのデータを整理していた。

今使っているNASの前に使っていたNASは、3年ぐらい使った頃に調子が悪くなってきたので、今のNASを買ったのだ。
クラッシュする前に古いNASからデータを全部読みだして、squashfsで圧縮して、今のNASにコピーした。
その古いNASの中には、さらに古いNASやPCのデータが何重にも入っている。そのため、20世紀末頃のデータも含まれている。
実は、ここで言っている古いコードの発掘は、正確にはPCの整理ではなく、そのsquashfs圧縮されたそのNASデータの中の古いPCデータで行われた。

そんな感じで、そのsquashfs内のデータには、様々なデータが入っている。
もちろん写真や動画もたくさん入っている(このC1で撮影した写真や動画も)。

Linux PCなら、Squashfsデータを簡単にmountでき、内部を参照できるが、TVでは見れない。
TVで見るためには、NASに普通に置かなければならない。
すなわち、Squashfsから読みだして、NASの上に普通にコピーするのだ。
以前からやらないといけないと思いながら、放置していた作業を、先週の土曜からやり始めた。

NASの上のSquashfsのアクセスは遅い。
写真は比較的短時間(とはいえ、数時間かかった)で終わった。実は最初は、写真も動画も一緒にコピーしようとしたが、動画のコピーがあまりにも遅いので、まずは写真だけコピーした。

動画が遅いのは、Motion-JPEG形式だからだ。圧縮率が悪くH264などと比べると、8倍から10倍大きいのだ。
というわけで、大きなデータをコピーするのではなく、H264で再圧縮したものを保存することにした。

動画の再圧縮はffmpegを使えば行える。
ffmpegで動画のエンコードするときビットレートを指定するが、サイズやフレームレートが違えば、適切なビットレートも変わる。
長い歴史の中で様々なサイズやフレームレートの動画が含まれているため、自動で計算/決定するshellスクリプトを用意して、変換するようにした。


2019/02/11 追記: 以下のスクリプトは、一部の動画では正常に機能しない。
動画圧縮し直しスクリプトを直したを参照。

#!/bin/bash
SRCFILE=$1
DSTFILE=$2
if [ -z "$DSTFILE" ]; then
  BASENAME=$(basename $SRCFILE)
  DSTFILE=${BASENAME%.*}.mp4
fi

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}  | cut -d, -f4 | sed -e "s/x[0-9]*//g" | sed -e "s/ //g" )
height=$(echo ${videoFormat} | cut -d, -f4 | sed -e "s/[0-9]*x//g" | sed -e "s/ //g" )
fps=$(echo ${videoFormat}    | cut -d, -f6 | sed -e "s/ *fps//g"   | sed -e "s/ //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" $DSTFILE

# No audio
#ffmpeg -i $SRCFILE -vcodec libx264 -profile:v main -b:v 8192k -pix_fmt yuv420p -f mp4 -metadata "creation_time"="$CREATION_TIME" -map 0:0 $DSTFILE

touch -r ${SRCFILE} ${DSTFILE}
メタデータのencoderには、"OLYMPUS u770SW/S770SW"などのカメラの情報が入っているのだが、それを-metadataで設定しようとしても、"Lavf56.40.101"になって、変更できなかった。

いつまでも悩んでいてもしょうがないので、そのshellスクリプトを使って再圧縮を始めた。 始めたのは日曜の朝だったが、終わったのは月曜の夜だった。

さっき、metadataを再設定する方法を探したら、mp4v2-utilsでできることがわかった。
明日は、それを使ってencoderへカメラの情報を書き戻してみる。

0 件のコメント:

コメントを投稿