はじめに
前回の記事
GoPro HERO10の動画(mp4)からFFMpegでメタデータを抽出する
GoPro HERO10で撮影した動画(mp4)からC#でGPSデータを抽出していきます.GPS等のセンサデータは,mp4ファイルにメタデータとして格納されていますので,今回は,C#からFFMpegを呼び出してmp4からメタデータを取り出すプログラムを作成しました.
で,GoPro HERO10で撮影した動画(mp4)からffmpegを使ってメタデータを取り出しました.取り出したデータは,バイナリ形式のファイルとして保存されますので,このファイルからGPSデータを抽出して使える形にしたいと思います.
データのフォーマット
GPSデータといっても,測位結果が入っているだけ(のはず)なので,Rawデータを読んでリアルタイムで測位演算するよりは簡単(なはず)です.フォーマットは,こちらのサイトでまとめて下さってます(素晴らしい!)ので参考にさせていただきます.
GitHub - gopro/gpmf-parser: Parser for GPMF™ formatted telemetry data used within GoPro® cameras.
Parser for GPMF™ formatted telemetry data used within GoPro® cameras. - gopro/gpmf-parser
読み進めていきますと,データは下の図のような構造を一つの単位として記録されているようです.
①:データの塊の頭はASCII文字4文字が入ります(FourCCと呼ばれている)
②:データ型をASCII文字1文字で表現
③:データ構造の1単位(ひとかたまり)の合計バイト数
④:データ構造の1単位の繰返し回数
⑤:データが格納される.データ部は32ビット単位で記録されるので,
終端が32ビットに満たない場合はゼロ埋めされる
以下,GPSデータを読むときに関連しそうなものだけをピックアップしてみました.
実際のデータと照らし合わせてみる
ffmpegで抽出したファイルをバイナリエディタで開いて,上のデータフォーマットと照らし合わせてみます.各種データの先頭はASCII文字4文字が入っていますので見やすいです.FourCCを拾いながら構造をみていきますと,以下のようになっていました.
DEVC
DVID
DVNM
STRM
STNM: Accelerometer
加速度関係のデータ色々?(今は無視)
STRM
STNM: Gyroscope
Gyro関係のデータ色々?(今は無視)
|
|
STRM--その他省略
|
|
STRM
STNM: GPS (Lat., Long., Alt., 2D speed, 3D speed)
GPSF
GPSU
UNIT
GPSA
GPS5
|
STRM--その他省略
|
|
DEVC
DVID
DVNM
|
|
以下同じように繰り返し
GPSUの値で想像するに,DEVCは1秒毎に書かれているようです.ホントに1秒かは分かりませんが...いずれにせよ,GPSデータの入っている場所が分かりましたので,その辺りを重点的に読んでみます.
GPSF
GPS Fix状態が3であることがわかります
GPSU
16バイトのデータが1回繰り返されるので,データ部は16バイトになっています.
UTC時刻が,2011年11月13日01時45分34.634秒ということがわかります
GPSP
2バイトのデータが1つなので,データ部の後ろ2バイトはゼロ埋めになっています.
データはDOP×100なので,この時のDOP値は1.43ということがわかります.
DOP値にも色々ありますが,書かれてないので何が出力されているかは分かりません.Fix=3でPDOPかGDOP,Fix=2ならそもそも2次元なのでHDOPですかね...
UNIT
char[3]が5回繰り返しです.lat(緯度), lon(経度), alt(高度), 2d speed, 3d speed の単位になります.
SCAL
4バイト(int32)を5回繰り返しです.latとlonは10,000,000で割る.altと2D speed は1,000で割る.3D speedは100で割ることになります.
GPSA
GPSAは参考にしたサイトでは出ていませんでした.新たに加わったデータでしょうか.
“MSLV”はMean Sea Level(平均海水面)ですかね...高度表現の基準が格納されているものと思われます.
GPS5
(int32が5つ=20バイト)が18回繰り返し.一つ目のブロックを読み取って,スケールファクタで割ると,緯度:34.9814846度,経度:135.9636815度,高度:150.790m,2D速度:0.041m/s,3D速度:0.02m/sになります.多分ちゃんと読めてると思います.
例えば緯度ですが,小数点以下7桁まで記録されています.これは,(1e-7)×3600 = 3.6e-4[秒]になり,日本付近では大雑把に緯度1秒が30mくらいですから,分解能としては,(3.6e-4)×30 = 0.01m程度となります.ですので,1cmくらいまでの分解能で記録できているということになります.
GPX,KML形式で書き出す
以上で,データの所在と読み出し方が分かりましたので,あとは繰り返し読み出して,GPXやKMLなど使いやすい形式で出力するだけです.GPXやKMLのフォーマットは色んなデータを埋め込めますが,必要最小限でテストしていきたいと思います.
今回は,GPX,KMLファイルのテンプレートとして次のような構造にしました.
GPXのテンプレート
<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="SkyRail - https://skyrail.tech/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/0" >
<metadata>
<time>2021-11-14T08:34:24.774Z</time>
</metadata>
<trk>
<name>Track-01</name>
<trkseg>
<trkpt lat="34.9833524" lon="135.7561149">
<ele>10.733</ele>
<time>2021-11-14T08:35:00.084Z</time>
<extensions>
<gpxtpx:TrackPointExtension>
<gpxtpx:speed>0</gpxtpx:speed>
<gpxtpx:dop>3.8</gpxtpx:dop>
</gpxtpx:TrackPointExtension>
</extensions>
</trkpt>
<trkpt lat="34.9851535" lon="135.7604088">
<ele>69.738</ele>
<time>2021-11-14T08:35:02.119Z</time>
<extensions>
<gpxtpx:TrackPointExtension>
<gpxtpx:speed>0.186</gpxtpx:speed>
<gpxtpx:dop>3.8</gpxtpx:dop>
</gpxtpx:TrackPointExtension>
</extensions>
</trkpt>
</trkseg>
</trk>
</gpx>
GPXの場合は,9~18行目のように,<trkpt>…</trkpt>で囲まれた部分が1つの点(データ)になります.緯度,経度,高度,時刻,速度,DOP値を埋め込んでいます.
KMLのテンプレート
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Demo</name>
<description>Description Demo</description>
<Placemark>
<name>Track Title</name>
<description>Track Description</description>
<Style>
<LineStyle>
<color>FF1400BE</color>
<width>4</width>
</LineStyle>
</Style>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>clampToGround</altitudeMode>
<coordinates>
135.7561149,34.9833524,69.738
135.7604088,34.9851535,59.572
135.7604162,34.9852428,52.853
</coordinates>
</LineString>
</Placemark>
</Document>
</kml>
KMLの場合は,19~23行目のように,<coordinates>…</coordinates>の間に,経度,緯度,高度を1点につき1行で埋め込めばOKです.
18行目で,altitudeModeをclampToGroundに設定しています.”clampToGround”にすると,GoogleEarthでの表示(点を線で繋いだ表示)は高度情報を無視して地表面に張り付いた表示になります.”absolute”にすると,海面からの高さ(標高)で表示されます.詳しくは以下に情報があります.
Altitude Modes | Keyhole Markup Language | Google for Developers
完成版のプログラム
以上をまとめて,次のような流れで処理を行うC#コンソールアプリを作成しました.
- GoProで撮影した動画から
- ffmpegでメタデータを抽出して(バイナリファイルに保存)
- GPSデータをGPXとKML形式で書き出す
全ソースコードはGitHubに置いています.ffprobe.exe,ffmpeg.exe,mp4動画のパス,ファイル名はプログラム内にベタ打ちしてますので適宜変更して下さい.
GitHub - Space-Sky-Rail/GoProGPS
Contribute to Space-Sky-Rail/GoProGPS development by creating an account on GitHub.
いつもは,もうちょっと機能追加してからとか,もうちょっとスマートなコードにしてからとか思っている内に,段々熱が冷めて何も公開せずに終わるのですが,今回は不完全でも公開することにしました.日曜プログラミングですので,ヘボい処理があってもご容赦下さい...
追記(GUIアプリ)
コンソール版,しかもファイル名等ベタ打ちはやはり使いにくいので,勢いでGUI付けました.
詳細は別ページにまとめています.C# (wpf, .NET6)で作りました.