Lithiumee

Lithiumee

Go wild

Accsoon Cineeyeを掘り下げる

背景#

2019 年、一代致迅影眸图传が発表されました。自媒体が急成長する時代に、カメラのさまざまなアクセサリーも次々と登場し、三軸スタビライザー、映像伝送、マイク… 大小さまざまなメーカーが参入し、多くの粗雑な製品も生まれました。影眸図伝は致迅の第一世代の映像伝送製品であり、小規模な工房の雰囲気が見受けられますが、良い点も多く、デザインは際立っていませんが非常に実用的で、使用体験も非常に良好です:遅延が低く、映像伝送を見ながらフォーカスを合わせることができ、外部電源なしで 3〜4 時間使用できます。発売時の 799 元の価格と、後の 300 元未満の中古価格を考慮すると、今でも実用性を失っていません。

映像伝送の方式として、影眸は Wi-Fi 映像伝送に属し、専用の受信機は装備されていません。カメラなどの HDMI 信号源を映像伝送送信機に接続し、受信にはモバイルデバイスの Wi-Fi で映像伝送に接続し、専用アプリを通じて画像をリモートで確認します。Wi-Fi を採用することは、低価格の映像伝送に適した選択肢であり、一般的な Wi-Fi ネットワークカードは専用の無線方式に比べて開発の難易度とコストが大幅に低くなります。Wi-Fi 以外では、1080P のビデオストリーム伝送を満たす 5Mbps 以上の速度を安価に実現する方法はほとんどありません。低価格の映像伝送にとって、専用の受信機を備えないことは、ほぼ半分のハードウェアコストを節約でき、スマートフォンやタブレットの既存の画面を利用できるため、追加の表示デバイスを購入する必要がなく、購入と使用のハードルが下がり、影眸は個人や小規模チームに非常に適しています。ただし、大型モニターや放送台との接続の機会を失うという代償があります。

影眸を研究する目的は、どのようにして良好な体験を持つ Wi-Fi 映像伝送を実現しているのかを理解することでした。影眸が送信するデータストリームを正しく解析できるようになった後、受信側を「カスタマイズ」し、受信機がないために大型画面やライブ配信に接続できない問題を解決し、全志 D1 に基づく受信機のプロトタイプと OBS Studio プラグイン受信の 2 つの方案を実現しました。研究の過程で、影眸を選ぶことはソフトな柿を選ぶことでもあると気づきました:海思のハードウェアソリューション、Wi-Fi の伝送方式、簡素な初版受信アプリなど、利用できる手段は非常に豊富で、ちょうど学びや練習に適していました。以下はその全過程の記録です。

ハードウェア#

正面のネジを外すと影眸の外装を開けることができ、ハードウェアの構成が見えます。以下は主要なチップと基本情報です:

951A1855

951A1854

  • 主チップ:海思 Hi3516ARBCV100 SoC
  • インターフェースチップ:聯陽 IT6801FN HDMI - BT.1120
  • RAM:海力士 H5TC2G63GFR DDR3L
  • Flash:旺宏 MX25L12835F 16MB SPI Flash
  • ネットワークカード:欧飛信 8121N-UH モジュール、高通 Atheros AR1021X チップ、2x2 802.11 a/n 5G、USB 2.0 インターフェース
  • MCU:意法 STM32F030C8T6

主チップの海思 Hi3516A は、プロセッサが単核 Cortex-A7 で、公式には Linux 3.4 カーネルに基づく SDK を提供しており、H.264/H.265 ビデオハードウェアコーデックを備えています。公式には「新世代 ISP を統合したプロフェッショナル HD IP カメラ SoC」として位置付けられ、監視分野で広く使用されています。また、低コストの映像伝送の本質を明らかにしました —— 監視ソリューションの基盤の上に、画像センサーの入力を HDMI 入力に置き換えることで映像伝送が実現されました。監視ソリューションの出荷量は非常に多く、この SoC は監視に不要な表示などの周辺機器を取り除くことができ、コストを非常に低く抑えることができます。HDMI 入力を SoC 上で広く利用されている MIPI CSI、BT.1120 などのインターフェースに変換する方法はやや特殊ですが、少なくとも既存の IC を選択することができます。類似の考え方の製品にはこのようなHDMI エンコーダがあり、同様に海思のソリューションを利用しています。外部 Wi-Fi ネットワークカードを必要とする Wi-Fi 映像伝送に比べて、これらは SoC 内蔵の GMAC を利用でき、外部にイーサネット PHY チップを接続するだけで有線ネットワーク接続を実現でき、HDMI をキャプチャし、安定してライブストリーミングを行うことができます。

