paint-brush
Kendi Apple Metal Eklentinizi Geliştirmenin ve DaVinci Resolve'ye Entegre Etmenin Kolay Yoluile@denissvinarchuk
3,610 okumalar
3,610 okumalar

Kendi Apple Metal Eklentinizi Geliştirmenin ve DaVinci Resolve'ye Entegre Etmenin Kolay Yolu

ile Denis Svinarchuk13m2024/03/13
Read on Terminal Reader

Çok uzun; Okumak

OFX, diğer adıyla OFX Görüntü İşleme API'si, 2D görsel efektler ve video birleştirme oluşturmaya yönelik açık bir standarttır. Eklenti benzeri bir uygulama geliştirme modelinde çalışır. Temel olarak, hem bir Ana Bilgisayar (bir dizi yöntem sağlayan bir uygulama) hem de bir Eklenti (bu seti uygulayan bir uygulama veya modül) olarak hizmet eder. Bu yapılandırma, ana bilgisayar uygulamasının işlevselliğinin sınırsız genişletilmesi potansiyelini sunar.
featured image - Kendi Apple Metal Eklentinizi Geliştirmenin ve DaVinci Resolve'ye Entegre Etmenin Kolay Yolu
Denis Svinarchuk HackerNoon profile picture

OFX, diğer adıyla OFX Görüntü İşleme API'si , 2D görsel efektler ve video birleştirme oluşturmaya yönelik açık bir standarttır. Eklenti benzeri bir uygulama geliştirme modelinde çalışır. Temel olarak, hem bir Ana Bilgisayar (bir dizi yöntem sağlayan bir uygulama) hem de bir Eklenti (bu seti uygulayan bir uygulama veya modül) olarak hizmet eder.


Bu yapılandırma, ana bilgisayar uygulamasının işlevselliğinin sınırsız genişletilmesi potansiyelini sunar.

DaVinci Resolve ve Metal

Final Cut X ve DaVinci Resolve Studio gibi uygulamalar, sürüm 16'dan başlayarak, Apple Metal işlem hatlarını tamamen destekler. OpenCL ve Cuda'ya benzer şekilde, OFX durumunda, platforma özgü bir komut kuyruğunun tanımlayıcısını veya işleyicisini elde edebilirsiniz. Ana bilgisayar sistemi ayrıca bu tür kuyruklardan oluşan bir havuz tahsis etme ve bunlar üzerindeki hesaplamaları dengeleme sorumluluğunu da üstlenir.


Ayrıca kaynak ve hedef görüntü klibi verilerini GPU belleğine yerleştirerek genişletilebilir işlevselliğin geliştirilmesini önemli ölçüde basitleştirir.

Resolve'da OFX Sürüm Desteği

Resolve ile işler biraz daha karmaşık. DaVinci, bazı sınırlamalara rağmen OFX v1.4 desteğini duyurdu. Özellikle arayüz işlevleriyle çalışmaya yönelik bazı yöntemler kullanılamaz. Hangi yöntemin kullanılabilir olduğunu belirlemek için OFX, desteklenen paketi anahtar/değer sorguları aracılığıyla incelemenize olanak tanır.


Eklenti kodundaki yayınlama yöntemleri C çağrılarına dayanmaktadır. Ancak biz C++17 için uyarlanmış OpenFXS C++ kabuğunu kullanacağız. Kolaylık sağlamak için her şeyi tek bir depoda derledim: açık kaynaklı Dehancer projesinden alınan dehancer-external .

OFXS Konsepti

Bu projede, orijinal olarak Bruno Nicoletti tarafından yazılan ve zamanla ticari ve açık kaynaklı video işleme projelerinde popüler hale gelen, OpenFX'in C++ uzantısı olan OpenFXS'i kullanacağım.


Orijinal OpenFXS, modern C++ lehçelerine uyarlanmamıştı, bu yüzden onu C++17 ile uyumlu hale getirecek şekilde güncelledim.


OFX ve dolayısıyla OFXS, ana program tarafından dinamik olarak yüklenen bağımsız bir yazılım modülüdür. Esas itibariyle ana uygulama başlatıldığında yüklenen dinamik bir kütüphanedir. OpenFXS, OFX gibi, yöntem imzalarını yayınlamalıdır. Bu nedenle koddaki bir C yöntemini kullanıyoruz.


OpenFXS'te geliştirmeye başlamak için uygulamanızda yeni işlevler oluşturmak amacıyla kullanılan birkaç ortak sınıf kümesini kabul etmeniz gerekir. Genellikle yeni bir projede bu sınıflardan miras almanız ve bazı sanal yöntemleri uygulamanız veya geçersiz kılmanız gerekir.


