OFX 이미지 처리 API 라고도 알려진 OFX는 2D 시각 효과 및 비디오 합성을 생성하기 위한 개방형 표준입니다. 플러그인과 유사한 애플리케이션 개발 모델에서 작동합니다. 기본적으로 호스트(메서드 세트를 제공하는 애플리케이션)와 플러그인(이 세트를 구현하는 애플리케이션 또는 모듈) 역할을 모두 수행합니다.
이 구성은 호스트 응용 프로그램 기능을 무제한으로 확장할 수 있는 가능성을 제공합니다.
버전 16부터 Final Cut X 및 DaVinci Resolve Studio와 같은 애플리케이션은 Apple Metal 파이프라인을 완벽하게 지원합니다. OpenCL 및 Cuda와 유사하게 OFX의 경우 플랫폼별 명령 대기열의 설명자 또는 처리기를 얻을 수 있습니다. 또한 호스트 시스템은 이러한 대기열 풀을 할당하고 이에 대한 계산 균형을 조정하는 역할을 담당합니다.
또한 소스 및 대상 이미지 클립 데이터를 GPU 메모리에 배치하여 확장 가능한 기능 개발을 크게 단순화합니다.
Resolve를 사용하면 상황이 약간 더 복잡해집니다. DaVinci는 일부 제한 사항이 있지만 OFX v1.4에 대한 지원을 발표했습니다. 특히, 인터페이스 기능 작업을 위한 일부 방법을 사용할 수 없습니다. 어떤 방법을 사용할 수 있는지 확인하기 위해 OFX를 사용하면 키/값 쿼리를 통해 지원되는 제품군을 검사할 수 있습니다.
플러그인 코드의 게시 방법은 C 호출을 기반으로 합니다. 하지만 우리는 C++17에 맞춰진 OpenFXS C++ 셸을 사용할 것입니다. 편의상 모든 것을 하나의 저장소로 컴파일했습니다: dehancer-external 오픈 소스 Dehancer 프로젝트 에서 가져온 것입니다.
이 프로젝트에서는 원래 Bruno Nicoletti 가 작성했으며 시간이 지나면서 상업 및 오픈 소스 비디오 처리 프로젝트에서 인기를 얻은 OpenFX의 C++ 확장인 OpenFXS를 사용할 것입니다.
원래 OpenFXS는 최신 C++ 언어에 적합하지 않았기 때문에 C++17 과 호환되도록 업데이트했습니다.
OFX, 즉 OFXS는 호스트 프로그램에 의해 동적으로 로드되는 독립형 소프트웨어 모듈입니다. 기본적으로 이는 기본 애플리케이션이 시작될 때 로드되는 동적 라이브러리입니다. OFX와 마찬가지로 OpenFXS는 메서드 서명을 게시해야 합니다. 따라서 우리는 코드에서 하나의 C 메서드를 사용합니다.
OpenFXS에서 개발을 시작하려면 애플리케이션에서 새로운 기능을 생성하는 데 사용되는 몇 가지 공통 클래스 세트에 동의해야 합니다. 일반적으로 새 프로젝트에서는 이러한 클래스를 상속하고 일부 가상 메서드를 구현하거나 재정의해야 합니다.
호스트 시스템에서 자신만의 플러그인을 만들려면 먼저 다음 공개 클래스와 동일한 방법을 숙지해 보겠습니다.
비디오 촬영 과정과 단순히 사진 속 이미지를 캡처하는 과정을 구별하는 한 가지 특징은 장면의 역동적인 변화와 두 장면 전체 및 이미지 내 영역의 조명입니다. 이는 촬영 과정에서 노출이 제어되는 방식을 결정합니다.
디지털 비디오에는 영역의 노출 수준이 제한된 영역 세트로 매핑되고 각각 고유한 색상으로 착색되는 운영자를 위한 제어 모니터 모드가 있습니다.
이 모드는 "프레데터" 또는 가색상 모드라고도 합니다. 척도는 일반적으로 IRE 척도를 참조합니다.
이러한 모니터를 사용하면 노출 영역을 확인하고 카메라 촬영 매개변수를 설정할 때 심각한 실수를 피할 수 있습니다. 예를 들어 Adams에 따른 구역 지정과 같이 사진에 노출할 때 비슷한 의미가 사용됩니다.
노출계를 사용하여 특정 대상을 측정하고 해당 대상이 어느 구역에 있는지 확인할 수 있으며 실시간으로 인식하기 쉽도록 깔끔하게 착색된 구역을 볼 수 있습니다.
영역 수는 제어 모니터의 목표와 기능에 따라 결정됩니다. 예를 들어 Arri Alexa 카메라와 함께 사용되는 모니터는 최대 6개 구역을 통합할 수 있습니다.
예제를 진행하기 전에 OpenFXS를 Metal 텍스처와 같은 소스 데이터 처리용 플랫폼으로 구현하기 위해 몇 가지 간단한 프록시 클래스를 추가해야 합니다. 이러한 수업에는 다음이 포함됩니다.
imetalling::Image2Texture : 클립 버퍼의 데이터를 Metal 텍스처로 전송하기 위한 기능자입니다. DaVinci에서는 이미지 채널 값의 모든 구조와 패키징의 버퍼를 플러그인으로 추출할 수 있으며 유사한 형식으로 반환되어야 합니다.
OFX에서 스트림 형식 작업을 더 쉽게 하기 위해 호스트에 특정 유형의 데이터를 미리 준비하도록 요청할 수 있습니다. RGBA(빨간색/녹색/파란색/알파)로 포장된 부동 소수점을 사용하겠습니다.
OFXS 기본 클래스를 상속하고 Metal 코어 작동 방식을 자세히 설명하지 않고 기능을 작성합니다.
또한 MSL에서 호스트 코드와 커널 코드를 논리적으로 분리하려면 Metal 위에 구축된 여러 유틸리티 클래스가 필요합니다. 여기에는 다음이 포함됩니다.
imetalling::FalseColorKernel : 지정된 색상 수로 포스터화(다운샘플링)하는 "프레데터" 에뮬레이터인 주요 기능 클래스입니다.
"predator" 모드의 커널 코드는 다음과 같습니다:
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
코드를 참조하세요.
explainInContext(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와의 대화형 상호 작용 구현을 읽을 수 있습니다. 보시다시피, 우리는 클립에 대한 포인터(소스 클립과 대상 변환을 넣을 메모리 영역)를 받습니다.
변환을 시작하기 위한 모든 논리를 정의할 또 다른 논리 계층을 추가하겠습니다. 우리의 경우 지금까지 재정의하는 유일한 방법은 다음과 같습니다.
출시 단계에서 유용한 속성을 가진 개체를 사용할 수 있게 되었습니다. 최소한 비디오 스트림에 대한 포인터(보다 정확하게는 프레임 이미지 데이터가 있는 메모리 영역)와 가장 중요한 것은 Metal 명령 대기열이 있습니다.
이제 커널 코드를 재사용하는 간단한 형태에 더 가까워지는 일반 클래스를 구성할 수 있습니다. OpenFXS 확장에는 이미 OFX::ImageProcessor와 같은 클래스가 있습니다. 우리는 그것을 오버로드하면 됩니다.
생성자에는 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 패널에서 찾아 선택하고 노드로 추가할 수 있습니다.
외부 링크