image

影眸のハードウェアソリューションで私が最も驚いたのは、わずか 16MB の Flash です:Linux を実行するデバイスがわずか 16MB のスペースを必要とするとは。しかし冷静に分析すると、多くの OpenWRT を実行するルーターも 16MB、さらには 4MB の Flash しか必要としません。ビデオ処理のスペースに対する要求は主に RAM に依存します。Debian などのディストリビューションの豊富なソフトウェアパッケージを捨て、特定のタスクに特化した Linux を使用すれば、非常に小さなスペースを占有することができます。

ボード環境#

ブート#

海思チップを使用しているため、基本的には公式 SDK に基づいて開発されます。ボード上のシリアルポート R、T、G の 3 つのはんだ付けポイントから線を引き出し、電源を入れると U-Boot と HiLinux のブートログが表示され、やはり純正の海思です。

image

image

U-Boot でprintenvを実行すると、起動カーネルのコマンドとカーネルに渡されるパラメータを取得できます。出力から SPI Flash のレイアウトは 1M(boot)、3M(kernel)、12M(rootfs)で、rootfs は 12MB の jffs2 ファイルシステムであることがわかります。ブートプロセスは、最初に SPI Flash(sf)デバイスを探査(probe)して Flash の情報を取得し、次に Flash からオフセット 0x100000(1MB)で 0x300000(3MB)サイズのカーネルをメモリアドレス 0x82000000 に読み込み、最後にbootmコマンドを使用してメモリからカーネルを起動します。

bootfile="uImage"
bootcmd=sf probe 0;sf read 0x82000000 0x100000 0x300000;bootm 0x82000000
bootargs=mem=128M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1M(boot),3M(kernel),12M(rootfs)

システム起動後#

システムに入った後、ボード上で実行されている映像伝送プログラムをどのように見つけるのでしょうか?海思の開発環境ユーザーガイド文書によると、システム起動後に自動的に実行されるプログラムは/etc/init.d/rcSに追加できます。したがって、/etc/init.d/rcSを開いて確認します。

image

rcSの主な内容は以下の通りです:

まず、カーネルのネットワークバッファを変更し、書き込みバッファを 0x200000(2MB)、読み取りバッファを 0x80000(512KB)に設定します:

#sys conf
sysctl -w net.core.wmem_max=2097152
sysctl -w net.core.wmem_default=2097152
sysctl -w net.core.rmem_max=524288
sysctl -w net.core.rmem_default=524288

無線ネットワークカードドライバをロードします。

insmod /ko/wifi/ath6kl/compat.ko
insmod /ko/wifi/ath6kl/cfg80211.ko
insmod /ko/wifi/ath6kl/ath6kl_usb.ko reg_domain=0x8349

ip/dhcp の設定

ifconfig wlan0 10.0.0.1 netmask 255.255.255.0 up
echo udhcpd
udhcpd /etc/wifi/udhcpd.conf &
#echo hostapd
#hostapd /etc/wifi/hostap.conf &

MPP ドライバをロードし、SDK 文書と一致します。

cd /ko
./load3516a -i -sensor bt1120 -osmem 128 -online

image

MPP をロードする際には主に初期化を行い、多くのカーネルモジュールをロードし、ログは以下のように出力されます。

