メインコンテンツまでスキップ

リポジトリのアーキテクチャと設計

このページは、ライブラリの構造、各コンポーネントの役割、およびモジュールとランタイムの整合性を損なうことなくフレームワークを拡張する方法を理解する必要があるコントリビューターを対象としています。

フレームワークと環境

「Neat」という言葉は、関連性はあるものの、それぞれ異なる2つの問題に対して使用されます。

  • Neat Library: このリポジトリにある C++/Python ライブラリおよびランタイムです。モデルを読み込みます。 パッケージ化、パイプラインの構築、コントラクトの検証、Modalix ハードウェア上での実行、およびパブリック API の公開を行います。
  • Neat SDK / 環境: フレームワークを中心としたコンテナ化された開発ワークフロー。 DevKit Sync、共有ワークスペース、およびエージェントツールなど。

このリポジトリを変更する際は、人間とエージェントの両方をサポートするフレームワークのプロパティを最適化してください。具体的には、明確な API、決定的な動作、構造化された診断、厳格な検証、および安定した公開インターフェースです。

このライブラリの目的は何ですか。

主な利用者

以下のことを実現したい開発者:

  • 再利用可能な構成要素からパイプラインを組み立てます(生のGStreamerのテンプレートコードを記述する必要はありません)。
  • パイプラインを早期に検証し(CIに対応)、問題発生時に迅速に原因を特定できるようにする。
  • C++でappsinkを使用して、パイプラインを実行し、フレームを処理します。
  • オプションとして、RTSP(gst-rtsp-server を介して)を通じてパイプラインを配信できます。
  • テンソル処理に適した形式で出力することで、機械学習コードをパイプライン処理し、GStreamer の複雑な設定を記述することなく、機械学習モデルにデータを供給します。

パッケージの所有権

選択されたコア・アーティファクトは、Neat、LLiMa、および一緒にインストールされた Internals Debian パッケージの信頼できる情報源です。コアは、そのアーティファクトの完全性を消費し、依存関係のバージョンを選択または書き換えることなく、それを転送します。アーティファクト外のパッケージは、プラットフォームによって管理されます。互換性のないプラットフォームは、コアまたは LLiMa によって修復されるのではなく、更新する必要があります。

一般的なワークフロー

  • デコード/取り込み: ファイルまたは RTSP → デペイロード/デマルチプレックス/解析 → デコード → 変換/キャプチャ → アプリシンク → C++ コンシューマー
  • 検証: ビルド、解析、およびプレロール(一時停止)を実行し、早期にネゴシエーションの問題を検出します。
  • RTSPストリームの送信: appsrc を使用して、合成フレームをRTSPサーバーのパイプラインにプッシュします。
  • 画像/動画テンソルアダプター: 画像/動画/RTSP -> デコード -> 変換/スケーリング -> add_output_tensor(...) -> Run::pull_tensors()
  • チュートリアル: 実行可能で、段階的に学習を進められるように構成されたチュートリアルは、チュートリアル から始めてください。

標準的なプロダクションパイプライン(信頼できる情報源)

このリポジトリにおける標準的な「本番環境の処理フロー」は次のとおりです。 入力 → 前処理 → MLA → 後処理。 正確な情報源は次の場所にあります。 tests/e2e_pipelines/obj_detection/sync_yolov8_test.cpp.

このテストが変更された場合は、READMEとアーキテクチャを更新して、ドキュメントの一貫性を保ってください。

メンタルモデル(ビジネスロジックとパイプラインの連携)

お客様のアプリケーションはビジネスロジックを保持し、フレームワークがパイプラインを構成する役割を担います。

Business logic
|
v
Nodes/Graph fragments -> GStreamer fragments -> caps negotiation -> runtime (Run)
| |
+-----------------------------------------------------------+
Sample / Tensor

主要な概念

このフレームワークは、意図的に少数の概念を中心に構成されています。ほとんどのユーザーコードが扱うのは、ModelGraphRunTensorSample だけです。低レベルの作業を行うコントリビューターは、Node、再利用可能なグラフフラグメント、MPK コントラクトの解析、グラフ内部も扱います。

コンセプト役割
モデルアーカイブMPK推論コントラクト、プラグイン専用の設定ファイル、モデルのバイナリファイル、およびカーネルのアーティファクトを含む、密封された.tar.gz形式のアーティファクト。
Model.tar.gz モデルアーカイブ用のパブリックローダーです。MPKコントラクトを解析し、経路計画を実行し、モデルの各段階を公開し、シンプルな run(...) / Graph 構成のエントリーポイントを提供します。
Tensorデータ型、形状、レイアウト、ストレージ、デバイス、およびセマンティックメタデータとともに型指定された数値ペイロード。
Sampleテンソル、テンソルのリスト、またはバンドルを囲むランタイム/メディアの範囲。フィールドを読み取る前に、Sample::kind を確認してください。
Node決定的な結果を出力するアトミックパイプラインステージ GStreamer フラグメントと所有する要素の名前。
再利用可能なグラフフラグメントデコード済み RTSP 入力やモデルステージなど、複数のノードへ展開される構築済みの Graph
Graphアセンブリと検証の境界。ノード、モデル、再利用可能なグラフフラグメントを、ネゴシエーション済みでビルド可能なパイプラインにします。
RunGraph::build(...) によって返される、アクティブなパイプラインのハンドル。このハンドルは、データのプッシュ、プル、およびランタイムのライフサイクルを管理します。
グラフ1 つのパイプライン内で DAG(有向非巡回グラフ)を構成するには、ビルダーグラフを使用します。複数のパイプラインにまたがるステージや実行を調整するには、ランタイムグラフを使用します。

左から右へ関係性を読み取ってください。

model archive on disk -> Model -> Graph fragments/Nodes -> Graph -> Run
|
v
Tensor/Sample flow

Model は、初心者向けの最初のステップですが、独立した実行エンジンではありません。これは、Graph に追加できるモデルのグラフ断片/ノードを解決します。Graph は、中心となる組み立ての概念です。Run は、構築後のライブオブジェクトです。

コントリビューター向けの設計原則

