OFX (別名OFX 画像処理 API)は、2D 視覚効果とビデオ合成を作成するためのオープン スタンダードです。これは、プラグインのようなアプリケーション開発モデルで動作します。基本的に、これはホスト (メソッドのセットを提供するアプリケーション) とプラグイン (このセットを実装するアプリケーションまたはモジュール) の両方として機能します。
この構成により、ホスト アプリケーションの機能を無制限に拡張できる可能性が得られます。
Final Cut X や DaVinci Resolve Studio などのアプリケーションは、バージョン 16 以降、Apple Metal パイプラインを完全にサポートします。 OpenCL や Cuda と同様に、OFX の場合も、プラットフォーム固有のコマンド キューの記述子またはハンドラーを取得できます。ホスト システムは、そのようなキューのプールを割り当て、それらのキューで計算のバランスをとる責任も負います。
さらに、ソースおよびターゲットのイメージ クリップ データを GPU メモリに配置するため、拡張可能な機能の開発が大幅に簡素化されます。
Resolve では、状況が少し複雑になります。 DaVinci は、いくつかの制限はありますが、OFX v1.4 のサポートを発表しました。特に、インターフェイス関数を操作するための一部のメソッドは使用できません。どの方法が利用可能であるかを判断するために、OFX ではキー/値クエリを通じてサポートされているスイートを調べることができます。
プラグイン コード内のパブリッシュ メソッドはC 呼び出しに基づいています。ただし、C++17 に適合した OpenFXS C++ シェルを使用します。便宜上、すべてを 1 つのリポジトリ (オープンソースDehancer プロジェクトから取得したdehancer-external)にコンパイルしました。
このプロジェクトでは、OpenFX の C++ 拡張機能である OpenFXS を使用します。OpenFXS は、もともとBruno Nicolettiによって作成され、商用およびオープンソースのビデオ処理プロジェクトで徐々に普及してきました。
オリジナルのOpenFXS は最新の C++ 方言に適合していなかったので、 C++17と互換性を持たせるために更新しました。
OFX、つまり OFXS は、ホスト プログラムによって動的にロードされるスタンドアロン ソフトウェア モジュールです。基本的に、これはメイン アプリケーションの起動時にロードされる動的ライブラリです。 OpenFXS は、OFX と同様にメソッド シグネチャを公開する必要があります。したがって、コードから 1 つの C メソッドを使用します。
OpenFXS で開発を開始するには、アプリケーションで新しい機能を作成するために使用されるいくつかの共通のクラス セットに同意する必要があります。通常、新しいプロジェクトでは、これらのクラスを継承し、いくつかの仮想メソッドを実装またはオーバーライドする必要があります。
ホスト システム上で独自のプラグインを作成するには、まず、次のパブリック クラスと同じメソッドについて理解しましょう。
ビデオ撮影のプロセスを単に写真に画像をキャプチャすることと区別する特徴の 1 つは、シーン全体と画像内の領域の両方のシーンと照明が動的に変化することです。これにより、撮影プロセス中に露出を制御する方法が決まります。
デジタル ビデオには、オペレーター向けの制御モニター モードがあり、エリアの露出レベルが、それぞれが独自の色で着色された限定されたゾーンのセットにマッピングされます。
このモードは、「プレデター」またはフォールス カラー モードと呼ばれることもあります。通常、スケールは IRE スケールを参照します。
このようなモニターを使用すると、露出ゾーンを確認し、カメラの撮影パラメータを設定する際の重大な間違いを避けることができます。写真で露出するときにも同様の意味が使用されます。たとえば、アダムズによればゾーニングです。
露出計で特定のターゲットを測定し、それがどのゾーンに位置するかを確認できます。ゾーンは、認識しやすいようにきれいに色付けされてリアルタイムで表示されます。
ゾーンの数は、制御モニターの目的と機能によって決まります。たとえば、 Arri Alexaカメラで使用されるモニターには、最大 6 つのゾーンを組み込むことができます。
例に進む前に、メタル テクスチャなどのソース データを処理するプラットフォームとして OpenFXS を実装するために、いくつかの単純なプロキシ クラスを追加する必要があります。これらのクラスには次のものが含まれます。
imetalling::Image2Texture : データをクリップ バッファーから Metal テクスチャに転送するためのファンクター。 DaVinci からは、任意の構造のバッファーと画像チャンネル値のパッケージ化をプラグインに抽出でき、同様の形式で返されるはずです。
OFX でのストリーム形式の操作を容易にするために、事前に特定のタイプのデータを準備するようにホストに要求できます。 RGBA (赤/緑/青/アルファ) でパックされた浮動小数点数を使用します。
Metal コアがどのように動作するかについては詳しく説明せずに、OXS の基本クラスを継承して機能を記述します。
さらに、MSL 上のホスト コードとカーネル コードを論理的に分離するには、Metal 上に構築されたいくつかのユーティリティ クラスが必要になります。これらには次のものが含まれます。
imetalling::FalseColorKernel : 私たちの主要な機能クラスであり、指定された色数にポスタライズ (ダウンサンプル) する「プレデター」エミュレーターです。
「プレデター」モードのカーネル コードは次のようになります。
static constant float3 kIMP_Y_YUV_factor = {0.2125, 0.7154, 0.0721}; constexpr sampler baseSampler(address::clamp_to_edge, filter::linear, coord::normalized); inline float when_eq(float x, float y) { return 1.0 - abs(sign(x - y)); } static inline float4 sampledColor( texture2d<float, access::sample> inTexture, texture2d<float, access::write> outTexture, uint2 gid ){ float w = outTexture.get_width(); return mix(inTexture.sample(baseSampler, float2(gid) * float2(1.0/(w-1.0), 1.0/float(outTexture.get_height()-1))), inTexture.read(gid), when_eq(inTexture.get_width(), w) // whe equal read exact texture color ); } kernel void kernel_falseColor( texture2d<float, access::sample> inTexture [[texture(0)]], texture2d<float, access::write> outTexture [[texture(1)]], device float3* color_map [[ buffer(0) ]], constant uint& level [[ buffer(1) ]], uint2 gid [[thread_position_in_grid]]) { float4 inColor = sampledColor(inTexture,outTexture,gid); float luminance = dot(inColor.rgb, kIMP_Y_YUV_factor); uint index = clamp(uint(luminance*(level-1)),uint(0),uint(level-1)); float4 color = float4(1); if (index<level) color.rgb = color_map[index]; outTexture.write(color,gid); }
OFXプラグインの初期化
まず、 imetalling::falsecolor::Factory.
このクラスでは、モニターのステータス (オンまたはオフ) という 1 つのパラメーターを設定します。これはこの例では必要です。
OFX::PluginFactoryHelper
から継承し、5 つのメソッドをオーバーロードします。
ImageEffectDescriptor
コードを参照してください。
descriptionInContext(ImageEffectDescriptor&,ContextEnum) : describe
メソッドと同様に、このメソッドもプラグインがロードされるときに呼び出され、クラスで定義する必要があります。現在のコンテキストに関連付けられたプロパティを定義する必要があります。
コンテキストによって、アプリケーションが扱う操作のタイプ (フィルター、ペイント、トランジション エフェクト、クリップ内のフレーム リタイマーなど) が決まります。
ImageEffect
型のオブジェクトへのポインタを返します。言い換えれば、 imetalling::falsecolor::Plugin
では、ホスト プログラムのユーザー イベントとソース フレームからターゲット フレームへのレンダリング (変換) の両方に関するすべての機能が定義されています。 OFX::ImageEffect *Factory::createInstance(OfxImageEffectHandle handle,OFX::ContextEnum) { return new Plugin(handle); }
この段階で、OFX モジュールを使用してバンドルをコンパイルすると、プラグインはホスト アプリケーションですでに利用可能になり、DaVinci では補正ノードにロードできます。
ただし、プラグイン インスタンスを完全に操作するには、少なくともインタラクティブな部分と、受信ビデオ ストリームの処理に関連する部分を定義する必要があります。
これを行うには、 OFX::ImageEffectクラスを継承し、仮想メソッドをオーバーロードします。
ChangeParam(const OFX::InstanceChangedArgs&, const std::string&) - このメソッドを使用すると、イベントを処理するロジックを定義できます。イベント タイプは OFX::InstanceChangedArgs::reason の値によって決定され、次のいずれかになります: eChangeUserEdit、eChangePluginEdit、eChangeTime - ユーザーによって編集されたプロパティ、プラグインまたはホスト アプリケーションで変更されたプロパティの結果としてイベントが発生しました。タイムラインの変更の結果。
2 番目のパラメーターは、プラグインの初期化段階で定義した文字列名を指定します。この場合、それは 1 つのパラメーターです: false_color_enabled_check_box 。
OFX との対話型対話の実装は、 Interaction.cppコードで読み取ることができます。ご覧のとおり、クリップへのポインター、つまりソース クリップとターゲット変換を配置するメモリ領域を受け取ります。
変換を開始するためのすべてのロジックを定義する別の論理レイヤーを追加します。私たちの場合、これは今のところオーバーライドする唯一の方法です。
起動段階では、便利なプロパティを持つオブジェクトが利用可能になりました。少なくとも、ビデオ ストリームへのポインタ (より正確には、フレーム イメージ データを含むメモリ領域)、そして最も重要なことに、Metal コマンドのキューがあります。
これで、カーネル コードを再利用する単純な形式に近づけるジェネリック クラスを構築できるようになりました。 OpenFXS 拡張機能には、次のようなクラスがすでに存在します。オーバーロードする必要があるだけです。
コンストラクターには OFX::ImageEffect パラメーターがあります。つまり、その中でプラグイン パラメーターの現在の状態だけでなく、GPU の操作に必要なすべてのものを受け取ります。
この段階では、 processImagesMetal()メソッドをオーバーロードし、既に Metal に実装されているカーネルの処理を開始するだけです。
Processor::Processor( OFX::ImageEffect *instance, OFX::Clip *source, OFX::Clip *destination, const OFX::RenderArguments &args, bool enabled ) : OFX::ImageProcessor(*instance), enabled_(enabled), interaction_(instance), wait_command_queue_(false), /// grab the current frame of a clip from OFX host memory source_(source->fetchImage(args.time)), /// create a target frame of a clip with the memory area already specified in OFX destination_(destination->fetchImage(args.time)), source_container_(nullptr), destination_container_(nullptr) { /// Set OFX rendering arguments to GPU setGPURenderArgs(args); /// Set render window setRenderWindow(args.renderWindow); /// Place source frame data in Metal texture source_container_ = std::make_unique<imetalling::Image2Texture>(_pMetalCmdQ, source_); /// Create empty target frame texture in Metal destination_container_ = std::make_unique<imetalling::Image2Texture>(_pMetalCmdQ, destination_); /// Get parameters for packing data in the memory area of the target frame OFX::BitDepthEnum dstBitDepth = destination->getPixelDepth(); OFX::PixelComponentEnum dstComponents = destination->getPixelComponents(); /// and original OFX::BitDepthEnum srcBitDepth = source->getPixelDepth(); OFX::PixelComponentEnum srcComponents = source->getPixelComponents(); /// show a message to the host system that something went wrong /// and cancel rendering of the current frame if ((srcBitDepth != dstBitDepth) || (srcComponents != dstComponents)) { OFX::throwSuiteStatusException(kOfxStatErrValue); } /// set in the current processor context a pointer to the memory area of the target frame setDstImg(destination_.get_ofx_image()); } void Processor::processImagesMetal() { try { if (enabled_) FalseColorKernel(_pMetalCmdQ, source_container_->get_texture(), destination_container_->get_texture()).process(); else PassKernel(_pMetalCmdQ, source_container_->get_texture(), destination_container_->get_texture()).process(); ImageFromTexture(_pMetalCmdQ, destination_, destination_container_->get_texture(), wait_command_queue_); } catch (std::exception &e) { interaction_->sendMessage(OFX::Message::eMessageError, "#message0", e.what()); } }
プロジェクトをビルドするには CMake が必要で、少なくともバージョン 3.15 である必要があります。さらに、システム ディレクトリ内のプラグイン インストーラーを使用してバンドルを簡単かつ便利に組み立てるのに役立つ Qt5.13 が必要です。 cmake を開始するには、まずビルド ディレクトリを作成する必要があります。
ビルド ディレクトリを作成した後、次のコマンドを実行できます。
cmake -DPRINT_DEBUG=ON -DQT_INSTALLER_PREFIX=/Users/<user>/Develop/QtInstaller -DCMAKE_PREFIX_PATH=/Users/<user>/Develop/Qt/5.13.0/clang_64/lib/cmake -DPLUGIN_INSTALLER_DIR=/Users/<user>/Desktop -DCMAKE_INSTALL_PREFIX=/Library/OFX/Plugins .. && make install
その後、 IMFalseColorOfxInstaller.appというインストーラーが、 PLUGIN_INSTALLER_DIRパラメーターで指定したディレクトリに表示されます。さあ、起動しましょう!インストールが成功したら、DaVinci Resolve を起動して、新しいプラグインの使用を開始できます。
カラーコレクションページの OpenFX パネルで見つけて選択し、ノードとして追加できます。
外部リンク