必要なパッケージをインストールする
必要なパッケージは次のとおりです。
gcc
build-essential
mkvtoolnix
ffmpeg
インストールされていなければインストールしておきます。
linuxBean14.04やKDE neonではgcc以外はインストールが必要でした。
build-essentialとmkvtoolnixはデフォルトリポジトリにありました。
ffmpegのインストール
linuxBean14.04ではUbuntu 14.04にPPAからffmpegを導入する - QiitaをみてPPAを追加する必要がありました。
sudo add-apt-repository ppa:mc3man/trusty-media
sudo apt update
sudo apt install ffmpeg
mkvtoolnixのバージョンに注意
mkvtoolnixパッケージのmkvmergeコマンドを使うのですが、バージョンによってオプションの名前が変わっているので注意が必要です。
最初はオプション名がうまくいかない原因とは思わず悪戦苦闘しました。
動画の合成にtimestampsオプションを使うのですが、v17.0.0より以前はtimestampという名称に代わってtimecodeという名称が使われていました(MKVToolNix Version History - VideoHelp)。
KDE neonではデフォルトリポジトリからmkvtoolnixをインストールするとv19.0.0が入りました。
この場合はtimestampsオプションを使います。
linuxBean14.04ではv6.7.0がインストールされるのでtimecodesオプションを使います。
split264のビルド
Cheap Chinese camera garbled .264 files
に解説があります。
.264ファイルはmp4形式のライセンス回避のためにMP4ヘッダーを使わずに似て非なるものにしているそうです。
.264ファイルから映像と音声を抽出するsplit264のソースを取得
ホームフォルダに適当な名前(今回は264)にフォルダを作成します。
右クリック ー> 新規作成 ー> 空のファイル。
ファイル名をsplit264.cにしてOK。
Cheap Chinese camera garbled .264 files
にある2番目にあるコードをsplit264.cにコピペします。
ソースのtimestampをtimecodeに置換する
linuxBean14.04のようにmkvtoolnixのv17.0.0より前のバージョンを使うときはsplit264.c内のtimestampをtimecodeに置換する必要があります。
mkvtoolnix v17.0.0以上のときはこの置換は不要です。
split264.cのコンパイル
split264.cあるフォルダでTerminalを起動します。
gcc -o split264 split264.c
これでsplit264というファイルができました。
264ファイルから映像と音声とタイムスタンプを抽出する
SV3Cが作成したsource.264ファイルを処理します。
SV3Cにはマイクがついていないので音声は入っていません。
./split264 source.264
source.264から.audio.ts.txt, .h264, .video.ts.txt, .wavの4つのファイルができました。
.audio.ts.txtと.video.ts.txtにはタイムスタンプが記録されており1行ずつ数値が並んでいます。
.audio.ts.txtは使いません。
抽出したファイルからmp4ファイルを合成する
.wavファイルを.mp3ファイルに変換する
ffmpeg -i "source.wav" -y "source.mp3"
ただし、音声については私は音声つきの.264ファイルは持っていないので正しく処理されているかは確認していません。
mkvファイルの作成
mkvmerge --output "output.mkv" --timestamps "0:source.video.ts.txt" "source.h264" "source.mp3"
mkvmergeがv17.0.0より前のときは次のようにtimecodesオプションを使います。
mkvmerge --output "output.mkv" --timecodes "0:source.video.ts.txt" "source.h264" "source.mp3"
これでoutput.mkvファイルができます。
mkvファイルをmp4ファイルに変換する
ffmpeg -i "output.mkv" -vcodec copy "output.mp4"
これでsource.264をoutput.mp4に変換できました。
264ファイルをmp4ファイルに変換するシェルスクリプト
convert.sh
#!/bin/bash
# dashではdoneへのリダイレクトが使えない。
# 変換対象のファイルがあるディレクトリパス。
DIRNAME=public/videos
while read -r F ; do
./split264 "${F}264"
ffmpeg -i "${F}wav" -y "${F}mp3" </dev/null
mkvmerge --output "${F}mkv" --timecodes "0:${F}video.ts.txt" "${F}h264" "${F}mp3"
ffmpeg -i "${F}mkv" -vcodec copy "${F}mp4" </dev/null
rm "${F}wav" "${F}mp3" "${F}video.ts.txt" "${F}audio.ts.txt" "${F}h264" "${F}mkv"
if [ -s "${F}mp4" ]; then
rm "${F}264"
fi
done < <(find "${DIRNAME}" -type f -name "*.264" -print | grep -Po ".+\.")
このconvert.shを実行可能にしてbashで実行するとDIRNAMEで指定したフォルダ内にある264ファイルをすべてmp4ファイルに変換します。convert.shと同じフォルダにsplit264に置いておく必要があります。
mp4ファイルができたことが確認できたら元の264ファイルを削除しています。
改行のあるファイル名のファイルの処理にも対応できるように次のスクリプトの方を使うことにしました。
#!/bin/bash
# dashではdoneへのリダイレクトが使えない。
# 変換対象のファイルがあるディレクトリパス。
DIRNAME=public/videos
while read -r -d '' F ; do
./split264 "${F}264"
ffmpeg -i "${F}wav" -y "${F}mp3" </dev/null
mkvmerge --output "${F}mkv" --timecodes "0:${F}video.ts.txt" "${F}h264" "${F}mp3"
ffmpeg -i "${F}mkv" -vcodec copy "${F}mp4" </dev/null
rm "${F}wav" "${F}mp3" "${F}video.ts.txt" "${F}audio.ts.txt" "${F}h264" "${F}mkv"
if [ -s "${F}mp4" ]; then
rm "${F}264"
fi
done < <(find "${DIRNAME}" -type f -name "*.264" -print0 | sed -z 's/264$//')
手間取った点は次の2点です。
grepの正規表現には3種類ある
grep は、「基本」正規表現 (BRE)、「拡張」正規表現 (ERE)、「Perl の」正規表現 (PCRE) という 3 種類の正規表現文法を扱うことができます。デフォルトはBREで、EREを使うときは-Eオプション、PCREを使うときは-Pオプションを付けます。
Man page of GREP
BRE、EREとPCREの大きな違いは、BRE、EREは「?+{|()」に対して特殊な意味を持たせたいときはバックスラッシュをつける必要があり、PCREでは逆に特殊な意味を持たせなくないときにバックスラッシュをつける必要がある点です。
BREとEREには、PCREのJavaScript、Python、PCREの正規表現チェッカー-p--qのようなチェッカーも見つけられませんでした。
ということで可能な限りPCREを使うことになりそうです。
while文でffmpegを使うには</dev/nullが必要
</dev/nullをつけていないと、2つ以上のファイルを処理しようとすると、1つ目のファイルの処理の途中でffmpegが2つ目のファイルを読み込んでしまってエラーで止まってしまいます。
bash と ffmpeg でハマった話
このページをようやくみつけて簡単に解決できました。
その他、名前付きパイプを使ってなんとかできないかとかやってみましたがそれはうまくいきませんでした。
画像蓄積サーバーで稼働させる
暗視機能付きワイヤレス屋外監視カメラシステムの構築-p--q
これの画像蓄積サーバーで稼働させます。
#!/bin/bash
# dashではdoneへのリダイレクトが使えない。
# 変換対象のファイルがあるディレクトリパス。
DIRNAME=public/videos
while read -r -d '' F ; do
./split264 "${F}264"
ffmpeg -i "${F}wav" -y "${F}mp3" </dev/null
mkvmerge --output "${F}mkv" --timecodes "0:${F}video.ts.txt" "${F}h264" "${F}mp3"
ffmpeg -i "${F}mkv" -vcodec copy "${F}mp4" </dev/null
rm "${F}wav" "${F}mp3" "${F}video.ts.txt" "${F}audio.ts.txt" "${F}h264" "${F}mkv"
if [ -s "${F}mp4" ]; then
rm "${F}264"
fi
done < <(find "${DIRNAME}" -mmin -10 -type f -name "*.264" -print0 | sed -z 's/264$//')
10分以内に作成された264ファイルだけ処理するようにしました。*/10 * * * * ~/upload.sh
57 * * * * ~/refreshTokens.sh
8,28 * * * * ~/keepspace.sh
5,15,25,35,45,55 * * * * ~/convert.sh
cron.confはこのようにしてcrontab cron.confで登録して、10分毎にconvert.shを稼働するようにしています。upload.shとrefreshTokens.shはGoogleフォトにアップロードするためのもの(linuxBean14.04(189)Googleフォトにアップロードするシェルスクリプト-p--q)、keepspace.shはディスク容量を保つためのもの(古いファイルから削除してディスク使用容量割合を保つシェルスクリプト-p--q)です。
0 件のコメント:
コメントを投稿