これらは、フレームワークの基盤となる耐荷重構造の原則です。実装方法を決定する際に、これらの原則を参考にしてください。

  • 決定性こそが重要です。 要素名、生成されたパイプライン文字列、シリアライズされたパイプラインデータを保持してください。 レポートの項目と、再現可能なテストを記載します。診断とエージェントのループは、安定した識別子に依存します。
  • デバッグのしやすさが最優先事項です。 障害が発生した場合は、文字列だけでなく、構造化されたデータを出力するようにしてください。 GraphReport.error_coderepro_note、バスメッセージ、および再現可能なバックエンドパイプライン。
  • 無音での代替処理は行わないでください。 モデルへの入力に関するバグや、ハードウェアまたはランタイムの障害を、音を立てずに隠蔽しないでください。 フォーマットの変換、グラフの種類変更、CPUへのフォールバック、またはプラグインのエラーの処理など。
  • 実行前に検証する。 ランタイム前に、構造、大文字・小文字、形状、および契約に関する検証を優先する。 スレッドが開始されるか、ハードウェアリソースが割り当てられます。
  • MPK契約は、信頼できる情報源のモデルです。 コアルーティング、データ型、形状、量子化など。 ステージごとの決定は、mpk.json/*_mpk.json から行われる必要があります。ステージごとの JSON ファイルは、プラグイン専用です。
  • Detessの論理的なランクとランタイムジオメトリは別個です。 コアは、MPKによって作成されたものを保持します。 frame_shape は、論理的な出力契約として機能し、必要に応じて明示的な MLA ジオメトリを導き出します。ランク 2 の形状は、宣言されたバイト範囲が 1 つの明確な解釈を特定する場合にのみ、NC または HW として受け入れられます。曖昧または矛盾した契約は、モデルのロード中にエラーとなります。
  • 公開 API は安定性を維持します。 include/* に含まれる公開ヘッダーがインストールされ、サポートされます。 既存のインターフェースを破壊する変更よりも、段階的な変更や非推奨化のプロセスを優先する。
  • 並行処理は、範囲を限定し、監視可能でなければなりません。 ストリーミング処理を行うスレッドは、軽量であるべきです。 プローブ側の診断処理には、アトミック演算またはそれに相当するスレッドセーフな処理が必要です。また、終了処理中にプログラムが停止してはいけません。

モデルの実行パス

モデルを基盤とするパイプラインの場合、大まかな手順は次のとおりです。

input Sample/Tensor
-> optional preprocessing / format normalization
-> MLA inference stages selected from MPK contract
-> optional postprocessing / box decode
-> output Sample/Tensor

ユーザーから見てわかるModelの仕様は、MLAハードウェアの仕様よりも、より使いやすいように意図的に設計されています。MLAはINT8/BF16やテッセレーションされたレイアウトを必要とする場合がありますが、ユーザーコードは通常、FP32と通常のテンソルのレイアウトで動作します。フレームワークは、マニフェスト駆動のアダプターステージを使用して、このギャップを埋めます。

前処理と後処理は、フレームワークの明示的なステージ/オプションです。フォーマットの不一致、必要な前処理メタデータの欠落、利用できないMLAディスパッチャー、無効なモデルアーカイブまたはMPKコントラクト、またはキャップネゴシエーションの失敗は、隠れたランタイムでの修正ではなく、対処可能な構造化されたエラーとして表示されるべきです。

リポジトリの構成

上位構造

  • include/ - パブリックヘッダー(サポートされているAPIの範囲)
  • src/ - 実装
  • docs/ -- ドキュメント(このファイル)
  • examples/ -- 実行可能な簡単なサンプルコード
  • tests/ -- ユニットテスト/統合テスト
  • python/pyneat パッケージのソースコード、nanobind バインディング、および Python テスト。
  • old_* - 過去のモノリシックな実装のスナップショット。参照や移行のために保存。

パブリックヘッダーツリー (include/)

パブリックなヘッダーファイルは、include/<module>/... ディレクトリに格納されます。 例:include/pipeline/Graph.hinclude/model/Model.h

パブリックな利便性エントリーヘッダー:

  • include/neat.h(傘)
  • include/neat/runtime.h
  • include/neat/models.h
  • include/neat/nodes.h
  • include/neat/node_groups.h

意図的に、公開されている包括的なヘッダーファイル(include/neat/graph.h)は存在しません。より低レベルのグラフ構造を必要とするランタイム/コンパイラテストでは、直接、限定的なヘッダーファイル(include/graph/...)を使用します。アプリケーション、サンプル、および公開ドキュメントでは、<neat.h>から提供される単一の公開グラフクラス(simaai::neat::Graph)を使用する必要があります。

内部ヘッダーとランタイムプラグインのパス

include/ ディレクトリにあるパブリックヘッダーはインストールされ、安定した API として扱われます。 src/**/internal ディレクトリにある内部ヘッダーはインストールされません。サンプルやチュートリアルでは、パブリック API のみを使用する必要があります。

ランタイム環境に関する注意事項:

  • deps/gst-plugins に同梱されている GStreamer プラグインを使用する場合は、以下のように設定してください。 そのディレクトリを含めるために、GST_PLUGIN_PATHおよび/またはGST_PLUGIN_PATH_1_0を指定してください。
  • cmake --install を使用してインストールした場合、プラグインは次の場所に配置されます。 ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/sima-neat/gst-plugins。 そのパスを、GST_PLUGIN_PATHおよび/またはGST_PLUGIN_PATH_1_0に追加してください。
  • 現在のシェルで使用するプラグインのパスを設定するには、scripts/use_neatdecoder.sh を使用してください。
  • プラグインをシステム全体にインストールする場合は、システム全体の GStreamer キャッシュを再構築してください。

計画段階と安定版(APIのインターフェース)