Hisilicon Media Memory Zone Manager
Module himedia: init ok
hi3516a_base: module license 'Proprietary' taints kernel.
Disabling lock debugging due to kernel taint
load sys.ko for Hi3516A...OK!
load tde.ko ...OK!
load region.ko ....OK!
load vgs.ko for Hi3516A...OK!
ISP Mod init!
load viu.ko for Hi3516A...OK!
load vpss.ko ....OK!
load vou.ko ....OK!
load hifb.ko OK!
load rc.ko for Hi3516A...OK!
load venc.ko for Hi3516A...OK!
load chnl.ko for Hi3516A...OK!
load h264e.ko for Hi3516A...OK!
load h265e.ko for Hi3516A...OK!
load jpege.ko for Hi3516A...OK!
load vda.ko ....OK!
load ive.ko for Hi3516A...OK!
==== Your input Sensor type is bt1120 ====
acodec inited!
insert audio
==== Your input Sensor type is bt1120 ====
mipi_init
init phy power successful!
load hi_mipi driver successful!

その後、RtMonitorという名前のプログラムが実行され、すべての映像伝送ビジネスロジックがその中で実現されます。

image

ボード環境の探索は非常にスムーズで、何の障害もなく、スクリプトにはデバッグ時に残されたコメント情報もありました。実際、海思の SDK 文書には各段階での暗号化手段が提供されており、シリアルポートの無効化や root アカウントのパスワード設定など、いずれかを適用すればかなりのトラブルを引き起こすことになります。

image

伝送#

パケットキャプチャ#

まず、Wi-Fi を通じてパケットをキャプチャして、どのようなデータが伝送されているのかを見てみましょう。ARM アーキテクチャの Mac 上に iOS のアプリをインストールできるため、Accsoon アプリを実行した後、Wireshark を開くとキャプチャを開始できます。3 種類のパケットが見つかります:

  1. 映像伝送→受信端 UDP:データ量が大きく、映像伝送データストリームであると推測されます;
  2. 受信端→映像伝送 UDP:非常に短く、データ応答パケットであると推測されます;
  3. 受信端→映像伝送 TCP:映像伝送インターフェースを開くと送信され、上記の UDP 伝送をトリガーし、その後約 0.5〜1 秒ごとに 1 パケットが送信され、ハートビートの保活であり、内容には "ACCSOON" という文字列があります。

image

ついでにリスニングモードでパケットをキャプチャします。複数のデバイスが接続されていると、Wi-Fi には高速なマルチキャスト / ブロードキャストメカニズムがないため、データを各デバイスに個別に送信する必要があり、信道の圧力が倍増します。

image 1

Wi-Fi 映像伝送のもう一つの欠点は、802.11 プロトコルを遵守し、フレーム間隔(interframe space)やバックオフ(backoff)ランダム数を変更せずに信道競争で不正な優位性を得ることがない場合、この映像伝送は他の Wi-Fi デバイスよりも高い伝送優先度を持たないことです。信道上で他の Wi-Fi デバイスが大量にアクティブな場合、映像伝送のカクつきを避けることはできません。しかし、5GHz 信道の混雑度は一般的に 2.4GHz よりも良好です。

Android APK の逆コンパイル#

パケットキャプチャだけではデータパケットの具体的な内容、特にヘッダーの各フィールドの意味を明確にするのは難しいため、致迅の Android アプリ内のロジックを分析しようとしました。更新されたバージョンは他のデバイスをサポートするためにコードが増えたため、古いバージョンの方が分析に適しています。apkpure から影眸映像伝送をサポートする古いバージョン(Accsoon 1.2.5 Android 版 APK)をダウンロードしました。Jadx を使用して apk を逆コンパイルし、主に以下の内容を探しました:

  • UDP ビデオストリームデータパケットの構成、ビデオストリームを正しく解析するため;
  • TCP 制御命令の内容と送信ロジック、デバイスが送信機能を開始するための正しいトリガーを得るため。

Untitled 7

Java コードの重要なロジックの分析:

  • MediaCodecUtil クラス
    • Android のネイティブコーデックインターフェース MediaCodec の操作をラップしています。

    • コンストラクタ内で MediaCodec を初期化し、初期化時のパラメータから、使用されるデコーダは "video/avc" であり、伝送されるビデオストリームは H.264 エンコードであることがわかります。

    • MediaCodec を初期化する際、MediaCodec.configureメソッドにSurfaceを渡すと、MediaCodecはデコードされたビデオフレームをそのSurfaceBufferQueueに直接出力し、onFrameAvailable()をコールバックします。

    • putDataToInputBufferメソッドは、MediaCodec の入力バッファに対応します。空のバッファを要求し、デコードが必要なデータをコピーしてから、入力バッファキューに入れます。

    • renderOutputBufferメソッドは、MediaCodec の出力バッファに対応します。出力バッファキューからデコードされたデータを取得し、そのバッファを解放します。

