監視カメラが生成した264ファイルをmp4ファイルに変換する

2020-07-21

KDE neonを使おう

t f B! P L
暗視機能付きワイヤレス屋外監視カメラシステムの構築-p--qで購入したカメラが作成する動画形式は264という拡張子のものです。WindowsではDownload CD | SV3CにあるHXシリーズ ー> PCソフトウェアにコンバーターやプレイヤーがありますがLinux用は公開されていません。

必要なパッケージをインストールする


必要なパッケージは次のとおりです。

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 種類の正規表現文法を扱うことができます。
 Man page of GREP
デフォルトはBREで、EREを使うときは-Eオプション、PCREを使うときは-Pオプションを付けます。

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)です。

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