Open8

Unity ARFoundationをレコーディングできるようにしたい

やりたいこと

  • ARアプリをUnityで作るのに毎回実機ビルド面倒くさいので、ビルド無しでシミュレーションできるようにしたい。
  • 私個人的に100%リモートワークなので、現地でしか動かないようなARを、録画ファイルを送ってもらって、Unity Editor上で再現する見たいなことをしたい。
  • Geospatial APIのような、公式ARFoundationにはないオプション情報もExtra Trackとしてタイムラインに埋め込みたい。
  • Machine Learningの画像認識とかと連動できるように、ARKitとARCoreの画像と同じフォーマットで再生できると嬉しいが… (ARKitはYCrCbで、2枚のテクスチャ、ARCoreはRGBのテクスチャが飛んでくる。)

リサーチ

AR-Testing

AR Foundation Editor Remote, AR Simulation, Unity MARSの比較をしてくれているのでとりあえずここをみると良さそう

AR Foundation Remote 2.0

第一候補。

Pros

  • エディタ専用でUnityとつなげたiPhone(ARKit), Android(ARCore)を録画する機能がある。多くのAR機能を録画してくれる。実際に仕事で使っている。
  • 値段と節約できる時間を考えるとARやるひとはみんな買っても良さそう

Cons

  • 録画できる画質とフレームレートが荒いので、Maschine Lerningで画像認識できなくもないが、認識精度も体験もかなり劣る感じ

Unity MARS

Unity公式のAR, XRシュミレーター

Cons

  • サブスクで$50/month。
  • ARFoundationの上に更にMARSのWrapperを乗っけて、xRグラスとかも含めた抽象化してる。
  • 画像認識のシュミレーションとかはできなそう
  • ar-simulationのGitHubでも言及されているように、抽象的で分厚いWrapperじゃなくて、ただARFoundationをUnity Editor上で実行したいだけなのに、どうしてこうなった感。

ARKitとARCoreの公式機能

ARKitStreamer

Pros

  • 自分で作ったので自分の欲しい機能を足せる

Cons

  • ARCoreには対応してない
  • URP対応まだしてない
  • NDIをつかっているため、iOSはNDIライブラリのインストールが必須。Unity Cloud Buildできない。(プライベート案件ならソースコードに入れちゃってもいい気がするけど、OSSなので)
  • 録画機能ない
  • 動画とその他情報を別々に送っているので、若干タイムラインにずれがある。

Bibcam by Keijiro

別リポジトリでAvfiというミニマムなrecording/playbackの仕組みも用意してくれている。使いやすそう。

Pros

  • 動画の中にAR上のカメラの座標、回転メタデータを埋め込むことで完全同期
  • フレームレートも早い

Cons

  • 大量のデータを埋め込めない
  • ARFoundationの上に作られてはいないので、シミュレーションをできるわけでは無い

自分で作るとしたら

keijiroさんのBibCamの仕組みをベースにして、動画にメタデータをエンコードするのではなく、meta data timelineとして、mp4に埋め込みたいかな。

Unityで再生する仕組みを用意しないといけなくなるけど…。

AVFoundationでバイナリデータのトラックを追加するのはこのへんで行けそうな

https://developer.apple.com/forums/thread/88276
https://developer.apple.com/documentation/avfoundation/avassetwriterinputmetadataadaptor

AppleのARKitをXcode上でシミュレーションための動画を録画するアプリReality Composerで録画した動画の中身を

ffmpeg -i sample.mov

でみてみると、以下のように大量のMetadataストリームを確認した。これはARKitのメタデータを上述の仕組みで埋め込んでいるやつだと思う。