image

image

image

  • MediaServerClass クラス
    • Start()メソッドは、MediaRtms.Start()TcpLinkClass.StartMediaStream()を呼び出し、それぞれ UDP と TCP を起動します。H264FrameReceiveHandleはコールバック関数としてMediaRtmsのインスタンス化時に渡されます。H264FrameReceiveHandleが呼び出されると、最終的にMediaCodecUtil内のputDataToInputBufferrenderOutputBufferが呼び出されます。
  • MediaRtms クラス
    • rtmsBaseクラスの簡単なラップです。
    • Start()メソッドは、DatagramSocketを作成し、udpRxThreadスレッドを起動します。このスレッド内で、データを受信し続け、一定の長さのデータを受信した後、パケットヘッダーを解析し、ビデオであればH264FrameReceiveHandleコールバックを呼び出します。
  • TcpLinkClass クラス
    • StartMediaStream()を呼び出すと、KeepAliveThreadスレッドが起動します。このスレッド内で、1 秒ごとにTcpLinkClassクラス内のStaOpというメソッドを呼び出し、TCP 接続、ハートビートパケットの送信、接続の切断のプロセスを実装します。
  • SurfaceRender クラス
    • ビデオはGLSurfaceViewコントロール上に表示されます。VideoMainActivity内で、setRendererメソッドを呼び出し、SurfaceRenderGLSurfaceViewのレンダラーとして設定します。
    • onSurfaceCreatedメソッドでは、OpenGL テクスチャ(mTextureId)にバインドされたSurfaceTexturemSurfaceTexture)を作成し、MediaCodecがデコードしたビデオフレームを受信します。そして、オフスクリーンレンダリングに必要なフレームバッファオブジェクト(FrameBuffer)とテクスチャ(Texture)を作成し、効果処理の準備をします。
    • onDrawFrameメソッドでは、現在のフレームを描画します。updateTexImageメソッドを呼び出して、SurfaceTexture内の最新の画像フレームをバインドされた OpenGL テクスチャに更新します。この時、オフスクリーンレンダリングに切り替え、シェーダープログラムを利用してビデオフレームテクスチャと LUT テクスチャを重ね合わせて 3D LUT を適用し、通常のレンダリングに戻り、オフスクリーンレンダリングから得られたテクスチャを基に、シェーダープログラムを利用してゼブラライン、白黒などの効果を実現し、表示します。中心線、比率フレームなどの重ね合わせ要素は最後に個別に描画されます。

具体的にパケットヘッダーの長さと情報を確認します。

TCP フレーム:

image

image

UDP フレーム:

各メッセージは 1 フレームのコーディングストリームを含み、各メッセージの前にはメッセージヘッダーがあります:

image

各メッセージは複数のフレームに分割されて送信され、各フレームの前にはフレームヘッダーがあります:

image

image

image

H.264 コーディングストリームの抽出#

データパケットの構造がわかったので、解析を開始できます。フレームを分割してメッセージを再構成した後、メッセージの内容は0x000001の固定プレフィックスで始まり、NALU(Network Abstraction Layer Unit)の特徴を持ち、1 バイトの NALU ヘッダーを含み、重要なのはnal_unit_typeで、ペイロードの内容タイプを判断するために使用されます。理論的にはここまで来れば、メッセージの内容を一つずつデコーダに送信すればビデオストリームをデコードできます。しかし、デコーダは SPS と PPS に保存されたプロファイル、レベル、幅、高さ、デブロックフィルターなどのパラメータに依存して正しくデコードする必要があるため、I フレームの前にデコーダに知らせる必要があります。したがって、コード内ではnal_unit_typeに基づいて判断し、SPS と PPS を待つことが最善です。

Untitled 13

NAL ヘッダー:

image

NALU タイプ:

image

受信端設計#

受信方案 1 - コンピュータ受信#

