NDI SDK v5を眺めながらメモ

普通のSDKとAdvanced SDKとある。
dylibがそれぞれあるのと、includeは
- Advanced
- AVSync
- Embedded
- Genlock
の4ファイルが追加されているだけなので、ofxNDIの実装にあたってはこの4ファイルだけを見ると良さそう。
※Mac版のSDKについてしか確認してない。でもたぶんWindows版も同じ

scatter gather listがaudio frameやvideo frameについて扱えるインターフェースがあるが、使い所不明・・・。
メモリ厳しい端末で動かすとき用?
compressed frameを送るときのプロパティと実データについてもこれを使うらしい。なるほど。

AVSyncについてはドキュメント読んでってヘッダに書いてある。
ヘッダとサンプルコードを読んだだけだとわからなかったけど、
NDIlib_avsync_ret_e NDIlib_avsync_synchronize(NDIlib_avsync_instance_t p_avsync, const NDIlib_video_frame_v2_t* p_video_frame, NDIlib_audio_frame_v3_t* p_audio_frame);
これでvideoに同期したaudioが取得できるらしいけど、別スレッドで動かしてるとかの場合は大丈夫?
videoをキャプチャしてからaudioを取り出す仕様なので、キャプチャしてレコーディングとかのときに便利?なのか?
ドキュメントを読んだら追記する
読んだけどよくわからん。
試しに実装してみたらめっちゃ音プチプチした。

audioとvideoが複数あって全部別スレッドで動いてても大丈夫
genlockオブジェクトはアプリで一つ?
You want to only have one genlock source in your application if possible and so you might need to trigger an event and do the sending across many senders on another thread.
-> たぶん同期したい単位につきひとつってことか

Advanced.hをざーっと見た感じ、フレームの圧縮にまつわる機能が追加されている感じ

カスタムアロケータについて
p_dataのallocate/deallocateをやるための自前の関数を設定できる。
NDI SDK的にknownでないフォーマットの信号を扱うときに便利?そんなことある?
たぶんメモリプールをアプリ側で持ってて、そこで使いまわしたいとかそういうことかな。
いちいちmalloc/freeしなくても良くなるということか。

Forwardのサンプルは何をやろうとしてる・・・?
もしかしてこのコードでhighQ優先でだめならlowQを受け取るとかできるの?

サンプルコードをざっと眺め終わった。
ドキュメントを読む。

インストール後は環境変数NDI_RUNTIME_DIR_V4でdllのパスがわかるらしい。
Macでも?addon_config.mkを書くときに再度チェック
ドキュメントにあった
On the Mac, it is not possible to specify global environment variables
and so there is no standard way for the application to provide to specify a path.
For this reason the redistributable on MacOS is installed within /usr/local/lib.
Redistのインストールで.dylibや.aが/usr/local/libに置かれるということだろうが、SDKのインストールでは置かれない。
ユーザーと環境を揃えるにはこちらでもRedist版を改めてインストールする必要があるということか・・・。
Redistパッケージではadvance版のライブラリはインストールされない。
フォーラムに質問投げ中

The libraries (DLLs) for the latest version of NDI should be entirely backwards compatible with NDI v4
とのこと

ビデオフレームのパフォーマンスについて
- YCbCrを使え
- 変換はCPUで自前でやるよりSDKに任せろ
- 送りたいデータがGPUにあって、GPUでエンコードできるならやってくれ

メタデータで<ndi_hwaccel enabled="true"/>
を送るとハードウェアアクセラレーションを明示的に使える。
モダンなバージョンのNDIでは自動で判別するが、ストリームの数やスレッドの数、コアの数など様々なので、全てに通用するルールはないことは覚えておくとよい。

マルチキャストUDPもサポートしているが、ルーター側でマルチキャストがデフォルト状態ではブロードキャストとして実装されていることが多く、ネットワークリソースをめちゃ食うのでNDI側でデフォルトでオフにしてある。

Advanced SDKではFinder, Receiver, Senderそれぞれに設定JSONが渡せて、これは
- Machine name
- NIC
- format
などなどを別々に設定できるということで、これはつよい

Wireshark入れてると接続できなかったり遅くなったりするかも。
Windowsの設定ファイルはC:\ProgramData\NDI\ndi-config.v1.json.
にあって、これはAccessManagerから大体設定できる

MacでReliable UDPを使うには、IPv6が使えるMacOS10.14以降が必要。それ以前でも動くがReliable UDPは使えない。
NDI|HX version 1
を使うならXcodeで下記設定
“Targets->Signing & Capabilities” and ensure that the option “Hardened Runtime -> Disable Library Validation”
iOS14とXcode12ではNDI DiscoveryにmDNS and Bonjourを使うためにUnder “Bonjour Services”, one should assign “Item 0” as being “_ndi._tcp.”が必要
MacもiOSも設定ファイルは$HOME/.ndi/ndi-config.v1.json.

NDIlib_send_timecode_synthesizeでSDK側でタイムコードを生成してくれる。UNIX epoch。
指定しなくてもSystemTimeを使うので、気にしなくても良い。
同マシンならSystemTimeで同期するし、別マシンでもNTPが効いてれば大丈夫なんじゃね?

iOSで使う場合、アプリがbackgroundに行く時はsender instanceを破棄するのがApple推奨

