aptpod Tech Blog

株式会社アプトポッドのテクノロジーブログです

SDK入門⑧〜動画アップロードツールの作り方〜

動画ファイルをintdashに取り込みたいみなさん、

こんにちは。ソリューションアーキテクトの伊勢です。

今回はMP4ファイルをintdashの計測データとして登録する方法をご紹介します。

はじめに

すでに保有している計測データファイルをintdashで可視化したいケースがあります。

例えば、システム構想段階でUXを試したいときなどです。

MP4ファイルの計測データ化

通常、intdashの計測データはエッジコンピューターからサーバーに送信されますが、サーバーにファイルの計測データを登録する機能もあります。

intdashのMeas Hubでは、タイプスタンプとデータ値が格納されたCSVファイルをアップロードして計測を作成できます。

Meas Hub 計測アップロード一覧

time,DATA_1,DATA_2,DATA_3
2024-01-01T00:00:00.123456789Z,1,0.1,str1
2024-01-01T00:00:01.123456789Z,2,0.2,str2
2024-01-01T00:00:02.123456789Z,3,0.3,str3
2024-01-01T00:00:03.123456789Z,4,0.4,"str4,example"
2024-01-01T00:00:04.123456789Z,5,0.5,"str5 ""last data"""

この方法ではデータは数値または文字列の形式である必要があります。

今回は映像データを登録するため、SDKを使ってツールを実装します。1

データフロー

今回は、取り込んだ映像を他の計測と同期再生させてみます。

  1. 既存の計測からMP4としてダウンロード
  2. 映像編集ソフトで加工
  3. ツールでMP4ファイル(編集後)をアップロード
  4. Data Visualizerで可視化・同期再生

データフロー

H.264とは

今回扱う映像データはH.264で圧縮されています。

前のフレームから変化した部分だけを扱い、データ量を低減する仕組みです。

  • IDRフレーム/キーフレーム:すべての画素を持ち、単独でデコードできます。動画の基準点として定期的に差し込まれます。
  • Non IDRフレーム/デルタフレーム:変化した部分だけを持ち、単独では表示できません。IDRフレームと組み合わせて利用されます。

www.idknet.co.jp

H.264フレームは、1〜複数のNAL Unit(Network Abstraction Layer Unit)というバイナリ列で構成されます。

MP4ファイルとは

動画や音声をひとつのファイルにまとめて扱える形式です。

再生時には内部の映像や音声を取り出し、タイムスタンプに基づいて同期再生します。

H.264の格納形式とは

バイナリデータである映像フレームを区切る方法です。

  • AVCC形式:保存向き。フレームの先頭にフレームサイズを記録します。最新のMP4で利用されます。2

  • Annex B形式:ストリーム向き。フレームの先頭に境界を示すスタートコードを付与します。intdashなど伝送処理で利用されます。

Gstreamerとは

動画・音声を変換できるオープンソースのメディアフレームワークです。3

今回はMP4ファイルのAVCC形式からAnnex B形式へ変換するのに利用します

インストール

SDK入門②でインストールしたREST APIのクライアントライブリと、

SDK入門④でインストールしたGstreamerとPyGObjectライブラリを利用します。

やってみた

実施手順

それでは、前述の流れでMP4ファイルを取り込みます。

H.264フレームのタイムスタンプが各段階でどうなるかを示します。

タイムスタンプ対応

MP4ファイルはAVCC形式のタイプスタンプ項目に1フレーム目起点の相対時刻を持ちますが、絶対時刻はありません。

そのため、ツールで改めて計測の基準時刻を与える必要があります。

MP4ファイルダウンロード

intdashのMedia Explorerで元計測の映像をMP4ファイルとしてダウンロードします。4 このとき、映像1フレーム目の時刻を覚えておきます。

MP4ファイル作成画面

MP4ファイルをダウンロードします。

MP4ファイルダウンロード

映像編集

MP4ファイルを映像編集ソフトで編集します。