データパケットの構造が明らかになった後、正しくデータパケットを受信し、H.264 コーディングストリームをデコーダに送るだけです。効率的に開発とデバッグを行うために、まずコンピュータ上で行います。FFmpeg(libav)や GStreamer(libgst)などのマルチメディアフレームワークを利用すれば、デコードを簡単に実現できます。まず FFmpeg を使用して、主に以下のプロセスを経る必要があります:

  1. デコーダの初期化avcodec_find_decoder()を使用して H.264 デコーダを検索し、avcodec_alloc_context3()を使用してコンテキストを作成し、avcodec_open2()を使用してデコーダを開きます。
  2. データのデコードav_packet_from_data()を使用してデータをAVPacketに格納し、avcodec_send_packet()を使用してデコーダに送信し、avcodec_receive_frame()を使用してデコードされたデータをAVFrameから取得します。

全体のプログラムの大まかなロジックは次の通りです:

  1. メインスレッド:FFmpeg デコーダと SDL 表示を初期化し、UDP と TCP スレッドを起動します。その後、利用可能なデータの信号を待つループを実行し、データをデコードして表示します。
  2. UDP スレッド:パケットを受信し、各msg_idに対応するすべてのセグメントを収集し、完全な内容を共有メモリに組み合わせ、信号をメインスレッドに通知します。
  3. TCP スレッド:定期的にハートビートパケットを送信します。

映像伝送の Wi-Fi に接続し、ソフトウェアを実行します。映像伝送は RX0 小型カメラに接続し、カメラでスマートフォンのストップウォッチを撮影し、大まかな遅延テストを行います。左側には画面が表示され、スマートフォンの画面表示→RX0 が画面を撮影し HDMI 出力→HDMI 入力映像伝送→コンピュータが無線受信し表示します。エンドツーエンドの遅延は基本的に 200ms 程度です。

3N5A3075

受信方案 2 - 開発ボード#

コンピュータ上で動作するプログラムができたので、これを組み込みハードウェアに移植する希望が出てきました。私は以前、全志 D1 の Mango Pi MQ-Pro D1 を手に入れており、HDMI 出力があり、H.264 ハードウェアデコーダがあり、完全な SDK と文書が開放されており、受信端の制作に必要なほとんどの要件を満たしています。残念ながら、Wi-Fi ネットワークカードは 2.4GHz しかサポートしておらず、5GHz 帯域をサポートする RTL8821CS ネットワークカードに交換し、対応するドライバをコンパイルする必要があります。

image

全志は D1 に Tina Linux SDK を提供しています。Tina の特徴は Linux カーネル + OpenWRT 構築システムに基づいており、AIoT 製品をより軽量にすることができます。OpenWRT のより広く知られた用途は、メモリとストレージが非常に限られたルーターです。宣伝によると、元々1GB DDR + 8GB eMMC が必要だったシステムが、Tina Linux システムを使用することで 64MB DDR + 128MB NAND Flash で済むようになります。

D1 チップには H.264 のハードウェアデコーダがあり、Tina システムは libcedar の OpenMAX インターフェースをサポートしているため、GStreamer はomxh264decプラグインを使用して libcedar を呼び出してビデオハードデコードを行うことができ、さらに Tina はsunxifbsinkプラグインを提供しており、DE を呼び出して YV12→RGB を実現できます。したがって、GStreamer を使用してデコードと表示を行うことが最良の選択肢となりました。この記事に従って SDK を設定し、さまざまなコンパイルの問題を排除した後、上記のプラグインを備えた GStreamer を得て、アプリケーション開発を行うことができました。

image

