はじめに
前回の記事で既存のツールでGPSデータの抽出と表示方法を調べました.
素晴らしいツールがたくさん公開されていますので,それはそれで良いのですが,C#の自作アプリに組み込んで使おうと思うと,なかなか良さそうなものがありません.ということで,自作してみようと思います.コンセプトは,
- 動画(mp4)ファイルからGPS等のセンサデータが格納されたストリームを取り出すのは,FFMpegに任せる.
- C#のプログラムからffmpeg.exeを実行して,ストリーム(データ)をファイルに保存する.
- そのファイルからGPSデータを読み出し,GPXとかKMLに変換して保存する.
他のツールで既にできていることですが,C#で自作しておけば,他のアプリに組み込んで使うことができそうなので,やってみます.はい,趣味です.
FFMpegのインストール
FFMpegをインストールして使ってみます.インストールといっても,実行可能なexeをダウンロードして適当なフォルダに置くだけです.まずは公式サイトにアクセスします.
公式でGitHubからソースコードのみの提供となっていますが,コンパイル済みの実行可能バイナリへのリンクも紹介されていますので,今回はこちらを使います.Windowsのロゴをクリックするとリンクが2つ出てきます.どちらでも良いと思いますが,今回は上のgyan.devにしました.
Windows Build formgyan.devをクリックすると,ビルド済みのウインドウズ用バイナリがたくさんリストアップされます.今回は[release builds]の[latest release version: 4.4.1]にしました.
ダウンロード,解凍すると,解凍したフォルダの中のbinに,ffmpeg.exe,ffplay.exe,ffprobe.exeの3つが格納されているのが確認できます.今回は,この内のffprobe.exeとffmpeg.exeを使います.
ffprobeでデータの内容物を確かめる
ffprobe.exeでmp4ファイル(ファイル名: GX010006.MP4)の中にどんなデータが入っているのかを確かめます.pathを通すのが面倒だったので,上記binフォルダをカレントにして作業しています.
.\ffprobe GX010006.MP4
実行すると,以下のような表示がズラズラと出てきます.
.\ffprobe GX010006.MP4
ffprobe version 4.4.1-essentials_build-www.gyan.dev Copyright (c) 2007-2021 the FFmpeg developers
built with gcc 11.2.0 (Rev1, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '..\..\GX010006.MP4':
Metadata:
major_brand : mp41
minor_version : 538120216
compatible_brands: mp41
creation_time : 2021-11-14T17:34:25.000000Z
firmware : H21.01.01.16.00
Duration: 00:13:53.20, start: 0.000000, bitrate: 16002 kb/s
Stream #0:0(eng): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt709), 1920x1080 [SAR 1:1 DAR 16:9], 15744 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 29.97 tbc (default)
Metadata:
creation_time : 2021-11-14T17:34:25.000000Z
handler_name : GoPro H.265
vendor_id : [0][0][0][0]
encoder : GoPro H.265 encoder
timecode : 17:33:22:03
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
Metadata:
creation_time : 2021-11-14T17:34:25.000000Z
handler_name : GoPro AAC
vendor_id : [0][0][0][0]
timecode : 17:33:22:03
Stream #0:2(eng): Data: none (tmcd / 0x64636D74) (default)
Metadata:
creation_time : 2021-11-14T17:34:25.000000Z
handler_name : GoPro TCD
timecode : 17:33:22:03
Stream #0:3(eng): Data: bin_data (gpmd / 0x646D7067), 54 kb/s (default)
Metadata:
creation_time : 2021-11-14T17:34:25.000000Z
handler_name : GoPro MET
Unsupported codec with id 0 for input stream 2
Unsupported codec with id 100359 for input stream 3
最後の2行でcodecが無いとか言われてますが,取り敢えず無視しておきます.大事なのはStreamから始まっているところで,下から6行目の
Stream #0:3(eng): Data: bin_data (gpmd / 0x646D7067), 54 kb/s (default)
がGoProのセンサデータ等が入っているstreamで,その番号は「0:3」ということが分かります.
ffmpegでデータを取り出す
上で,Stream #0:3にセンサデータが入っていることが分かったので,「0:3」を指定してffmpeg.exeでセンサデータのみを抽出します.
.\ffmpeg -y -i GX010006.MP4 -codec copy -map 0:3 -f rawvideo tmp.bin
細かいオプションの意味は調べ切れてませんが,このコマンドで「GX010006.MP4」から「Stream #0:3」のデータを取り出して,「tmp.bin」に書き出してくれます.上のコマンドを実行してtmp.binができていればOKです.
C#プログラムからffmpegを使う
C#コンソールアプリから上記のffprobe,ffmpegを実行し,その標準出力をC#のコンソールウインドウに表示してみます.検索すると参考例はたくさん出てきます.例えば
- ipconfig.exe コマンドを実行し、その標準出力を例のコンソール ウィンドウにリダイレクトする例
- ffmpegを用いて動画から画像を取り出す【C#】
などを参考にして,以下を作りました.
using System;
using System.Diagnostics;
using System.IO;
namespace GoTest
{
class Program
{
// ffprobeの実行
static void Main(string[] args)
{
using (Process process = new Process())
{
string ffprobePath = Path.GetFullPath(@".\ffprobe.exe"); // フルパス or 相対パスでもOK
string mp4Path = Path.GetFullPath(@".\GX010002.MP4");
process.StartInfo.FileName = ffprobePath; // 実行するファイル指定
process.StartInfo.Arguments = mp4Path; // 実行ファイルに渡すオプション
process.StartInfo.UseShellExecute = false; // リダイレクトする場合はfalseにする
process.StartInfo.RedirectStandardOutput = true; // 標準出力をリダイレクトする
process.Start();
StreamReader reader = process.StandardOutput;
string output = reader.ReadToEnd();
Console.WriteLine(output);
process.WaitForExit();
}
// ffmpegの実行
using (Process process = new Process())
{
string ffprobePath = Path.GetFullPath(@".\ffmpeg.exe");
string mp4Path = Path.GetFullPath(@".\GX010002.MP4");
process.StartInfo.FileName = ffprobePath;
process.StartInfo.Arguments = "-y -i " + mp4Path + " -codec copy -map 0:3 -f rawvideo tmp.bin";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
StreamReader reader = process.StandardOutput;
string output = reader.ReadToEnd();
Console.WriteLine(output);
process.WaitForExit();
}
}
}
}
12-25行目でffprobeを実行,28-41行目でffmpegを実行し,それぞれ出力をコンソールに出力しています.
これを実行すると,C#のコンソール画面にffprobeとffmpegをそれぞれ実行したときの標準出力が表示され,tmp.binにStream #0:3の内容が出力されます.
さて,次回はtmp.binの内容と,GPSデータの抽出について考えていきます.