ContorGPSで撮影した動画ファイルからnmeaを取り出す


始めに・背景

ContorGPSで撮影した動画ファイルにはnmea形式のGPS情報が埋め込まれていて、通常、それを取り出すにはContor Starytellerを使って動画をインポートする必要があります。

↓動画ファイルに埋め込まれたnmea形式の文字列

ところが、OSをWindows10にアップグレードしたところStarytellerがまともに動かなくなってしまいました。

そこで、仕方がないので動画ファイルからnmeaファイルを取りだすプログラムを作成しました。ニッチ過ぎて需要があるかわかりませんがせっかく作ったのでシェアします。そんなに高機能ではないです。

ソース

NmeaExporter.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PushbackInputStream;

public class NmeaExporter {

    public static void main(String[] args) throws FileNotFoundException, IOException {
        if (args.length == 0) {
            usage();
            System.exit(1);
        }

        try (PushbackInputStream is = new PushbackInputStream(new FileInputStream(args[0]), 256)) {
            export(is);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static void export(PushbackInputStream is) throws IOException {
        while (true) {
            byte[] buf = new byte[6];

            // ファイル終端に達したら終了
            int bytes = is.read(buf);
            if (bytes < buf.length) {
                break;
            }

            // 欲しいデータじゃなければスキップ
            if (!equals(buf, "$GPGGA") && !equals(buf, "$GPRMC")) {
                is.unread(buf, 1, buf.length - 1);
                continue;
            }

            // ここまで来ると欲しいデータなので改行文字(\r\n)まで出力
            System.out.print(new String(buf));
            while (true) {
                buf = new byte[2];
                is.read(buf);
                if (equals(buf, "\r\n")) {
                    break;
                }
                System.out.print((char) buf[0]);
                is.unread(buf, 1, 1);
            }
            System.out.println("");
        }
    }

    private static boolean equals(byte[] buf, String str) {
        if (buf.length != str.length()) {
            return false;
        }

        for (int i = 0; i < buf.length; i++) {
            if ((char) buf[i] != str.charAt(i)) {
                return false;
            }
        }

        return true;
    }

    private static void usage() {
        System.err.println("ファイルパスを渡してください。");
    }

}

使い方

ソースをコンパイルして次のコマンドを実行すると。[出力ファイル]で指定したパスにnmeaが出力されます。

java NmeaExporter [入力ファイル] > [出力ファイル]

解説

やっていることはいたってシンプルです。動画ファイルの中から
$GPGGA$GPRMCといったnmeaの文字列を探して、見つかれば逐次出力しています。

ちなみに、Storytellerが出力するnmeaファイルの中には$GPEMTという謎のレコードが含まれるのですが、動画ファイルの中にそんな文字列は含まれていません。そもそもnmeaの仕様にすらないようなので無視しちゃいました。

一文字一文字探していくので、大きな動画ファイルからnmeaを取り出すには結構時間がかかります。探索アルゴリズムを工夫すれば(BM法とか)もう少し高速化できそうですが、いずれにせよ計算量はlog(n)なので数倍速くなる程度でしょう。