方案一を行っている際に方案二を考えず FFmpeg を使用しましたが、TCP 制御命令と UDP データ取得部分は再利用できます。GStreamer の核心は、要素(element)が順次パイプライン(pipeline)を構成することです。UDP から取得したフレームデータをパイプラインに送るために、GStreamer のappsrcを使用できます。appsrcは GStreamer パイプラインにデータを送る API を提供します。appsrcには 2 つのモードがあります:プッシュモードとプルモードです。プルモードでは、appsrcはデータが必要なときに指定されたインターフェースを通じてアプリケーションから対応するデータを取得します。プッシュモードでは、アプリケーションがデータをパイプラインにプッシュします。プッシュ方式を採用すれば、UDP 受信スレッド内でデータをappsrcに「送信」することができます。したがって、以下のプロセスでパイプラインを作成します:

  1. 要素の作成

    appsrc = gst_element_factory_make("appsrc", "source");
    parse = gst_element_factory_make("h264parse", "parse");
    decoder = gst_element_factory_make("omxh264dec", "decoder");
    sink = gst_element_factory_make("sunxifbsink", "videosink");
    

    各要素はg_object_set()で属性を設定し、その中でcapsはデータストリームのフォーマットと属性を定義し、要素が正しく処理できるようにし、要素間の交渉を行います。このアプリケーションでは、appsrccapsが最も重要です。そうでなければ、後続の要素は受け取った内容がどのフォーマットであるかを知ることができません。appsrccapsは以下のように設定します:

    GstCaps *caps = gst_caps_new_simple("video/x-h264",
                                        "width", G_TYPE_INT, 1920,
                                        "height", G_TYPE_INT, 1080,
                                        "framerate", GST_TYPE_FRACTION, 30, 1,
                                        "alignment", G_TYPE_STRING, "nal",
                                        "stream-format", G_TYPE_STRING, "byte-stream",
                                        NULL);
    g_object_set(appsrc, "caps", caps, NULL);
    
  2. パイプラインの作成と要素の追加およびリンク

    pipeline = gst_pipeline_new("test-pipeline");
    gst_bin_add_many(GST_BIN(pipeline), appsrc, parse, decoder, sink, NULL);
    gst_element_link_many(appsrc, parse, decoder, sink, NULL);
    

    これにより、appsrc→h264parse→omxh264dec→sunxifbsinkのパイプラインが形成されます。

UDP スレッド内では、引き続きパケットを受信し、各msg_idに対応するすべてのセグメントを収集し、完全な内容をgst_bufferに組み合わせ、g_signal_emit_by_name(appsrc, "push-buffer", gst_buffer, &ret)を通じてバッファgst_bufferappsrcにプッシュします。gst_buffer内には、フレームデータ自体に加えて、dtsptsdurationは重要な時間パラメータとして渡す必要があります。appsrcdo-timestamp属性をTRUEに設定すると、appsrcはバッファを受信した際に自動的にタイムスタンプを設定しますが、duration(持続時間)はフレームレートに基づいて設定する必要があります。設定しない場合、実測で「カクつき感」が生じることがあり、その原因はdurationの設定が欠如しているため、再生速度が不安定になる可能性があります。追加の遅延を引き起こす可能性がありますが、視覚的な体験を保証するためには設定する方が良いです。

完成したコードをコンパイルするために、Makefile を作成し、私たちのコードを OpenWRT のソフトウェアパッケージとして構築 rootfs 時に一緒にコンパイルされるようにします。

image 8

ボード上でソフトウェアを実行し、映像伝送は RX0 小型カメラに接続し、画面のストップウォッチを撮影して粗い遅延テストを行います。具体的なプロセスは左側の画面表示→RX0 が画面を撮影し HDMI 出力→HDMI 入力映像伝送→開発ボードが無線受信し HDMI 出力→HDMI 入力右側のディスプレイ表示です。エンドツーエンドの遅延は基本的に 200〜300ms の間で、低くはありません。良い点は、映像伝送の画面を通じて画面上で再生されるビデオを視覚的に見ることができ、体験は比較的スムーズです。

951A1816

カメラを直接ディスプレイに接続してテストし、プロセスは左側の画面表示→RX0 が画面を撮影し HDMI 出力→HDMI 入力右側のディスプレイ表示で、遅延は基本的に 70ms 程度です。したがって、映像伝送自体の遅延は基本的に 130ms〜230ms の間です。

3N5A3029

この受信端を利用することで、HDMI を介してさまざまなモニターに接続でき、影眸はスマートフォンやタブレットに限定されることなく使用できます。

受信方案 3 - OBS Studio プラグイン#