Ana sistemde kendi eklentinizi oluşturmak için aşağıdaki genel sınıfları ve aynı yöntemi öğrenerek başlayalım:


  • OFX::PluginFactoryHelper, bir eklentinin veri yapısı paketini ve kontrol panelini oluşturmak için temel bir şablondur (boş bırakılabilmesine rağmen). Miras alınan sınıf, geliştiricinin modülünü kaydettirdiği ana sistemdeki bir dizi parametreyi ve ön ayarı kaydeden tek bir nesne oluşturur;


  • OFX::ParamSetDescriptor - yapı özelliklerini oluşturmak ve depolamak için temel kapsayıcı sınıfı;


  • OFX::ImageEffectDescriptor - veri işleme prosedürlerini çağırırken grafik verileri işlenirken kullanılan özelliklerin kapsayıcısı. Ana bilgisayar uygulaması tarafından, işleme parametrelerinin içeriğini dahili veritabanına kaydetmek ve her bir örneği için tanımlanan eklenti özellikleriyle çalışmak için kullanılır;


  • OFX::ParamSet - kayıtlı veri yapısını değiştirmenizi sağlayan bir dizi ayar;


  • OFX::ImageEffect - OFX::ParamSet'ten miras alınan, grafik veriler üzerindeki efektler için bir dizi ayar;


  • OFX::MultiThread::Processor - alt sınıfta veri akışı işlemenin uygulanması gerekir: resimler veya videolar;


  • OFX::Plugin::getPluginIDs - ana bilgisayar uygulamasına bir eklentiyi (fabrika) kaydetme yöntemi;

Yanlış Renk

Video çekme işlemini basitçe bir fotoğraftaki görüntüyü yakalamaktan ayıran özelliklerden biri, sahnelerin dinamik değişimi ve hem bir bütün olarak sahnelerin hem de görüntüdeki alanların aydınlatılmasıdır. Bu, çekim işlemi sırasında pozlamanın nasıl kontrol edileceğini belirler.


Dijital videoda, alanların maruz kalma düzeyinin, her biri kendi rengiyle renklendirilmiş sınırlı sayıda bölgeye eşlendiği, operatörler için bir kontrol izleme modu vardır.


Bu moda bazen "yırtıcı" veya Yanlış Renk modu denir. Ölçekler genellikle IRE ölçeğine atıfta bulunur.


Böyle bir monitör, kamera çekim parametrelerini ayarlarken pozlama bölgelerini görmenize ve önemli hatalardan kaçınmanıza olanak tanır. Fotoğrafta pozlama sırasında anlam olarak benzer bir şey kullanılır - örneğin Adams'a göre imar.


Belirli bir hedefi bir pozlama ölçerle ölçebilir ve hangi bölgede bulunduğunu görebilirsiniz; gerçek zamanlı olarak algılama kolaylığı için düzgün bir şekilde renklendirilmiş bölgeleri görebiliriz.


Bölgelerin sayısı kontrol monitörünün hedefleri ve yeteneklerine göre belirlenir. Örneğin, Arri Alexa kameralarıyla kullanılan bir monitörde 6'ya kadar bölge bulunabilir.


16 bölgeli yazılım “yırtıcı” versiyonu


Uzantı Ekleme

Örneğe geçmeden önce, OpenFXS'i Metal dokular gibi kaynak verileri işlemek için bir platform olarak uygulamak için bazı basit proxy sınıfları eklememiz gerekiyor. Bu sınıflar şunları içerir:


  • imetalling::Image : OFX klip verileri için bir proxy sınıfı.


  • imetalling::Image2Texture : Verileri klip arabelleğinden Metal dokuya aktarmak için kullanılan bir işlev. DaVinci'den, herhangi bir yapının arabelleğini ve görüntü kanalı değerlerinin paketlenmesini eklentiye çıkarabilirsiniz; bu, benzer bir biçimde döndürülmelidir.


    OFX'te akış formatıyla çalışmayı kolaylaştırmak için ana bilgisayardan belirli bir türdeki verileri önceden hazırlamasını isteyebilirsiniz. RGBA - kırmızı/yeşil/mavi/alfa olarak paketlenmiş şamandıraları kullanacağım.


  • imetalling::ImageFromTexture : Bir akışı ana bilgisayar sistemi arabelleğine dönüştürmek için ters bir işlev. Gördüğünüz gibi, Metal hesaplama çekirdeklerine dokuyla değil doğrudan arabellekle çalışmayı öğretirseniz, hesaplamaların önemli ölçüde optimizasyonu potansiyeli vardır.


