OFX, ওরফে OFX ইমেজ প্রসেসিং API , 2D ভিজ্যুয়াল ইফেক্ট এবং ভিডিও কম্পোজিটিং তৈরির জন্য একটি উন্মুক্ত মান। এটি একটি প্লাগইন-এর মতো অ্যাপ্লিকেশন ডেভেলপমেন্ট মডেলে কাজ করে। মূলত, এটি একটি হোস্ট উভয়ই কাজ করে - একটি অ্যাপ্লিকেশন যা পদ্ধতির একটি সেট প্রদান করে এবং একটি প্লাগ-ইন - একটি অ্যাপ্লিকেশন বা মডিউল এই সেটটি বাস্তবায়ন করে।
এই কনফিগারেশনটি হোস্ট অ্যাপ্লিকেশনের কার্যকারিতা সীমাহীন সম্প্রসারণের সম্ভাবনা অফার করে।
16 সংস্করণ থেকে শুরু করে Final Cut X এবং DaVinci Resolve Studio এর মতো অ্যাপ্লিকেশনগুলি অ্যাপল মেটাল পাইপলাইনগুলিকে সম্পূর্ণরূপে সমর্থন করে৷ OpenCL এবং Cuda এর মতো, OFX-এর ক্ষেত্রে, আপনি একটি প্ল্যাটফর্ম-নির্দিষ্ট কমান্ড সারির একটি বর্ণনাকারী বা হ্যান্ডলার পেতে পারেন। হোস্ট সিস্টেম এই ধরনের সারিগুলির একটি পুল বরাদ্দ করার এবং তাদের উপর গণনার ভারসাম্যের দায়িত্ব নেয়।
অধিকন্তু, এটি GPU মেমরিতে উৎস এবং টার্গেট ইমেজ ক্লিপ ডেটা রাখে, উল্লেখযোগ্যভাবে এক্সটেনসিবল কার্যকারিতার বিকাশকে সহজ করে।
সমাধানের সাথে, জিনিসগুলি কিছুটা জটিল। DaVinci কিছু সীমাবদ্ধতা থাকা সত্ত্বেও OFX v1.4-এর জন্য সমর্থন ঘোষণা করেছে। বিশেষত, ইন্টারফেস ফাংশনগুলির সাথে কাজ করার জন্য কিছু পদ্ধতি ব্যবহারের জন্য উপলব্ধ নয়। কোন পদ্ধতি উপলব্ধ তা নির্ধারণ করতে, OFX আপনাকে কী/মান প্রশ্নের মাধ্যমে সমর্থিত স্যুট পরীক্ষা করার অনুমতি দেয়।
প্লাগইন কোডে প্রকাশনা পদ্ধতি সি কলের উপর ভিত্তি করে। কিন্তু আমরা C++17-এর জন্য অভিযোজিত OpenFXS C++ শেল ব্যবহার করব। সুবিধার জন্য, আমি সবকিছু একটি সংগ্রহস্থলে কম্পাইল করেছি: dehancer-external ওপেন সোর্স Dehancer প্রকল্প থেকে নেওয়া।
এই প্রকল্পে, আমি OpenFXS ব্যবহার করব, OpenFX-এর একটি C++ এক্সটেনশন যা মূলত ব্রুনো নিকোলেটি লিখেছিলেন এবং সময়ের সাথে সাথে বাণিজ্যিক এবং ওপেন-সোর্স ভিডিও প্রক্রিয়াকরণ প্রকল্পে জনপ্রিয় হয়ে উঠেছে।
আসল OpenFXS আধুনিক C++ উপভাষায় অভিযোজিত হয়নি, তাই আমি এটিকে C++17 এর সাথে সামঞ্জস্যপূর্ণ করতে আপডেট করেছি।
OFX, এবং ফলস্বরূপ OFXS হল একটি স্বতন্ত্র সফ্টওয়্যার মডিউল যা হোস্ট প্রোগ্রাম দ্বারা গতিশীলভাবে লোড হয়। মূলত, এটি একটি গতিশীল লাইব্রেরি যা মূল অ্যাপ্লিকেশন শুরু হলে লোড হয়। OpenFXS, OFX এর মত, অবশ্যই পদ্ধতি স্বাক্ষর প্রকাশ করতে হবে। সুতরাং, আমরা কোড থেকে একটি সি পদ্ধতি ব্যবহার করি।
OpenFXS-এ বিকাশ শুরু করার জন্য, আপনাকে কয়েকটি সাধারণ ক্লাসের সাথে সম্মত হতে হবে যা আপনার অ্যাপ্লিকেশনে নতুন কার্যকারিতা তৈরি করতে ব্যবহৃত হয়। সাধারণত, একটি নতুন প্রকল্পে, আপনাকে এই ক্লাসগুলি থেকে উত্তরাধিকারসূত্রে প্রাপ্ত করতে হবে এবং কিছু ভার্চুয়াল পদ্ধতি প্রয়োগ বা ওভাররাইড করতে হবে।
হোস্ট সিস্টেমে আপনার নিজস্ব প্লাগইন তৈরি করতে, আসুন নিম্নলিখিত পাবলিক ক্লাস এবং একই পদ্ধতির সাথে নিজেদের পরিচিত করে শুরু করি:
একটি বৈশিষ্ট্য যা ভিডিও শ্যুট করার প্রক্রিয়াটিকে কেবল একটি ছবিতে একটি চিত্র ক্যাপচার করার থেকে আলাদা করে তা হল দৃশ্যের গতিশীল পরিবর্তন এবং সম্পূর্ণরূপে উভয় দৃশ্যের আলো এবং চিত্রের অংশগুলি। এটি শুটিং প্রক্রিয়া চলাকালীন এক্সপোজার নিয়ন্ত্রণের উপায় নির্ধারণ করে।
ডিজিটাল ভিডিওতে, অপারেটরদের জন্য একটি কন্ট্রোল মনিটর মোড রয়েছে যেখানে অঞ্চলগুলির এক্সপোজার স্তরকে একটি সীমিত অঞ্চলে ম্যাপ করা হয়েছে, প্রতিটি তার নিজস্ব রঙে রঙিন।
এই মোডটিকে কখনও কখনও "শিকারী" বা মিথ্যা রঙের মোড বলা হয়। স্কেলগুলি সাধারণত IRE স্কেলে উল্লেখ করা হয়।
এই ধরনের মনিটর আপনাকে এক্সপোজার জোন দেখতে এবং ক্যামেরা শুটিং প্যারামিটার সেট করার সময় উল্লেখযোগ্য ভুলগুলি এড়াতে দেয়। ফটোগ্রাফিতে প্রকাশ করার সময় অর্থে অনুরূপ কিছু ব্যবহার করা হয় - উদাহরণস্বরূপ অ্যাডামস অনুসারে জোনিং।
আপনি একটি এক্সপোজার মিটার দিয়ে একটি নির্দিষ্ট লক্ষ্য পরিমাপ করতে পারেন এবং এটি কোন অঞ্চলে অবস্থিত তা দেখতে পারেন এবং বাস্তব সময়ে আমরা উপলব্ধির সহজতার জন্য সুন্দরভাবে রঙিন অঞ্চলগুলি দেখতে পাই।
জোনের সংখ্যা নিয়ন্ত্রণ মনিটরের উদ্দেশ্য এবং ক্ষমতা দ্বারা নির্ধারিত হয়। উদাহরণস্বরূপ, Arri Alexa ক্যামেরার সাথে ব্যবহৃত একটি মনিটর 6 টি জোন পর্যন্ত অন্তর্ভুক্ত করতে পারে।
উদাহরণের সাথে এগিয়ে যাওয়ার আগে, মেটাল টেক্সচারের মতো উত্স ডেটা প্রক্রিয়াকরণের জন্য একটি প্ল্যাটফর্ম হিসাবে OpenFXS বাস্তবায়নের জন্য আমাদের কিছু সাধারণ প্রক্সি ক্লাস যোগ করতে হবে। এই ক্লাস অন্তর্ভুক্ত:
imetalling::Image2 Texture : ক্লিপ বাফার থেকে মেটাল টেক্সচারে ডেটা স্থানান্তরের জন্য একটি ফাংশন। DaVinci থেকে, আপনি প্লাগইনে ইমেজ চ্যানেলের মানগুলির যেকোন কাঠামো এবং প্যাকেজিংয়ের একটি বাফার বের করতে পারেন এবং এটি একই আকারে ফেরত দেওয়া উচিত।
OFX-এ স্ট্রিম ফর্ম্যাটের সাথে কাজ করা সহজ করতে, আপনি হোস্টকে একটি নির্দিষ্ট ধরণের ডেটা আগে থেকে প্রস্তুত করার জন্য অনুরোধ করতে পারেন। আমি RGBA-তে প্যাক করা ফ্লোট ব্যবহার করব - লাল/সবুজ/নীল/আলফা।
আমরা OFXS বেস ক্লাসগুলি উত্তরাধিকার সূত্রে পাই এবং মেটাল কোর কীভাবে কাজ করে তার বিশদে না গিয়ে আমাদের কার্যকারিতা লিখি:
অতিরিক্তভাবে, MSL-এ হোস্ট কোড এবং কার্নেল কোডকে যৌক্তিকভাবে আলাদা করার জন্য আমাদের মেটালের উপরে নির্মিত বেশ কয়েকটি ইউটিলিটি ক্লাসের প্রয়োজন হবে। এর মধ্যে রয়েছে:
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.
এই ক্লাসে, আমরা একটি একক প্যারামিটার সেট করব - মনিটরের অবস্থা (হয় চালু বা বন্ধ)। এটি আমাদের উদাহরণের জন্য প্রয়োজনীয়।
আমরা OFX::PluginFactoryHelper
থেকে উত্তরাধিকারী হব এবং পাঁচটি পদ্ধতি ওভারলোড করব:
ImageEffectDescriptor
কোড পড়ুন।
describeInContext(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 - ব্যবহারকারীর দ্বারা একটি সম্পত্তি সম্পাদনা করা, প্লাগইন বা হোস্ট অ্যাপ্লিকেশনে পরিবর্তিত হওয়ার ফলে ঘটনাটি ঘটেছে, অথবা টাইমলাইনে পরিবর্তনের ফলে।
দ্বিতীয় প্যারামিটারটি স্ট্রিং নামটি নির্দিষ্ট করে যা আমরা প্লাগইন প্রারম্ভিক পর্যায়ে সংজ্ঞায়িত করেছি, আমাদের ক্ষেত্রে, এটি একটি প্যারামিটার: false_color_enabled_check_box ।
আপনি Interaction.cpp কোডে OFX এর সাথে ইন্টারেক্টিভ ইন্টারঅ্যাকশনের বাস্তবায়ন পড়তে পারেন। আপনি দেখতে পাচ্ছেন, আমরা ক্লিপগুলিতে পয়েন্টার পাই: উৎস এক এবং মেমরির এলাকা যেখানে আমরা লক্ষ্য রূপান্তর রাখব।
আমরা আরেকটি যৌক্তিক স্তর যোগ করব যার উপর আমরা রূপান্তর চালু করার জন্য সমস্ত যুক্তি সংজ্ঞায়িত করব। আমাদের ক্ষেত্রে, এটি এখন পর্যন্ত ওভাররাইড করার একমাত্র পদ্ধতি:
লঞ্চের পর্যায়ে, দরকারী বৈশিষ্ট্য সহ একটি বস্তু আমাদের কাছে উপলব্ধ হয়েছিল: আমাদের কাছে ভিডিও স্ট্রিমের কমপক্ষে একটি পয়েন্টার রয়েছে (আরও স্পষ্টভাবে, ফ্রেম চিত্র ডেটা সহ একটি মেমরি এলাকা), এবং, সবচেয়ে গুরুত্বপূর্ণভাবে, মেটাল কমান্ডের একটি সারি।
এখন, আমরা একটি জেনেরিক ক্লাস তৈরি করতে পারি যা আমাদের কার্নেল কোড পুনরায় ব্যবহার করার একটি সহজ ফর্মের কাছাকাছি নিয়ে আসবে। OpenFXS এক্সটেনশনের ইতিমধ্যেই এই ধরনের একটি ক্লাস রয়েছে: OFX::ImageProcessor; আমরা শুধু এটা ওভারলোড প্রয়োজন.
কনস্ট্রাক্টরে, এটির OFX::ImageEffect প্যারামিটার রয়েছে, অর্থাৎ, এতে, আমরা শুধুমাত্র প্লাগইন প্যারামিটারের বর্তমান অবস্থাই পাব না কিন্তু GPU-এর সাথে কাজ করার জন্য প্রয়োজনীয় সবকিছুই পাব।
এই পর্যায়ে, আমাদের শুধু processImagesMetal() পদ্ধতি ওভারলোড করতে হবে এবং ইতিমধ্যে মেটালে প্রয়োগ করা কার্নেলের প্রক্রিয়াকরণ শুরু করতে হবে।
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 প্যানেলে এটি খুঁজে পেতে এবং নির্বাচন করতে পারেন এবং এটি একটি নোড হিসাবে যোগ করতে পারেন।
বাহ্যিক লিঙ্ক