前の 2 つの受信方案では、影眸を使用する際にコンピュータや HDMI 表示デバイスで監視できますが、低遅延のライブストリーミングのニーズには応えられません。方案一の基礎の上に受信プログラムを少し変更し、localhost の UDP を介して H.264 コーディングストリームを OBS Studio に送信すれば、バッファを有効にするとスムーズですが遅延が大きく、バッファを無効にすると遅延が低いですが、監視時に見られないカクつきが頻繁に発生します。方案二はキャプチャカードを接続して HDMI 出力をキャプチャできますが、開発ボード上でのデコード、出力、キャプチャカードの遅延が増加します。遅延を減らすためには、OBS プラグインを直接開発することがほぼ最良の選択肢です。

OBS Studio はプラグインを通じて機能を拡張することをサポートしていますPlugins — OBS Studio 30.0.0 documentation (obsproject.com)。紹介によると、ソースタイプのプラグインを開発すれば、ビデオソースを OBS に接続できます。OBS Studio のソースクラスプラグイン開発には、同期ビデオソース(Synchronous Video Source)と非同期ビデオソース(Asynchronous Video Source)があります。同期ビデオソースは Image Source のように OBS のレンダリングループと同期し、OBS がビデオソースのレンダリング関数を呼び出してフレームデータを取得します。グラフィック描画やエフェクト処理に適しています。非同期ビデオソースは独立した作業スレッドで実行され、OBS のレンダリングループと非同期で、ビデオソースがフレームデータを OBS にプッシュします。ネットワークストリームやカメラ入力には非同期の方が適しています。

提供されたプラグインテンプレートobs-plugintemplateを基にプロジェクトを立ち上げ、環境を準備し、OBS の既存の image_source プラグインのソースコードを参考にしてロジックを完成させます。行うべき変更は非常に少なく、大部分のコードは方案二のコードを再利用できます。異なる点は、デコードされたフレーム内容を直接表示要素に送ることができず、appsinkを介してデコード後の内容を取得し、obs_source_output_video()を呼び出して OBS Studio に渡す必要があります。

コンパイルが成功した後、buildディレクトリ下の.soファイルを OBS Studio のプラグインディレクトリ(例:/usr/local/lib/obs-plugins/)にコピーし、OBS Studio を起動すればテストを開始できます。同様に遅延テストを行い、具体的なプロセスは左側の画面表示→RX0 が画面を撮影し HDMI 出力→HDMI 入力映像伝送→コンピュータ OBS プラグインが無線受信し表示します。エンドツーエンドの遅延は基本的に 200ms 程度で、映像伝送の画面を通じて画面上で再生されるビデオを視覚的に見ることができ、体験も連続的でスムーズです。

IMG_20241003_224607-Enhanced-NR-1_1

obs-studio プラグインの遅延テスト:左側の画面表示→RX0 が画面を撮影し HDMI 出力→HDMI 入力映像伝送→コンピュータ OBS プラグインが無線受信し表示

同時に 3 つの方案を接続すると、カクつきが増加することが感じられますが、すべてまだ受信可能な遅延を維持しています。

3N5A3116

まとめ#

ある意味で、強力なコーデックと成熟した無線技術の支えにより、リアルタイムビデオ伝送を実現することはそれほど難しくなく、ソフトウェアロジックは非常にシンプルで直接的です。また、海思のハードウェアコーディングチップは監視に広く使用され、5GHz Wi-Fi の普及により、Wi-Fi 無線映像伝送のような製品が非常に低コストで良好なリアルタイムビデオ伝送を実現できるようになりました。さらに、大型ディスプレイデバイスの発展により、ハードルがさらに下がりました。残念ながら、これらの製品の上限は非常に制限されています:Wi-Fi のエコシステムを享受することで、Wi-Fi の混雑を受け入れなければならず、成熟したハードウェアコーデックを享受することで、基本的に変更の自由度を失います。当然、影眸自体は非常に「機能が充実した」製品であり、既定のタスクをうまく完了し、深刻な短所はなく、多くの新製品が登場しても、基本的な映像伝送のニーズを効果的に満たすことができます。致迅はあるライブ配信で影眸の製造過程を紹介し、彼らが早くからユーザーの痛点を捉え、心を込めて完成度の高い製品を作り上げたことは、今でも称賛に値します。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。