OFXS temel sınıflarını miras alıyoruz ve Metal çekirdeğin nasıl çalıştığına dair ayrıntılara girmeden işlevselliğimizi yazıyoruz:


  • imetalling::falsecolor::Processor : Burada akım dönüşümünü gerçekleştirip işlemeyi başlatıyoruz.


  • imetalling::falsecolor::Factory : Bu, eklenti için paket açıklamasının özel kısmı olacak. Yapının kurulumuyla ilgili birkaç zorunlu çağrı uygulamamız ve uygulamada iki alt sınıfa ayırdığımız OFX::ImageEffect sınıfının belirli işlevselliğe sahip bir örneğini oluşturmamız gerekiyor: Etkileşim ve Eklenti.


  • imetalling::falsecolor::Interaction : Efektlerle çalışmanın etkileşimli kısmının uygulanması. Temel olarak bu, eklenti parametrelerindeki değişikliklerin işlenmesiyle ilgili OFX::ImageEffect'in yalnızca sanal yöntemlerinin uygulanmasıdır.


  • imetalling::falsecolor::Plugin : İş parçacığı oluşturmanın uygulanması, yani imetalling::Processor'ın başlatılması.


Ek olarak, MSL'de ana bilgisayar kodu ile çekirdek kodunu mantıksal olarak ayırmak için Metal üzerine inşa edilmiş birkaç yardımcı program sınıfına ihtiyacımız olacak. Bunlar şunları içerir:


  • imetalling::Function : Metal komut kuyruğuyla çalışmayı engelleyen bir temel sınıf. Ana parametre, MSL kodundaki çekirdeğin adı ve çekirdek çağrısının yürütücüsü olacaktır.


  • imetalling:Kernel : Bir kaynak dokuyu hedef dokuya dönüştürmek için genel bir sınıf, Function'ı MSL çekirdeğini çağırmak için parametreleri ayarlamak üzere genişletiyor.


  • imetalling::PassKernel : Çekirdeği atla.


  • imetalling::FalseColorKernel : Ana işlevsel sınıfımız, belirli sayıda renge poster oluşturan (alt örnekler) bir "yırtıcı" öykünücüsü.


"Yırtıcı" modunun çekirdek kodu şöyle görünebilir:

 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 Eklentisinin Başlatılması

imetalling::falsecolor::Factory. Bu sınıfta tek bir parametre belirleyeceğiz - monitörün durumu (açık veya kapalı). Örneğimiz için bu gereklidir.

OFX::PluginFactoryHelper miras alacağız ve beş yöntemi aşırı yükleyeceğiz:


  • load() : Bu yöntem, eklenti ilk yüklendiğinde örneği genel olarak yapılandırmak için çağrılır. Bu yöntemin aşırı yüklenmesi isteğe bağlıdır.


  • unload() : Bu yöntem, örneğin belleği temizlemek için bir örneğin yükü kaldırıldığında çağrılır. Bu yöntemin aşırı yüklenmesi de isteğe bağlıdır.


  • define(ImageEffectDescriptor&) : Bu, eklenti yüklendiğinde OFX ana bilgisayarının çağırdığı ikinci yöntemdir. Sanaldır ve sınıfımızda tanımlanması gerekir. Bu yöntemde, içerik türünden bağımsız olarak eklentinin tüm özelliklerini ayarlamamız gerekiyor. Özellikler hakkında daha fazla ayrıntı için ImageEffectDescriptor koduna bakın.


  • defineInContext(ImageEffectDescriptor&,ContextEnum) : describe yöntemine benzer şekilde bu yöntem de eklenti yüklendiğinde çağrılır ve sınıfımızda tanımlanması gerekir. Geçerli bağlamla ilişkili özellikleri tanımlamalıdır.


    Bağlam, bir klipteki filtre, boyama, geçiş efekti veya kare yeniden zamanlayıcı gibi uygulamanın birlikte çalıştığı işlem türlerini belirler.


  • createInstance(OfxImageEffectHandle, ContextEnum) : Aşırı yüklediğimiz en önemli yöntemdir. ImageEffect türündeki bir nesneye bir işaretçi döndürürüz. Başka bir deyişle, hem ana bilgisayar programındaki kullanıcı etkinliklerine hem de kaynak çerçeveyi hedef çerçeveye dönüştürmeye (dönüştürmeye) ilişkin tüm işlevleri tanımladığımız imetalling::falsecolor::Plugin :
 OFX::ImageEffect *Factory::createInstance(OfxImageEffectHandle handle,OFX::ContextEnum) {     return new Plugin(handle);   }


Olayları Ele Alma

Bu aşamada, OFX modülü ile bir paket derlerseniz, eklenti ana bilgisayar uygulamasında zaten mevcut olacaktır ve DaVinci'de düzeltme düğümüne yüklenebilecektir.


Ancak bir eklenti örneğiyle tam olarak çalışmak için en azından etkileşimli kısmı ve gelen video akışının işlenmesiyle ilişkili kısmı tanımlamanız gerekir.


