TL;DR
動画をネットからDL → コマンド実行 → multiavchdでAVCHD、という手順になる。以前は、XMedia RecodeやJoinMP4GFilesなどのGUIツールを使っていて時間を要していた箇所;副作用としてffmpegで動画を”正規化”するので、再生可能となる動画が増えた。
カーナビ諸元
旧手順
- 動画をネットからDL … 怪しいDLサイト使うか、有料のDLソフトを使う。
- XMedia Recode を使ってmp4ファイルをコンバートする。
- JoinMP4GFiles を使ってmp4ファイルを連結する。チャプタのタイムコードを得る。
- multiavchdを使ってmp4ファイルをAVCHD形式に変換する。
↑の手順に沿って車載動画を作成したところ、①正常に再生できるもの、②まったく再生できないもの、③連続再生はできるけどチャプタのジャンプをしようとすると再生できないもの、の3パタンがあった。
新手順
環境
- ubuntu20.04/wsl2/windows11
- ffmpeg version 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers, built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
手順
- 動画をネットからDL … 怪しいDLサイト使うか、有料のDLソフトを使う。
- DLした動画はジャンルごとにフォルダ分けしておく。後続の処理で動画を連結する際、フルパスの辞書順で連結されるため。
eg.
00.orig/dir1_anime/anime01.mp4
00.orig/dir1_anime/anime02.mp4
00.orig/dir2_sports/sports01.mp4
00.orig/dir2_sports/sports02.mp4
00.orig/dir2_sports/sports03.mp4
- DLした動画はジャンルごとにフォルダ分けしておく。後続の処理で動画を連結する際、フルパスの辞書順で連結されるため。
- ffmpegコマンドで動画のエンコードと連結、チャプタファイルの作成を実行する。
- multiavchdを使ってmp4ファイルをAVCHD形式に変換する。
スクリプト
以下のスクリプト2点をローカルに作成。bash convert.sh
を実行すると、output.mp4とtimecodes.txtが作成される。これをmultiavchdでAVCHD形式化すればOK。
convert.sh
#!/bin/bash
for mp4 in 00.orig/*/*.mp4
do
ffmpeg -y -i "${mp4}" -vf scale=720:480,fps=30000/1001 -c:v rawvideo -pix_fmt yuv420p -c:a pcm_s16le -ar 48000 -af "loudnorm,aresample=async=1,aformat=channel_layouts=stereo" "${mp4%.*}.avi"
done
ls 00.orig/*/*.avi | sed "s/^/file '/g" | sed "s/$/'/g" | tee avi.txt
ffmpeg -y -f concat -safe 0 -i avi.txt -fflags +genpts -fflags +igndts -vf fps=30000/1001,scale=720:480 -c:v libx264 -r 30000/1001 -c:a aac -ar 48000 output.mp4
bash make_timecodes.sh avi.txt timecode.txt
cat timecode.txt
make_timecodes.sh
#!/bin/bash
# make_timecodes.sh: ffmpeg用concatファイルリストから各ファイルの開始タイムコード(ミリ秒付き)を計算・出力するスクリプト
if [ $# -ne 2 ]; then
echo "Usage: $0 input_file_list output_timecodes"
echo " input_file_list : ffmpeg concat用ファイルリスト"
echo " output_timecodes : 出力するタイムコードファイル名"
exit 1
fi
file_list="$1"
output="$2"
offset=0
> "$output" # 出力ファイル初期化(空にする)
while IFS= read -r line
do
# 行が file '...' の形式と仮定してファイルパス部分のみ抽出
file=$(echo "$line" | sed -e "s/file '\(.*\)'/\1/")
# offset(秒の小数)をHH:MM:SS.mmm形式に変換
offset_int=${offset%.*}
offset_frac=${offset#*.}
# 小数部が無ければ"000"をセット
if [ "$offset_frac" = "$offset" ]; then
offset_frac="000"
else
# ミリ秒3桁に切り詰め&0埋め
offset_frac=${offset_frac:0:3}
while [ ${#offset_frac} -lt 3 ]; do
offset_frac="${offset_frac}0"
done
fi
h=$((offset_int / 3600))
m=$(((offset_int % 3600) / 60))
s=$((offset_int % 60))
printf '%02d:%02d:%02d.%s\n' $h $m $s $offset_frac >> "$output"
# ffprobeで動画長秒(小数点付き)を取得
duration=$(ffprobe -v error -select_streams v:0 -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 "$file")
# offsetを更新
offset=$(echo "$offset + $duration" | bc)
done < "$file_list"
echo "Timecodes saved to $output"
結果・考察・知見
- コマンド化により煩雑なGUI操作が減った。作業時間短縮とオペミス削減。
- ②③で再生不可となる動画が減った。これまでのところ再生不可となる動画は確認されていない。
- rawvideo形式の中間ファイルが生成される。10GBオーダーで無駄なファイルが発生。。。
- どういう原理で再生不可が減ったのだろうか。mp4としてDLした時点ではいろんな映像形式があるけど、rawvideo化により映像形式の種類が減って、カーナビの再生可能形式の範疇となるのだろうか。
Next Action
- 中間ファイルの容量削減 … rawvideoでなくてh264でも、形式を絞ってやればうまくいくのかもしれない。
- multiavchdのプロジェクトファイル(.mpf)を自動作成
- multiavchdのコマンド実行
- 動画DLの自動化。一番ハードルが高そう;
まとめ
カーナビ動画の作成をコマンド化することで、時短と再生可能性向上を達成できた。さらなる自動化を進めていく。
コメント