今回は文字をオーバーレイしてみます。

MP4ファイルを出力します。解像度・FPSは映像編集ソフトに依存します。

アップロード実行

対象エッジと基準時刻を指定してアップロードします。

今回は元の計測とは別のエッジとして作成します。

基準時刻は元計測の映像1フレーム目の時刻にします。5

ツール起動

全ての映像フレームがアップロードされ、計測が完了します。

アップロード完了

作成された計測

計測再生

intdashのData Visualizerで元の計測を指定してプレイバック再生します。

  • 映像(左)・GNSS・IMU:元の計測です。
  • 映像(右):編集したMP4ファイルから取り込んだ計測です。

www.youtube.com

映像は元の計測がHD・15FPS、編集後がFullHD・30FPSですが、

計測データのタイムスタンプにより、問題なく同期再生されます。

サンプルプログラム

Gstreamerとデータ送信を非同期で実行しています。

クラスアーキテクチャ

  • Gstreamer:H.264フレームをAVCC形式からAnnex B形式に変換します。
  • Fetchステージ:GsteamerからAnnex B形式のフレームを取り出します。
Convertor

Gstreamerをラップします。

入力はMP4ファイルから呼ばれるため、特にメソッドはありません。

出力では、映像フレームをsizeごとに取得します。

        while len(frames) < size:
            sample = await asyncio.to_thread(self.sink.emit, "pull-sample")
MeasurementWriter

計測の作成・完了、シーケンスの作成・置き換え、チャンク送信を行います。6 intdashのH.264フレームは以下のNAL Unit順で扱うため、Gstreamerから出力されるAUDNALU Type:9をスキップしています。

  • IDRフレーム:SPSNALU Type:7→PPSNALU Type:8→IDRNALU Type:5
  • non-IDRフレーム:non-IDRNALU Type:1
            payload = MeasurementWriter.skip_aud(frame)

IDR/non-IDRを判定し、送信時のデータ型を指定してデータポイント、チャンクを生成しています。

            is_idr = self.is_idr_frame(payload)


            type_name = "h264_frame/idr_frame" if is_idr else "h264_frame/non_idr_frame"
            store_data_point_group = StoreDataPointGroup(
                data_id=StoreDataID(type=type_name, name=data_name),
                data_points=[store_data_point],
            )
            store_data_chunk = StoreDataChunk(
                sequence_number=self.sequence_number,
                data_point_groups=[store_data_point_group],
            )
UploadService

GstreamerパイプラインとFetchステージを並列起動しています。

            self.convertor.start()

            fetch_task = asyncio.create_task(self.fetch())  # H.264フレーム取得
エントリーポイント

MP4ファイルを読んでH.264(Annex B形式)に変換するGstreamerパイプラインを定義しています。

PIPELINE = """
    filesrc location="{path}" !
    qtdemux name=demux demux.video_0 !
    h264parse config-interval=-1 !
    video/x-h264,stream-format=byte-stream,alignment=au !
    appsink name=sink sync=false emit-signals=true
"""


計測の基準時刻をRFC3339形式で指定します。

指定がないときは現在時刻を基準時刻にしています。

            datetime.fromisoformat(basetime)
            if basetime
            else datetime.now(tz=timezone.utc),

おわりに

今回はintdash外のデータを取り込む一例を紹介しました。

MP4ファイルのタイムスタンプを利用して、intdashの時系列管理に統合できました。

既存の計測データでintdashへの格納や可視化を試せると、システム運用を具体的にイメージしやすくなります。

リンク

本シリーズの過去記事はこちらからご覧ください。


  1. コードはGitHubで公開しています。
  2. MPEG-4 Part 10です。本ツールはこの形式のMP4を前提としています。
  3. 入門④でも利用しました。
  4. 2025年4月のバージョンから時間範囲を指定できるようになりました。
  5. 計測の開始時刻≦映像の1フレーム目の時刻のためです。
  6. 計測シーケンス、チャンク送信は入門②を参照ください。