Bunu yapmak için OFX::ImageEffect sınıfından miras alıyoruz ve sanal yöntemleri aşırı yüklüyoruz:


  • changeParam(const OFX::InstanceChangedArgs&, const std::string&) - Bu yöntem, olayı işleme mantığını tanımlamamıza olanak tanır. Olay türü, OFX::InstanceChangedArgs::reason değerine göre belirlenir ve şunlar olabilir: eChangeUserEdit, eChangePluginEdit, eChangeTime - bir özelliğin kullanıcı tarafından düzenlenmesi, bir eklenti veya ana bilgisayar uygulamasında değiştirilmesi sonucu meydana gelen olay veya zaman çizelgesindeki bir değişikliğin sonucu olarak.


    İkinci parametre, eklenti başlatma aşamasında tanımladığımız dize adını belirtir; bizim durumumuzda bu bir parametredir: false_color_enabled_check_box .


  • isIdentity(...) - Bu yöntem, bir olaya tepki verme mantığını tanımlamamıza ve bir şeyin değişip değişmediğini ve oluşturmanın anlamlı olup olmadığını belirleyen bir durumu döndürmemize olanak tanır. Yöntemin false veya true değeri döndürmesi gerekir. Bu, gereksiz hesaplamaların sayısını optimize etmenin ve azaltmanın bir yoludur.


OFX ile etkileşimli etkileşimin uygulanmasını Interaction.cpp kodunda okuyabilirsiniz. Gördüğünüz gibi kliplere işaretçiler alıyoruz: kaynak olan ve hedef dönüşümü koyacağımız hafıza alanı.

Rendering Lansmanının Uygulanması

Dönüşümü başlatmanın tüm mantığını tanımlayacağımız başka bir mantıksal katman ekleyeceğiz. Bizim durumumuzda şu ana kadar geçersiz kılmanın tek yöntemi budur:


  • render(const OFX::RenderArguments& args) - Burada kliplerin özelliklerini öğrenebilir ve bunların nasıl oluşturulacağına karar verebilirsiniz. Ayrıca bu aşamada Metal komut kuyruğu ve mevcut zaman çizelgesi özellikleriyle ilişkili bazı yararlı özellikler de kullanımımıza sunulur.

İşleme

Başlatma aşamasında, kullanışlı özelliklere sahip bir nesne bizim için kullanılabilir hale geldi: video akışına yönelik en azından bir işaretçimiz (daha doğrusu, çerçeve görüntü verilerini içeren bir hafıza alanı) ve en önemlisi bir Metal komutları kuyruğumuz var.


Artık bizi çekirdek kodunu yeniden kullanmanın basit bir biçimine yaklaştıracak genel bir sınıf oluşturabiliriz. OpenFXS uzantısının zaten böyle bir sınıfı var: OFX::ImageProcessor; sadece onu aşırı yüklememiz gerekiyor.


Yapıcıda OFX::ImageEffect parametresi vardır, yani içinde yalnızca eklenti parametrelerinin mevcut durumunu değil aynı zamanda GPU ile çalışmak için gerekli olan her şeyi alacağız.


Bu aşamada sadece prosesImagesMetal() metodunu aşırı yüklememiz ve Metal üzerinde hali hazırda uygulanan kernellerin işlenmesini başlatmamız gerekiyor.

 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());      }    }


Projeyi Oluşturmak

Projeyi oluşturmak için CMake'e ihtiyacınız olacak ve en az 3.15 sürümü olmalıdır. Ek olarak, paketin sistem dizinindeki eklenti yükleyicisiyle kolay ve rahat bir şekilde birleştirilmesine yardımcı olan Qt5.13'e ihtiyacınız olacak. Cmake'yi başlatmak için önce bir derleme dizini oluşturmanız gerekir.


Derleme dizinini oluşturduktan sonra aşağıdaki komutu çalıştırabilirsiniz:


 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 


Kişisel “yırtıcınız”


Daha sonra PLUGIN_INSTALLER_DIR parametresinde belirttiğiniz dizinde IMFalseColorOfxInstaller.app isimli kurulum dosyası karşınıza çıkacaktır. Hadi devam edelim ve başlatalım! Kurulum başarılı olduktan sonra DaVinci Resolve'yi başlatabilir ve yeni eklentimizi kullanmaya başlayabilirsiniz.


Renk düzeltme sayfasındaki OpenFX panelinde bulup seçebilir ve düğüm olarak ekleyebilirsiniz.



Yanlış Renkte Çalışma



Dış bağlantılar

  1. Yanlış Renk OFX Eklenti Kodu
  2. Açık Efektler Derneği
  3. Resolve + örnekleri altında DaVinci Resolve - OFX başlık dosyası sürümünü ve OFXS kitaplık kodunu indirin