エリア/API状況備考
主要なパイプライン API(GraphRunTensorSample安定した主にサポートされている C++ のインターフェース。
ビルダーの内部構造(Node、プライベートなノードベクターヘルパー、GraphPrinter)。内部STL形式のみに対応し、GStreamerによる合成処理を事前に行うことができます。
モデル API(Model、再利用可能なグラフフラグメント)安定標準モデルアーカイブ統合パス。
include/policy/*安定した検証済みの最小限のポリシー契約とデフォルト設定(DecoderEncoderMemoryRTSP)。
include/nodes/groups/ImageToH264RtspGroup.h計画された空のプレースホルダーグループ。
Python用バインディング (python/pyneat)ベータ版Nanobind をベースとしたバインディングとパッケージは、リポジトリ内に配置されています。API の主な機能は、TensorGraph/RunModel、および主要なノード/グループヘルパーです。

モジュールと役割

builder/:ノード間の契約と、プライベートな線形合成のサポート(GStreamerは使用しません)。

目的: パイプラインが論理的な構成要素からどのように組み立てられるかを定義します。

主な種類:

  • Node - 各パイプラインの構成要素で実装されるインターフェース
  • ノードベクトルを扱うための内部関数と、GraphPrinter -- グラフの表示や診断を行うためのユーティリティ

ルール: ビルダーは、基本的に STL のみを使用するようにしてください。GStreamer ランタイムオブジェクトを所有してはなりません。

nodes/ - 型付きのパイプライン構築モジュール

目的: 決定的なGStreamerフラグメントを出力する、すぐに使用できるノードの実装を提供します。

例:

  • nodes/io/HttpSource, nodes/io/RTSPInput, nodes/io/StillImageInput
  • nodes/common/*(キャプチャ、キュー、出力など)
  • nodes/sima/*(SiMa.ai:デコード/エンコード/解析/決済ノード)
  • nodes/rtp/*(ペイロード処理関連のヘルパー関数)
  • nodes/groups/*(一般的な複数ノードのレシピ)

契約: 各ノードは、以下のものを生成しなければなりません。

  • backend_fragment(index) - 指定されたインデックスにおける、このノードの GStreamer フラグメント。
  • element_names(index) - このノードが所有する、決定的な要素名(診断および強制に使用)。

gst/ -- 軽量な GStreamer ユーティリティ

目的: よく使用される GStreamer のパターンを扱うための、小さなラッパー/ヘルパー関数。

例:

  • 初期化 (GstInit)
  • 解析起動文字列 (GstParseLaunch)
  • バスのデータ抽出/文字列化 (GstBusWatch)
  • Capsヘルパー / 要素の内部構造の調査 (GstHelpers, GstIntrospection)
  • パッドタップ/プローブヘルパー (GstPadTap)

ルール: gst/ は、pipeline/ に依存してはならない(依存関係の循環や「ユーティリティ層」の肥大化を防ぐため)。

pipeline/ - ランタイムのオーケストレーションと公開 API

目的: ランタイムのライフサイクル全体を管理する:ビルド → 解析 → 実行 → 処理 → 終了、および診断機能の実装。

主要な型:

  • Graph - ユーザーの主なアクセスポイント
  • Run - パイプラインの実行処理を、プッシュ/プル API を使用して管理します。
  • Sample - プル操作によって返される構造化された出力ペイロード
  • GraphReport - 障害、停止、および再現に関する構造化された診断情報
  • Errors - レポートを埋め込む例外 (NeatError)

エラーのセマンティクスに関する契約

GraphReport.error_code は、機械によるトリアージの標準的なフィールドです。フレームワークのランタイム/ビルド/IO パスは、ターミナルでのエラーを安定したコードファミリーにマッピングします。

  • misconfig.pipeline_shape
  • misconfig.caps
  • misconfig.input_shape
  • misconfig.input_capacity
  • misconfig.media_caps
  • misconfig.tensor_dtype_missing
  • misconfig.option_out_of_range
  • build.parse_launch
  • build.pipeline_syntax
  • build.plugin_missing
  • build.property_invalid
  • runtime.pull
  • runtime.element_failed
  • runtime.output_timeout
  • io.parse
  • io.open
  • io.file_not_found
  • io.permission_denied
  • io.rtsp_connection_failed
  • io.camera_not_found
  • codec.*resource.*infra.*、およびinternal.*

GStreamerのエラーは、1つの内部パーサー、分類器、およびレンダラーを通過します。 分類では、バージョン管理されたNeatの診断IDが優先され、次にネイティブのGStreamerドメイン/コードと要素ファクトリ、そして古いプラグインに対するより限定的な互換性マッピングが使用されます。不明なエラーが発生した場合、runtime.element_failedが使用されます。これは、実際にネゴシエーションが失敗した場合を除き、misconfig.media_capsとして報告されません。パイプラインで複数のエラーが発生した場合、最も具体的な根本原因がレンダリングされ、すべてのエラーがバスログに保持されます。

GraphReport.repro_noteは、人間が理解しやすい要約です。本番レンダリングには、平易な言葉で記述された原因、関連する観測/期待される値、具体的なユーザーアクション、および安定した診断IDが含まれます。生のプラグインストリング、ソースの場所、およびGStreamerドメイン/コードは、デバッグ専用です。括弧で囲まれた公開コードは、NeatErrorが構築されたときに1回追加されます。 GraphReport.busは、プラグイン/ランタイムエラーの詳細に関する信頼できる情報源です。 ビルド(入力)フローの場合、GraphReport.build_adaptationは、解決された形状ポリシー/機能、シード/最大値の起源、バイトガードの起源、および適用/スキップされた適応アクションを記録します。 例外をスローしないランタイムプルの場合、PullError.codeは同じ分類を使用します。入力ストリームワーカーのエラーは、型付きエラーコードを保持し、ワーカーthreadの境界を越えて報告されるため、Run::pull()とPython例外トランスレーターは、同じNeatErrorを伝達します。

サポートの優先順位は次のとおりです。

  1. バケット形式でerror_code
  2. repro_note を読んでください。
  3. まず最初のターミナルを検査します。 bus エラー
  4. repro_gst_launch を使って再生する

内部パイプライン診断

src/pipeline/internal/(社内のみ):

  • Diagnostics.h - ランタイムで使用される、共通の診断情報型:
    • DiagCtx(バスログ+ノードレポート+境界/要素カウンタ)
    • BoundaryFlowCounters(ストリーミングスレッドから更新されるアトミックカウンター)
    • ElementTimingCounters(各要素ごとのアトミックな計算時間計測)
    • ElementFlowCounters(各要素ごとのアトミックなフロー統計)
  • GstDiagnosticsUtil.h -- フォーマットおよび収集を行うためのユーティリティ関数。GStreamer の診断情報を扱います。

SIMAの静的マニフェストコンテキスト契約

モデルのパイプラインの場合、静的なステージ/テンソルの契約データはフレームワークに組み込まれ、パイプラインレベルの GstContext として注入されます。

  • コンテキストの種類:sima.model.manifest.v1
  • コンテキストフィールド:
    • manifest_version
    • manifest_json(旧バージョンの互換性を維持するためのデータ)
    • manifest_accessor_v1(ABI互換アクセサーテーブルへのポインタ)
    • オプションの session_idmodel_id
  • マニフェストによる所有権/有効期間は、パイプラインの有効期間に紐付けられています。プラグインはポインタを借用し、その内容をコピーします。 彼らが求めるものは。
  • リポジトリの境界:このリポジトリには、プラグイン/ディスパッチャーのリポジトリへのビルド時の依存関係を追加してはなりません。 統合はインターフェースのみを対象とします(ランタイム GstContext、プロパティ、caps/メタデータ、およびC-ABIコントラクト)。

移行されたフィールドに対するリゾルバーの優先順位は、決定論的です。

  1. 契約またはランタイムのシグナル(形状/メタデータ/機能)から推測する。
  2. コンテキスト/デフォルト/プロパティ パス
  3. ハードバスエラー(プログラムは停止せず、SIGSEGVシグナルは発生しない)

StageTransformRuleRegistry(内部)は、リゾルバーがどの非MLAステージがMLA入力からテンソルコントラクトを継承し、MLA出力からテンソルコントラクトを継承するか、また、出力量子化がいつ伝播されるかを指示する、単一のマッピングテーブルです。これにより、前処理/後処理の処理が明確になり、テスト可能になります。

集約テンプレートを使用する移行されたSIMAプラグインの場合、ランタイム構成は、コンテキスト/プロパティ駆動のリゾリューションに従います。

  1. ステージの静的フィールドは、マニフェストのコンテキストから取得されます。
  2. ランタイムの調整パラメータは、プロパティやコンテキストのデフォルト値から取得されます。
  3. 未解決の必須フィールドがあると、明示的にエラーが発生します(フレームワークにはステージJSONによるフォールバック機能がありません)。

simaaiprocesscvuの場合、CMから派生した配線は、まず推論を行い、次にコンテキストsink_pad_tensor_index_mapを使用して、決定的な多入力マッピングを行います。従来の入力バッファー名は、フォールバック専用として残ります。

logical_stage_idは、提供された場合、stage-id/stage_idパイプラインのプロパティから解決されます。そうでない場合は、要素名にフォールバックします。SIMAモデルパスのフラグメントビルダーは、デフォルトでstage-idsimaaiprocesscvusimaaiprocessmla、およびsimaaiboxdecode要素に設定します。

YOLO26のBoxDecodeクラスにおけるクラス数の制約

モデルによって管理される YOLO26 の検出、ポーズ推定、セグメンテーションの処理において、MPK クラスヘッドの深さが、クラス数の決定的な値となります。Model::Options::num_classes = 0 は、その推測された値を選択します。正の値は、この値と一致する必要があります。一致しない場合、契約の構築時にエラーが発生し、設定された値、MPK から導出された値、およびデコードタイプが報告されます。これにより、無効なクラス数が、グループ化された生のヘッドレイアウトの解釈に使用されることが防止されます。SSD および YOLO26 以前のポーズ推定を行わない YOLO ファミリーは、既存の明示的なオーバーライド動作を維持し、ポーズ推定および SuperPoint デコーダーは、それぞれのファミリー固有のルールを維持します。

SuperPoint BoxDecodeコントラクト

SuperPointは、他のモデル管理型のBoxDecodeファミリーと同様に、MPKから静的マニフェストへの境界を使用しますが、以下の追加の不変条件があります。

  • MPKレコードは、検出器のロジットと記述子グリッドのテンソル識別子、およびストレージを所有します。 表現、dtype/形状に関する情報、数値プロファイル、およびオプションの明示的なNMS(非最大抑制)と境界制御。コアは、これらの役割をテンソルの値から識別することはありません。
  • Coreは、各ロールに正確に1つのテンソルを割り当て、プロファイルフィンガープリントとサポートされているものを検証します。 表現、明示的なModel::Options::superpointによる上書きの適用、および省略されたプロファイル設定のデフォルトのみの解決を行います。プロファイルを変更すると、その派生したデフォルトが再計算され、MPKまたはAPIによって明示的に作成された設定は維持されます。
  • バージョン管理された静的マニフェスト ABI は、解決されたコントラクトを simaaiboxdecode に伝達します。プラグイン マニフェストへのポインタは、設定時のみ借用し、ランタイムに必要な状態はすべてコピーする必要があります。 コアは、パイプラインのライフサイクル全体にわたってマニフェストの所有権を保持します。
  • 生成された出力は、FEATURE_POINTS_V1 ワイヤー形式を使用し、特徴に関する意味的なメタデータを格納します。 FEATURE_POINTS_LEGACY_A65_V0 は、互換性のために明示的に選択した場合にのみ利用可能です。 ユーザーは、バッファーのサイズからどちらの形式であるかを推測してはなりません。

contracts/ -- 検証ルール

目的: 「gst_parse_launch が成功した」というだけでなく、「有効なパイプラインがどのようなものか」を明確に定義する。

例:

  • バリデーターのインターフェースとレジストリ
  • 構造化されたValidationReport

このレイヤーは、CI(継続的インテグレーション)に使用したり、ランタイム前に問題を検出するために使用したりできます。

policy/ -- ユーザーが調整可能な動作

目的: チューニング可能なパラメータ(デフォルト値、メモリ制限、エンコーダー/デコーダー/RTSPポリシーの選択肢など)を一元管理する。

目標は、「調整可能な設定」を明示的かつ容易にアクセスできるようにし、コードのあちこちに隠された状態にしないようにすることである。


モデルアーカイブとの統合

目的: Model.tar.gz モデルアーカイブを読み込み、解析した MPK 推論コントラクトをルーティング可能なグラフフラグメントへ変換します。

セキュアなアーカイブローダーは、内部実装の詳細です。アプリケーションコードは、Model を構築し、model.graph() またはステージ固有の断片を構成する必要があります。

一般的な使用例:

simaai::neat::Model model("resnet_50.tar.gz");
simaai::neat::Graph graph;
graph.add(model.graph());

モデルのステージフラグメント

目的: Model によって公開される、前処理、推論、後処理、または完全な処理フローを、内部のアーカイブローダーを公開せずに構成します。

主要な API:

  • Model::preprocess()
  • Model::inference()
  • Model::postprocess()
  • Model::graph()

これは、前処理を一度だけ行い、MLA/BoxDecodeを別のグラフまたはスレッドで実行するハイブリッドフローで使用されます。

どの処理がどのユニット(CPU/CVU/MLA)で実行されるか

プロセッサのルーティングは、MPKコントラクト(モデルアーカイブで定義されているCVU/MLAステージ)と、オプションのランタイムによるオーバーライドによって決定されます。

  • Model::Options は、前処理、後処理、命名、およびバッファリングに関する設定を制御します。
  • SIMA_MLA_NEXT_CPU は、特定の構成において、MLA の次の段階を上書きすることができます。
  • パイプラインのノード自体は宣言的であり、実際の実行は次の段階で行われます。 GStreamer のプラグインとそれらの設定。

実用的な影響:より多くのバッファーと明示的なルーティングを使用することで、スループットを向上させることができます。一方、Caps の不一致や、バッファーのサイズが不十分な場合、ネゴシエーション中にすぐにエラーが発生します。

ランタイムモデル(プログラムの実行方法)

初期化

すべてのランタイムのエントリーポイントは、単一の安全な初期化ルーチンを呼び出します。

  • gst_init_once()(スレッドセーフ、std::call_once

さらに、ランタイムパスは、必要なプラグインがインストールされているかどうかを確認することができます。

  • require_element("appsink", ...)など。

パイプラインの構築

Graph は、Node オブジェクトと再利用可能なグラフフラグメントを追加して構築します。RTSP ではコーデック対応フラグメントを使用し、デコード前にソースをデパケット化して解析します。

simaai::neat::nodes::groups::RtspDecodedInputOptions source;
source.url = "rtsp://example/live";
source.codec = simaai::neat::nodes::groups::RtspCodec::H265;
source.source_fps = 30;

simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::groups::RtspDecodedInput(source));
graph.add(simaai::neat::nodes::Output());

社内では:

  1. グラフは、論理的な構成の各頂点に対して、1つのノードオブジェクトのみを強制します。connect() の繰り返し呼び出し。 そのインデックス化された頂点を、ファンアウト処理で再利用できます。

  2. コンポジションの変更は、まとめて適用されるか、完全にロールバックされます。

  3. グラフは、各ノードに対してbackend_fragment(i)を要求し、その結果得られたフラグメントを!で連結します。

  4. オプションとして、ノード間に境界マーカーを挿入します。

    • identity name=sima_b<i> silent=true
  5. これは、正確なname=バインディングを分析し、GStreamerを使用して一度解析を行い、構築されたものを一覧化します。 オブジェクトツリー。重複または欠落した名前があると、後続の構成処理が失敗します。

  6. これは、DiagCtx を構築します。

    • 再現性を確保するためのnode_reports
    • boundaries を、BoundaryFlowCounters(アトミック変数)として。

プッシュ/プル ランタイムモデル

Run は、入力/出力キューと入力スレッドを所有します。

  • push(...) は、入力データをキューに追加します(RunOptions::overflow_policy に基づいて、キューがいっぱいになった場合に、処理をブロックするか、入力を破棄するかを決定します)。
  • pull(...) は、appsink からの Sample 出力をキューから取り出します。
  • try_push(...) はノンブロッキング処理であり(キューが一杯の場合は false を返します)。

これは、完全に非同期のパイプライン(プロデューサー/コンシューマー分割)と、 一度限りのフローの両方をサポートします。Graph::run(...)).

デコーダーの承認ライフサイクル

単一のパイプラインまたは接続されたグラフのランタイムを選択する前に、Coreは、コンパイルされた実行計画をスキャンして、型付きのH.264/H.265 SimaDecode ノードを検索します。 資格のあるすべてのデコーダーは、1つのグループとして許可され、その結果として得られる予約は、そのパイプラインのワーカーが停止するまで、最上位レベルのRunによって管理されます。 これは、線形Graph::add(...) パイプライン、通常の接続されたセグメント、および統合されたリアルタイムブランチに等しく適用されます。

許可には、既知のデコーダーの幅、高さ、およびフレームレートが必要です。 Coreはフレームレートを推測することはありません。 不完全な契約または利用できないオプションの許可エンドポイントは、警告を生成し、計画を変更しません。 SIMA_DECODER_ADMISSION_REQUIRE=1 の場合、どちらかの条件が満たされないと、デコーダーハードウェアが開始される前に処理が失敗します。 容量の拒否と不正なリース応答は、常に失敗します。

リアルタイムでのファンイン数の削減

アプリケーションは、通常の Graph::connect(...) を使用してリアルタイムのエッジを記述し、通常の Graph::build(...) を使用してそれらを具現化します。GraphLinkOptions は、ストリームごとの最新ポリシー、ストリームID、予約されたキューの深さフィールド、およびオプションの生のフレーム許容制限を伝達します。ストリームごとの最新ポリシーは、常にストリームごとに1つの保留中のサンプルを保持します。

実行グラフコンパイラ(アプリケーションではなく)が、ライブのマルチソースファンインを1つの GStreamer パイプラインに統合できるかどうかを決定します。対象となるプライベートで入力のないソースブランチは、ストリームごとの多重化およびコンシューマとともに、デコードされたデバイスバッファが appsink/appsrc の境界を越えないように、統合されます。対象とならないストリームごとの最新のトポロジーは、セグメントされたままになります。すでに統合されたネストされたソースセグメントは、そのブランチが再帰的に保持できるまで、対象とならないままになります。

内部境界タイミング

1つの論理的なGraphは、複数のGStreamerパイプラインセグメントに分割できます。コアは、それらの間の各内部境界にappsrcを挿入します。

挿入された境界は、渡されたタイムラインを伝送し、タイムスタンプを生成することはありません。タイムスタンプを生成するのは、公開され、アプリケーションが所有するInputのみです。

appsrcは、自身のセグメントの実行時間からタイムスタンプを生成するため、タイムスタンプを生成する境界は、ファンアウトの各部分に異なるクロックを与えます。これにより、同じフレームを記述するモデル出力メタデータとの間で、Video RTPの整合性が失われ、どのアプリケーションもそれを修正できません。分割処理では、アプリケーションによって宣言されたInputノードが消費されるため、アプリケーションによって設定されたInputOptionsは、挿入された境界に到達することはありません。

セグメントの具現化パスを追加する場合:

  • injected_boundary_input_options(...) を使用して、注入されたオプションを構築します。 これは、この不変量の唯一の定義場所です。
  • is_live = true の状態を維持してください。これをクリアすると、ライブセグメントの処理が停止します。
  • 公開されているInputOptions::do_timestampのデフォルト設定は変更しないでください。 PTS(プレゼンテーション・タイムスタンプ)を持たないcv::Matであっても、入力時に1つ受信します。

境界を越える際に、保持されているGstBufferはゼロコピーで転送されるため、すでに存在するタイムスタンプはそのまま維持されます。タイムスタンプの作成を拒否しても、それを削除することはできません。

入力契約の専門化

いくつかの複合パイプラインノードは、複数の安全なバックエンド表現を持つ。 グラフコンパイラは、静的に確立されたOutputSpecからそれらのノードを特殊化する。これにより、パブリックグラフが変更されたり、最初のランタイムサンプルから永続的なトポロジーが推測されることはない。DerivedまたはAuthoritativeコントラクトは、最適化された表現を選択できる。Hint、不明なフォーマット/メモリ、または不足しているバックエンド機能は、保守的な表現を選択する。

たとえば、生のVideoSenderは、システムまたはSiMaAIメモリ内の安定したNV12コントラクトの場合、およびneatencoderが読み取り専用のinput-layout-aware=true機能をアドバタイズする場合にのみ、NV12変換を省略する。OutputSpecは現在、プレーンストライドとオフセットを伝達しないため、その機能ゲートをバイパスするメモリドメインは存在しない。存在しない、またはfalseの機能は、サポートされていないものとして扱われるため、Coreは古い内部パッケージを使用しても安全である。

生のビデオのジオメトリと物理的なストレージレイアウトは、引き続き個別のコントラクトとして扱われる。OutputSpecとcapsは、表示される幅と高さを記述する。Coreは、これらの値をコーデックブロック、DMAピッチ、またはサーフェス高さのアラインメントに丸めてはならない。レイアウトを認識するプラグインは、GstVideoMetaまたはGstVideoInfoから物理プレーンオフセットとストライドを派生させ、物理コントラクトが互換性がない場合は再パッケージ化し、コーデック/ハードウェアの承認はエンコーダサービスに委ねる。これにより、正確なデコードされたジオメトリが保持され、デバイス固有のアラインメントがパブリックグラフAPIから分離される。

解析と起動

この図書館では主に以下のものを使用しています。

  • gst_parse_launch(pipeline_string, &err)

これにより、柔軟性とデバッグの容易性が向上します(正確な文字列をgst-launch-1.0で再実行できます)。

実行中

一般的な処理の流れ(Graph::build() / Run):

  1. 契約を履行させる(例:build() + プルリクエストに対して、「最後にマージする」というルールを適用する)。
  2. パイプライン文字列を構築します(オプションで境界を追加できます)。
  3. 解析パイプライン
  4. 必要に応じて、要素の命名規則を強制する。
  5. オプションの境界プローブを取り付けてください。
  6. パイプラインをPLAYINGに設定します。
  7. を返す Run 押し引き操作用のハンドル

フレームの寿命(平易な言葉で)

  1. 構築: ノードが、決定的な gst-launch 文字列に変換されます。
  2. ネゴシエート: GStreamer は、要素間で caps(フォーマット、サイズ、メモリ)を調整します。
  3. 実行: 入力データがパイプラインに投入される(または、ソースからパイプラインに引き込まれる)。
  4. サンプル: Appsink は、Sample / Tensor をあなたのコードに返します。
  5. エラー: 交渉の失敗やランタイムの障害が発生した場合、NeatError が発生し、GraphReport が生成されます。

Capsネゴシエーションは自動的に行われ、エラーが発生した場合は、検証/プリロール段階の早い段階で、またはランタイム中に診断情報とともに再現可能になります(describe_backend() + レポート)。

カメラの割り当て権限

CameraInput は、カメラのキャプチャ機能の直後に、そしてライブキューの前に neatcamerabridge を配置します。ネゴシエーション中に、ブリッジは標準プールで上流の GST_QUERY_ALLOCATION に応答し、GstVideoMeta を要求します。プールは、1つのパックされた SiMaAI アロケーションから検証済みのプレーンを割り当て、各プレーンに対して1つの DMA-BUF をエクスポートします。互換性のある libcamerasrc は、これらの DMA-BUF を ISP キャプチャキューにインポートします。次に、ブリッジは同じパックされたアロケーションをアンラップして、下流の処理に使用します。厳密モードでは、その条件を満たさないバッファーはすべて拒否されます。CPU コピーは、明示的な互換性のあるフォールバックとして残ります。

アプリケーション向けのキャプチャ深度は、カーネルのプライベートな CSI-to-ISP RAW トランジットリングと、後続の GStreamer キューの両方とは独立しています。オプションの capture_buffer_count 引数は、CameraInputWithCaptureBuffers に渡され、ISP 出力、libcamera、およびアプリケーション間で保持されるバッファーを制御します。queue_depthleaky_queue は、それぞれ下流の遅延とフレームドロップポリシーを個別に制御します。オプションの互換性コピープールは、必要に応じて拡張され、そのキュー深度によって制限されないため、リーキーキューは、上流のブリッジが最初に停止することなく、ドロップポリシーを適用できます。

解体

Teardown は、意図的に防御的な処理を行うように設計されています。 一部のプラグインの組み合わせでは、状態の変化によって処理が停止することがあります。そのため、ランタイムは、ホストプロセスや CI のデッドロックを回避するように設計されています。

一般的なパターンは次のとおりです。

  • EOSを送信
  • GST_STATE_NULL を設定します。
  • 参照されていないオブジェクト
  • タイムアウトによる安全策を適用する(必要に応じて、プログラムがフリーズする代わりに、エラーを発生させる)。

SimaAI の同時実行処理

SimaAIプラグインは、1つのプロセスで複数のパイプラインをサポートします。複数のパイプラインを同時に実行する場合は、GraphOptionsまたはModelのサフィックス/プレフィックスを使用して要素名に一意性を与え、GStreamerにおける名前の衝突を回避してください。


制約と安全性

  • 入力形式は、大文字と小文字を区別して一致させる必要がありますInputOptionsとモデルの設定は、形式、幅、高さに関して一致している必要があります。 ネゴシエーション中や入力のプッシュ時に、不一致が発生すると、すぐに処理が中断されます。
  • 機能による制限付きの動的入力: ランタイムでの再ネゴシエーションは、構築されたグラフが動的な機能をアドバタイズする場合にのみ許可されます。FullyDynamic グラフは、生のビデオのジオメトリ、フォーマット、フレームレート、メディアの制限を再ネゴシエーションできます。IngressDynamicCvuOnly は、ジオメトリの変更を許可し、ビルド時の下流コントラクトチェックで安定した出力動作が確認された場合にのみ、フォーマットの変更を許可します。
  • 効果的な範囲内での動的な調整: max_* は絶対的な上限値です。max_* が設定されていない場合、width/height/depth が暗黙的な上限値として機能します。
  • モデルとグラフのデフォルト値: どちらのフローも、現在は src/pipeline/internal/InputPolicy.* を通じて、シード/最大値/バイトガードポリシーを解決します。Model は、ドキュメントに記載されているメタデータに基づいたデフォルト値(例:1920x1080 の上限)を適用し続けますが、Graph は、設定されていない限り、ノードオプションによって制御されます。
  • caps_override は、設定されると、再ネゴシエーションがブロックされ、形状の変更には再構築が必要になります。
流れデフォルトのシード値最大値のデフォルト設定バイトガードのデフォルト設定
Model事前にメタデータを処理します(存在する場合)。存在しない場合は、ユーザーの形式や設定から推測します。明示的な input_max_*;それ以外の場合は、ポリシーのデフォルト設定が適用されます(例: 1920x1080(フォーマットから派生した奥行き)明示的にRunOptions.max_input_bytesを指定するか、それ以外の場合は、InputPolicyに基づいて、上限値または動的なデフォルト値を使用します。
Graph入力ノードのオプション、および/または入力サンプル(シード)明示的に指定された場合、max_* となります。そうでない場合は、シードが与えられたときに、width/height/depth から暗黙的に決定されます。明示的にRunOptions.max_input_bytesを指定するか、それ以外の場合は、InputPolicyに基づいて、上限値または動的なデフォルト値を使用します。
  • SimaAI の同時実行性: 複数のパイプラインをプロセス内で実行できます。要素名が重複しないようにしてください。

フレームごとの属性伝播

ソースは、GstSimaMeta 内にネストされた構造として Sample::attributes をアタッチします。バッファーを保持する要素は、メタデータを自然に持ちます。コア境界は、バッファーを割り当てたり再利用したりする際に、属性をディープコピーし、古い値をクリアします。neatdecoder は、デコード前に同じフレームコンテキストのスナップショットを撮り、デーモンによって提供される相関 ID を使用してそれを復元するため、順序が変更されたり、フレームが削除されたりしても、属性が別の出力にシフトされることはありません。ネゴシエートされたデコーダー/デーモンプロトコルが、その相関契約を管理します。従来のデコーダープロトコルは、FIFO のみを使用し続けます。

サポートされているユーザー向けのパスと制限は、フレームごとの属性 に記載されています。

スレッドと所有権モデル

スレッド

  • GStreamer ストリーミングスレッド: パッドプローブ、デコード、スケジューリング
  • ユーザー スレッド: appsink ポーリング + 定期的なバスのデータ読み出し
  • RTSPサーバーのスレッド: gst-rtsp-serverモードにおけるGLibのメインループ。

所有権に関するルール(GStreamerオブジェクト)

  • GStreamerオブジェクトは、参照カウント方式で管理されます。
  • もし、あなたが~を保存すると GstObject* 取得範囲を超えて、あなたは~しなければなりません。 gst_object_ref() それ。
  • 処理が完了したら、必ず gst_object_unref() を一度だけ実行してください。

診断機能におけるスレッドセーフティ(重要)

パッドプローブはストリーミングスレッド上で実行されるため、プローブから更新された診断情報は、ロックフリーでなければなりません

設計は以下のとおりです。

  • BoundaryFlowCountersアトミック変数 を格納します。
  • パッドプローブは、原子レベルでのみ fetch_add() / store() を実行します。
  • レポート作成では、アトミック変数をBoundaryFlowCounters::snapshot()を使用して、通常の整数型であるBoundaryFlowStatsに変換します。

これにより、データ競合を回避しつつ、プローブのコストを低く抑えることができます。

診断と可視化

DiagCtx が取得する情報:

  • パイプライン文字列(再現用)
  • ノードレポート(各ノードが生成した内容)
  • バスメッセージ(ミューテックス下で)
  • 境界を越えるフローカウンタ(アトミック変数)
  • 要素のタイミングとフローカウンター(アトミック変数)

境界流れプローブ

有効にすると、ランタイムは境界にパディングプローブをアタッチします。 identity 要素。 追跡対象:

  • バッファーのカウント(入力/出力)
  • 前回確認された PTS(ナノ秒)
  • 最後に確認された時刻(経過時間、マイクロ秒)

これは、「可能性のある問題点」の概要を生成するために使用されます。

  • 「前回、境界線Xにおいて、時刻Tに何らかの活動(進入または退出)があったのを確認しました」

要素のタイミングを測定するプローブ

有効にすると(SIMA_GST_ELEMENT_TIMINGS=1)、ランタイムは各要素のすべてのパッド(静的、動的、およびリクエスト)にシンク+ソースパッドプローブをアタッチし、バッファーごとにsrc_ts - sink_tsを記録します。これにより、プラグインによる計測に依存せずに、要素ごとの計算時間を算出できます。

バッファーを置き換える要素の場合、実装はGstSimaMeta相関(フレームID/ストリームID)にフォールバックし、missed_in/missed_outカウンターを記録します。

エレメントフロープローブ

有効になっている場合(SIMA_GST_FLOW_DEBUG=1), ランタイムは、各要素のパディングプローブをアタッチして、バッファー/バイト数の追跡や変更の監視を行い、グラフ内のすべてのプラグインに対してスループットのコンテキストを提供します。

バスのログ記録とエラー

ランタイムは、バスメッセージをDiagCtxに書き込みます。 エラーメッセージ(GST_MESSAGE_ERROR)が発生した場合、GraphReportと再現手順を含むNeatErrorをスローします。

DOT形式のファイル

有効になっている場合、ランタイムは、gst_debug_bin_to_dot_file_with_ts(...) を使用して、設定されたディレクトリに DOT 形式のグラフを出力できます。

デバッグ手順書(本番環境用)

  1. パイプラインを再現する: Graph::describe_backend() または last_pipeline()
  2. レポートをキャプチャ: MeasureReport::to_text() または NeatError::report()
  3. 特定のプローブを有効にする:
    • 失速局部の特定のためのSIMA_GST_BOUNDARY_PROBES=1
    • 要素ごとのタイミング設定用:SIMA_GST_ELEMENT_TIMINGS=1
    • 各要素ごとのフローカウンタに対する SIMA_GST_FLOW_DEBUG=1
  4. DOT形式のグラフを生成する: SIMA_GST_DOT_DIR を設定し、再実行してください。
  5. 検証を厳格化する: SIMA_GST_ENFORCE_NAMES=1 を実行し、プリロールのタイムアウトを検証します。

出力処理

Run::pull() を実行すると、Sample が生成され、これには以下のものが含まれる可能性があります。

  • Tensor ペイロード(SampleKind::Tensor、テンソル)
  • 複数の出力の束SampleKind::Bundle)

使用 Run::pull_tensors(...) テンソル形式のペイロードを使用したい場合に、機械学習に特化したワークフローで、完全な形式の代わりにこれを使用します。 Sample 封筒。

パイプラインのシリアライズ(保存/読み込み)

パイプラインは JSON 形式で保存および復元できます。

  • Graph::save(path) は、ノードの種類、ラベル、フラグメント、要素を含む、バージョン管理された JSON 形式のファイルを書き出します。
  • Graph::load(path) は、ConfiguredNode ラッパーを通じてノードを再構築します。

現在のスキーマは、意図的に最小限かつ再現しやすい構成になっており、後になってより高度なノード設定に拡張できます。また、これは将来の連携やツールのための橋渡しとしても機能します。

UXを支援するツール

  • Graph::describe() は、人が読みやすいノードのリストを生成するために、GraphPrinter を使用します。
  • Graph::describe_backend() は、迅速なデバッグのために、gst-launch コマンド文字列を返します。

要素の命名と決定論

決定的な要素名は、以下の理由から、基本的な設計原則となっています。

  • シンクや主要な要素に対するgst_bin_get_by_name()
  • 安定したプローブ固定機構
  • 安定した診断と再現性
  • オプションの命名規則の強制(「すべての要素は、いずれかのノードに属する」)。

Nodeの作成者は、以下の点を確実に守る必要があります:

  • フラグメントには、要素を確実に取得できるように、安定した name= フィールドが含まれます。
  • element_names() は、フラグメントが生成するすべての明示的な要素名を返します。
  • 宣言と名前付きパッド参照は常に同期された状態を保ちます。

名前の整合性は、build() の一部であり、それ以前の validate() の呼び出しに依存しません。名前は、フレームワークの検索で再帰的な短い名前を使用するため、マテリアライズされたパイプラインセグメント内で一意です。個別に解析された接続されたセグメントは、同じ名前を再利用できます。フレームワークは、名前がパディングやルーティング式で使用される可能性があるため、名前の変更ではなく、名前の衝突を拒否します。

入力に依存する接続されたセグメントは、最初の入力でマテリアライズできます。したがって、そのビルドの失敗は、最初の push() または pull() で報告され、元の GraphReport が保持されます。


ステージの命名と配線

このフレームワークでは、プラグインの JSON をプラグインが所有するデータとして扱い、パイプラインの構築中に、ステージごとの JSON フィールドを書き換えたり、検証したりすることはありません。

信頼できる情報源の接続:

  1. ノードの断片から、決定的な GStreamer 要素名を作成します。
  2. SIMAモデルのパス要素におけるstage-id
  3. 静的ステージ/テンソル契約の検索に関するsima.model.manifest.v1のコンテキスト。

示唆される点:

  • これ以上、node_name / input_buffers[*].name / buffers.input[*].name を変更することはできません。
  • Build は、JSON ベースの配線チェックを実行しなくなりました。
  • 名前変換は、引き続き要素名にのみ適用されます。

モデルによって管理されるグラフの実行の場合、ステージの解決は、stage-id とマニフェストのコンテキストによって制御されます。 モデルによって管理されないグラフの実行の場合、明示的なプラグインのプロパティがランタイムの制御面となります。

検証と契約

検証は、ランタイムよりも早い段階で問題を検出するために存在します。

  • validate() は、解析と事前ロールバック(一時停止)を行い、交渉の停滞を検知できます。
  • contracts/ は、「パイプラインの整合性」を検証するための構造化されたバリデーターを提供します。

必須の最終的なローンチ名チェックも、通常のビルドパスで実行されます。ValidateOptions は、名前の整合性が強制されるかどうかではなく、追加の検証作業を制御します。

接続されたグラフの場合、validate() はエンドポイントのトポロジーをコンパイルしますが、入力に依存するセグメントのローンチ文字列は生成しません。各セグメントは、実際の入力コントラクトが利用可能になり、セグメントが実際に作成されたときに、必須のチェックを受けます。

意図された動作:

  • ランタイムは、重大なエラーが発生した場合に例外をスローします。
  • 検証プロセスは、構造化されたレポートを返します(CI ツールとの連携に最適)。

SSD BoxDecode の契約解除

SSDモデルパックは、正確な術後の頭部コントラクトのプライベートレジストリに対して検証されます。これは、グラフのコンパイル中に実行されます。リゾルバーは、順序付けられたすべての論理的な位置情報と信頼度、H/W/C形状を比較します。レベルをソートしたり、モデル名を使用したり、一般的なSSDのようなフォールバックを受け入れたりすることはありません。現在登録されているレシピは、SSD300-v1、SSD-Mobile-300-v1、SSD-Mobile-320-v1、およびSSDlite-Mobile-320-v1です。

解決されたレシピは、スコア活性化、信頼度チャネルの順序、背景クラス、許可されたクラスの選択、必要な300x300または320x320モデルフレーム、およびStretchによる前処理を所有します。コアは、レシピを内部のSsdRecipeIdとして保持します。パブリックおよびプラグインABIデコードタイプは、BoxDecodeType::Ssd / ssdのままです。これは、デプロイされたオブジェクトデコーダーによってサポートされるトークンです。サポートされていない、または不正な形式の頭部ジオメトリ、競合する活性化、無効なクラスの選択、Stretch以外のリサイズ、または誤ったモデルフレームの場合、パイプラインの起動前にエラーが発生します。レシピの検出は、コンパイル時にのみ行われ、フレームごとに実行される処理は追加されません。

RTSPサーバーモード

run_rtsp() は、gst-rtsp-server を使用します。

  • サーバーは、GLibのメインループを持つ専用のスレッドで実行されます。
  • media-configureにおいて、コードは名前によってappsrcを特定し、その機能やプロパティを設定します。
  • フレームは、一定の間隔で(タイマーに基づいて)明確なタイムスタンプとともに送信されます。

各クライアントは、ファクトリの構成に応じて、それぞれ独自のメディアインスタンスを取得できます。

環境/設定項目

ランタイムは、環境に依存するデバッグ設定をサポートしています。

  • SIMA_GST_DOT_DIR -- 失敗時のグラフやデバッグ用のDOT形式のグラフを生成します。
  • SIMA_GST_BOUNDARY_PROBES - 境界フローカウンタを有効にする。
  • SIMA_GST_STAGE_TIMINGS -- ステージタイミングプローブを有効にする
  • SIMA_GST_ELEMENT_TIMINGS - 要素タイミングプローブを有効にする。
  • SIMA_GST_FLOW_DEBUG -- 要素ごとのフローカウンタを有効にする
  • SIMA_GST_ENFORCE_NAMES -- 名前付け規則を強制する。
  • SIMA_GST_RUN_INPUT_TIMEOUT_MS - 実行/ビルドの入力パスに対する入力タイムアウト。
  • SIMA_GST_VALIDATE_TIMEOUT_MS -- プリロールの検証タイムアウト
  • SIMA_GST_VALIDATE_INSERT_BOUNDARIES -- validate() の実行中に境界線を挿入します
  • SIMA_GST_RUN_INSERT_BOUNDARIES -- ビルド時または run() 実行時に境界を挿入します。
  • SIMA_GST_TEARDOWN_TIMEOUT_MS - NULL状態になるまで待機する時間(ミリ秒)
  • SIMA_GST_TEARDOWN_REAPER_MS - reaper の再試行間隔(ミリ秒)
  • SIMA_GST_TEARDOWN_ASYNC -- 待機をスキップし、後処理を reaper に委ねる。

これらの設定項目は、意図的に公開 API の外に配置されているため、再コンパイルすることなく、CI 環境や実際の運用環境で有効にすることができます。

src/pipeline/internal/* には、追加の低レベルのデバッグフラグ(入力ストリームのログ記録、サンプルデータのダンプ、プールデバッグなど)があります。これらのフラグは、詳細な診断が必要な場合を除き、ユーザー向けのドキュメントには含めないでください。

PCIeホストのランタイム境界

個別にパッケージ化された PCIe ホスト API には、次の 2 つの公開レベルがあります。

  • pcie::Model は、特定のモデルに対して、ソース互換性のある便利な API です。
  • pcie::Runtime は、カードの範囲内で動作するマルチモデルコーディネーターであり、軽量な OAAX C ABI アダプターをサポートするように設計されています。

ランタイムは、論理モデルID、呼び出し元が提供するリクエストID、ノンブロッキングエンキュー、任意のモデルからの取得、バッチロード、独立したアンロード、およびべき等なクリーンアップを公開します。ハードウェアキューIDは、実装の詳細として残ります。現在の Modalix 実装では、ロードされたモデルを正確に1つずつ、4つのPCIeキューのそれぞれに割り当て、仮想イーサネットのSSH/SCP制御パスを介してモデルアーカイブの転送を継続します。

推論リクエストの相関関係は、符号付き32ビットのOAAXリクエストIDを使用して、エンコードされます。 GstSimaHostMeta.frame-id PCIe/カード間の往復処理全体にわたって。ビットパターンは不透明であり、パブリック完了時に変更されない状態で復元する必要があります。ランタイムは、モデルとキューのレジストリを管理し、各キューの結果を集約します。カード側 pcie-pipeline-builder キューごとに、プロセスとモデルグラフは1つだけです。

カード搬送機構は、従来の命名規則に従って、個別の専用リクエストトークンを伝送します。 GstSimaMeta.pcie-buffer-id フィールド。正確なドライバーのリクエストと、現在処理中のクレジットを特定します。 通常のプラグインは、これを変更せずに転送できますが、内容を検査したり、改ざんしたりしてはいけません。 stream-id 引き続き、出力ルーティングキーとして機能します。 frame-id 引き続き、アプリケーションの相関キーとなります。 neatpciesink リクエストトークンを解決します。 正常に処理された場合、DATAレスポンスが返されます。デコーダーのドロップ、フラッシュ、再起動、または下流側の障害が発生した場合、関連する NEAT_PCIE_FRAME_RETURN_ERRORこれにより、同じホストのクレジットが解除され、影響を受けるホストのパイプラインが、単にブロックされた状態のままになるのではなく、対処可能なエラーとともに終了されます。

標準化されたOAAX runtime_* Cシンボルは、このネイティブAPIよりも上位にあるアダプターの境界です。OAAXの所有権ルール、ステータスコード、および最終エラーの保存は、C++ APIではなく、そのアダプターに属します。

ライブラリを拡張する方法

新しいノードを追加する

  1. include/nodes/<category>/<YourNode>.h にヘッダーを作成します。

  2. src/nodes/<category>/<YourNode>.cpp に実装してください。

  3. 確認してください:

    • backend_fragment(i) は有効であり、結果が常に一定です。
    • 重要なすべての要素には名前が付けられ、element_names(i) によって返されます。
  4. テストを追加してください(理想的には、以下のいずれか1つ)。

    • 解析/検証テスト
    • 単純なソース/シンクのパイプラインを使用して、テストの実行/ビルドを行う。

ランタイム診断機能の追加

  • DiagCtx および GraphReport にフィールドを追加することを推奨します。
  • ストリーミングスレッドから更新が発生する場合、アトミック操作(または別のロックフリーなメカニズム)を使用してください。
  • レポート用に、プレーンなスナップショット形式に変換します。

依存関係ルール(変更不可)

  • builder/ は、GStreamer や pipeline/ に依存すべきではありません。
  • gst/ は、pipeline/ に依存すべきではありません。
  • nodes/ は、pipeline/ に依存すべきではありません(ノードはビルド時の記述であり、ランタイムのオーケストレーターではありません)。
  • pipeline/ はオーケストレーターであり、gst/builder/nodes/contracts/policy/、およびモデルの内部構造に依存します。

これにより、アーキテクチャはモジュール性を維持し、循環依存を防ぐことができます。

テストとサンプル

  • examples/ は、一般的なエンドツーエンドの利用パターンを示しています。

    • RTSPをデコードする
    • モデルアーカイブを実行
    • RTSPサーバーを実行する
  • tests/ は、重要な動作を検証します。

    • ファイル読み込みパス
    • グループ拡張等価性(入力グループ)
    • テンソル出力パス + 保存/読み込みの往復処理
    • model_resnet50_multi_test は、複数のグラフ/実行インスタンスを使用して、モデルの精度を検証します。

機能を追加する際には、以下のテストを追加することを優先してください。

  • パイプライン文字列を確実に再現する。
  • 上限交渉の前提条件を検証する
  • エラーが発生した場合に、役立つGraphReportの診断情報が生成されるようにする。

ドキュメントの変更監視

ドキュメントとコードを整合させる:

  • 公開ヘッダーを変更した場合(include/*)、README およびアーキテクチャを更新。
  • 標準的なプロダクションパイプラインテストを変更した場合 (tests/e2e_pipelines/obj_detection/sync_yolov8_test.cpp)、ドキュメントを両方とも更新してください。
  • 新しい環境変数を追加する場合は、「環境/設定項目」セクションに追加してください。

デザイン原則

  1. 決定論が勝利する

    • 安定した要素名、安定したパイプライン文字列、安定したレポート
  2. デバッグの容易性が最優先事項である

    • バスログ、DOTダンプ、境界プローブ、明確な再現手順
  3. 安全な並行処理

    • ストリーミングスレッドによるプローブは、アトミック変数のみを対象とします(スナップショットは通常のレポートを生成します)。
  4. 処理を中断しないでください

    • teardown は防御的な処理です。壊れたプラグインのスタックで永久に処理がブロックされるのを避けてください。
  5. 公開 API の安定性を維持する

    • 内部リファクタリングは、意図的にバージョン管理を行わない限り、ユーザーのコードを動作不能にすべきではありません。