13:35:21
ffmpeg version 4.4.1-tessus  https://evermeet.cx/ffmpeg/  Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.17)
  configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libmysofa --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvmaf --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-version3 --pkg-config-flags=--static --disable-ffplay
  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 'sample.mov':
  Metadata:
    major_brand     : qt
    minor_version   : 0
    compatible_brands: qt
    creation_time   : 2022-05-30T04:13:49.000000Z
    com.apple.framework.state.MOVStreamIO: <?xml version="1.0" encoding="UTF-8"?>
                    : <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
                    : <plist version="1.0">
                    : <dict>
                    : 	<key>default_options</key>
                    : 	<dict>
                    : 		<key>MIOBitrateMultiplier</key>
                    : 		<real>1</real>
                    : 		<key>MIOBitrateOverride</key>
                    : 		<integer>0</integer>
                    : 		<key>MIOBossMode</key>
                    : 		<false/>
                    : 		<key>MIODisableFrameReordering</key>
                    : 		<false/>
                    : 		<key>MIOForce10bitMonoByVT</key>
                    : 		<false/>
                    : 		<key>MIOForceColorLossless</key>
                    : 		<false/>
                    : 		<key>MIOForceLossless8bitMonoByVT</key>
                    : 		<false/>
                    : 		<key>MIOLogAppendTimeStamps</key>
                    : 		<false/>
                    : 		<key>MIOLogPrepareRecording</key>
                    : 		<false/>
                    : 		<key>MIOSkipSourceHint</key>
                    : 		<false/>
                    : 	</dict>
                    : 	<key>version</key>
                    : 	<string>3.17.10b</string>
                    : </dict>
                    : </plist>
                    :
    com.apple.framework.state.MOVKit: {"extrinsicsSWToW":[0.9999387264251709,-0.0010817100992426276,-0.011017407290637493,-8.9610586166381836,0.0010484313825145364,0.99999487400054932,-0.0030258949846029282,16.653076171875,0.011020624078810215,0.0030141586903482676,0.99993473291397095,-1.6000
    com.apple.recordingEnvironment: {"extrinsicsSWToW":[0.9999387264251709,-0.0010817100992426276,-0.011017407290637493,-8.9610586166381836,0.0010484313825145364,0.99999487400054932,-0.0030258949846029282,16.653076171875,0.011020624078810215,0.0030141586903482676,0.99993473291397095,-1.6000
  Duration: 00:00:54.39, start: 0.000000, bitrate: 115785 kb/s
  Stream #0:0(und): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, smpte170m/bt709/bt709), 1920x1440, 39827 kb/s, 59.96 fps, 60 tbr, 16800 tbn, 16800 tbc (default)
    Metadata:
      rotate          : 90
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : HEVC
    Side data:
      displaymatrix: rotation of -90.00 degrees
  Stream #0:1(und): Data: none (mebx / 0x7862656D), 252 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:2(und): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, smpte170m/bt709/bt709), 640x480, 4433 kb/s, 10 fps, 10 tbr, 16800 tbn, 16800 tbc (default)
    Metadata:
      rotate          : 90
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : HEVC
    Side data:
      displaymatrix: rotation of -90.00 degrees
  Stream #0:3(und): Data: none (mebx / 0x7862656D), 42 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:4(und): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, smpte170m/bt709/bt709), 1280x720, 13303 kb/s, 59.90 fps, 59.94 tbr, 16800 tbn, 16800 tbc (default)
    Metadata:
      rotate          : 90
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : HEVC
    Side data:
      displaymatrix: rotation of -90.00 degrees
  Stream #0:5(und): Data: none (mebx / 0x7862656D), 238 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:6(und): Data: none (mebx / 0x7862656D), 14138 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:7(und): Data: none (mebx / 0x7862656D), 16981 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:8(und): Data: none (mebx / 0x7862656D), 131 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:9(und): Data: none (mebx / 0x7862656D), 570 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:10(und): Data: none (mebx / 0x7862656D) (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:11(und): Data: none (mebx / 0x7862656D), 552 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:12(und): Data: none (mebx / 0x7862656D) (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:13(und): Data: none (mebx / 0x7862656D), 237 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:14(und): Data: none (mebx / 0x7862656D) (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:15(und): Data: none (mebx / 0x7862656D), 1854 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:16(und): Data: none (mebx / 0x7862656D) (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:17(und): Data: none (mebx / 0x7862656D), 654 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:18(und): Data: none (mebx / 0x7862656D), 5394 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:19(und): Data: none (mebx / 0x7862656D), 8637 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata
  Stream #0:20(und): Data: none (mebx / 0x7862656D), 8637 kb/s (default)
    Metadata:
      creation_time   : 2022-05-30T04:13:50.000000Z
      handler_name    : Core Media Metadata

恐らく、videoのタイムラインに同期したmetadataをmp4に同梱するところまではできた。

https://github.com/asus4/Avfi/tree/metadata

次のステップはmp4の再生機能。videoをUnityのテクスチャに反映 & Raw byte dataを送信する

ffmpeg -i record_0707_1737_00.MP4                                                                                                                                                                                                                                            17:37:48
ffmpeg version 4.4.1-tessus  https://evermeet.cx/ffmpeg/  Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.17)
  configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libmysofa --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopus --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvmaf --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-version3 --pkg-config-flags=--static --disable-ffplay
  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 'record_0707_1737_00.MP4':
  Metadata:
    major_brand     : qt
    minor_version   : 0
    compatible_brands: qt
    creation_time   : 2022-07-07T15:37:01.000000Z
  Duration: 00:00:11.42, start: 0.000000, bitrate: 7762 kb/s
  Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 7744 kb/s, 58.25 fps, 240 tbr, 600 tbn, 1200 tbc (default)
    Metadata:
      creation_time   : 2022-07-07T15:37:01.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : H.264
  Stream #0:1(und): Data: none (mebx / 0x7862656D), 11 kb/s (default)
    Metadata:
      creation_time   : 2022-07-07T15:37:01.000000Z
      handler_name    : Core Media Metadata
At least one output file must be specified

Unityのテクスチャにbyte arrayをネイティブ側で突っ込む事例

https://github.com/keijiro/TextureUpdateExample/blob/master/Plugin/Plasma.c

メタデータを受け取るには2種類の方法があるらしい。

https://github.com/robovm/apple-ios-samples/blob/1f6b14ef6e2bda610ef8f1c93b16bf76b8594fbb/AVMetadataRecordPlayTimedMetadataCaptureRecordingandPlayback/README.md

There are a few different ways to retrieve timed metadata from a QuickTime movie, depending on what an application wants to do:

For offline processing of media (such as an export operation), an AVAssetReader can be used. In this case, an AVAssetReaderOutputMetadataAdaptor provides AVTimedMetadataGroups from metadata tracks in the QuickTime movie. This technique is demonstrated by the AVLocationPlayer sample code.

AVMetadataRecordPlay demonstrates how to visualize timed metadata during realtime playback. The app implements a class conforming to the AVPlayerItemMetadataOutputPushDelegate protocol, which creates an AVMutableComposition, and plays the composition with an AVPlayerItem. Detected face metadata is shown by drawing bounding boxes on the video where faces were detected. Video orientation metadata is "visualized" as the app updates the video track's display layer's transform property. Location (GPS) metadata is shown as a string in a UI label.

Unity Integration動いた!macOS, iOSどちらでも動作確認。

https://github.com/asus4/MetaAvfi

次はフレーム単位の同期かな…。ARKitのレコーディングもしたいな。

ログインするとコメントできます