Receiverは接続中のSenderがネットワークから消えても、再度見つかったときに自動でReconnectする。
NDIlib_recv_capture_v3
の呼び出しはスレッドセーフ。
返されたフレームはユーザーが解放する必要がある。

NDIlib_send_set_video_async_completionについて
通常はasync_sendしたフレームは、次のSynchronizing events
までいじっちゃいけないけど、NDIlib_send_set_video_async_completionにコールバックを登録すると、送信完了(=フレームをユーザーが自由にして良い)のタイミングが取得できる
// Synchronizing events are :
// - a call to NDIlib_send_send_video
// - a call to NDIlib_send_send_video_async with another frame to be sent
// - a call to NDIlib_send_send_video with p_video_data=NULL
// - a call to NDIlib_send_destroy

NDIlib_source_v2_tにconst char* p_metadata
がある
-> connectしなくてもconnection_metadataが読めるってこと?名前やIPアドレスだけでなく、メタデータでソースを選べるということか?

CompressedなFrameを送る部分の実装を進める。
ptsとdtsが初耳なので調べる。
ドキュメントより
The PTS and DTS are not used directly by the NDI SDK, however they are important in order to ensure that frames may be decoded and displayed in correct order. While we recommend that you use 100 ns intervals for these values, any time-base is technically supported as long as the ordering of integers is correct.
NDI SDK的には別に何でも良さそう。
このリンク先が分かりやすかった。
ということは、ofxNDI的には具体的な値は気にせず、ユーザーに開いておけば良さそう

iPhone7にReceiverのテストアプリを入れようとしたらH.264のencode/decode関連?でライブラリへのリンクエラー。
Undefined symbols for architecture arm64:
"_kVTEncodeFrameOptionKey_ForceKeyFrame", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::send_packet(NDI_recv_video_header_v2 const&, std::__1::pair<unsigned char*, long>) in libndi_advanced_ios.a(video_codec_interface.o)
"_VTCompressionSessionEncodeFrame", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::send_packet(NDI_recv_video_header_v2 const&, std::__1::pair<unsigned char*, long>) in libndi_advanced_ios.a(video_codec_interface.o)
"_VTSessionSetProperty", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::recreate_compress_session() in libndi_advanced_ios.a(video_codec_interface.o)
"_VTCompressionSessionInvalidate", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::~encode_h264() in libndi_advanced_ios.a(video_codec_interface.o)
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::recreate_compress_session() in libndi_advanced_ios.a(video_codec_interface.o)
"_VTCompressionSessionCreate", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::recreate_compress_session() in libndi_advanced_ios.a(video_codec_interface.o)
"_kVTCompressionPropertyKey_RealTime", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::recreate_compress_session() in libndi_advanced_ios.a(video_codec_interface.o)
"_VTDecompressionSessionInvalidate", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::decode_h264::recreate_decompress_session() in libndi_advanced_ios.a(video_codec_interface.o)
Processing::NDI::Codecs::details::video_codec_impl::decode_h264::~decode_h264() in libndi_advanced_ios.a(video_codec_interface.o)
"_VTDecompressionSessionCanAcceptFormatDescription", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::decode_h264::decode_packet(NDI_recv_video_header_v2 const&, std::__1::pair<unsigned char*, long>) in libndi_advanced_ios.a(video_codec_interface.o)
"_kVTCompressionPropertyKey_AllowFrameReordering", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::encode_h264::recreate_compress_session() in libndi_advanced_ios.a(video_codec_interface.o)
"_VTDecompressionSessionDecodeFrame", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::decode_h264::decode_packet(NDI_recv_video_header_v2 const&, std::__1::pair<unsigned char*, long>) in libndi_advanced_ios.a(video_codec_interface.o)
"_VTDecompressionSessionCreate", referenced from:
Processing::NDI::Codecs::details::video_codec_impl::decode_h264::decode_h264(NDI_recv_video_header_v2 const&, std::__1::pair<unsigned char*, long>, unsigned long long) in libndi_advanced_ios.a(video_codec_interface.o)
Processing::NDI::Codecs::details::video_codec_impl::decode_h264::recreate_decompress_session() in libndi_advanced_ios.a(video_codec_interface.o)
ld: symbol(s) not found for architecture arm64
ドキュメントに記載あり。
The current NDI implementation supports H.264 decoding without any installed plugins
across the Windows and macOS targets.
If you require Linux support, please contact NDI SDK support.
しかし NDIlib_recv_create_v4
(v3も同じ)か NDIlib_recv_destroy
の呼び出しでこのリンクエラーが出るのでそれは無理。
iPhone7/iOS14.6だと非対応だとしたら悲しい

iOSのSenderアプリは動いているっぽいが、MacでFindできない。
最近のiOSはlocal networkを探索する(される?)のにユーザーのパーミッションが必要とかなんとか
ドキュメントにあった。
In iOS 14 and XCode 12, a new setting was introduced to enable support for mDNS and Bonjour. Under “Bonjour Services”, one should assign “Item 0” as being “_ndi._tcp.” In order for NDI discovery operate correctly. It is also required to enable networking in the App sandbox settings.
NDIの話ではないがこちらの記事の1と2をなぞればOK。
2のBonjour services
に書く値は_ndi._tcp.