rendering still not correct

This commit is contained in:
2026-04-19 18:59:56 +08:00
parent 3b5b0187cb
commit f3c50017e9
8 changed files with 2790 additions and 35 deletions
+85 -25
View File
@@ -703,8 +703,13 @@ static olive::AVFramePtr create_avframe_from_ofx_image(OFX::Host::ImageEffect::I
return frame;
}
// 作用:按指定 VideoParams 复制 OFX Image 到 AVFrame
// Purpose: Copy OFX Image data into an AVFrame using target VideoParams.
// 前置声明:必要时将 AVFrame 转换为目标 VideoParams 对应格式
// Forward declaration: Convert AVFrame to match destination VideoParams when needed.
static olive::AVFramePtr ConvertFrameIfNeeded(olive::AVFramePtr src,
const olive::VideoParams &dst_params);
// 作用:按指定 VideoParams 复制 OFX Image 到 AVFrame,必要时做格式转换。
// Purpose: Copy OFX Image data into an AVFrame using target VideoParams with format conversion.
static olive::AVFramePtr create_avframe_from_ofx_image_with_params(
OFX::Host::ImageEffect::Image &image,
const olive::VideoParams &params)
@@ -722,25 +727,74 @@ static olive::AVFramePtr create_avframe_from_ofx_image_with_params(
return nullptr;
}
// Get ACTUAL source format from image properties
std::string image_depth = image.getStringProperty(kOfxImageEffectPropPixelDepth);
std::string image_comp = image.getStringProperty(kOfxImageEffectPropComponents);
int src_channel_count = 4;
if (image_comp == kOfxImageComponentRGB) src_channel_count = 3;
else if (image_comp == kOfxImageComponentAlpha) src_channel_count = 1;
int src_bytes_per_component = 1;
if (image_depth == kOfxBitDepthShort) src_bytes_per_component = 2;
else if (image_depth == kOfxBitDepthHalf) src_bytes_per_component = 2;
else if (image_depth == kOfxBitDepthFloat) src_bytes_per_component = 4;
const int src_bytes_per_pixel = src_channel_count * src_bytes_per_component;
const int dst_bytes_per_pixel = params.channel_count() * params.format().byte_count();
int row_bytes = image.getIntProperty(kOfxImagePropRowBytes);
if (row_bytes <= 0) {
row_bytes = width * src_bytes_per_pixel;
}
uint8_t *src = static_cast<uint8_t *>(data_ptr);
src += bounds[1] * row_bytes + bounds[0] * src_bytes_per_pixel;
// Check if format conversion is needed
bool needs_conversion = (src_bytes_per_pixel != dst_bytes_per_pixel) ||
(src_channel_count != params.channel_count());
if (needs_conversion) {
// Create source frame with actual format
AVPixelFormat src_fmt = AV_PIX_FMT_NONE;
if (src_channel_count == 4) {
if (src_bytes_per_component == 1) src_fmt = AV_PIX_FMT_RGBA;
else if (src_bytes_per_component == 2) src_fmt = AV_PIX_FMT_RGBA64LE;
else if (src_bytes_per_component == 4) src_fmt = AV_PIX_FMT_RGBAF32LE;
} else if (src_channel_count == 3) {
if (src_bytes_per_component == 1) src_fmt = AV_PIX_FMT_RGB24;
else if (src_bytes_per_component == 2) src_fmt = AV_PIX_FMT_RGB48LE;
else if (src_bytes_per_component == 4) src_fmt = AV_PIX_FMT_RGBF32LE;
} else if (src_channel_count == 1) {
if (src_bytes_per_component == 1) src_fmt = AV_PIX_FMT_GRAY8;
else if (src_bytes_per_component == 2) src_fmt = AV_PIX_FMT_GRAY16LE;
else if (src_bytes_per_component == 4) src_fmt = AV_PIX_FMT_GRAYF32LE;
}
if (src_fmt != AV_PIX_FMT_NONE) {
olive::AVFramePtr src_frame = olive::CreateAVFramePtr();
src_frame->width = width;
src_frame->height = height;
src_frame->format = src_fmt;
if (av_frame_get_buffer(src_frame.get(), 0) >= 0) {
// Copy source data row by row
for (int y = 0; y < height; ++y) {
memcpy(src_frame->data[0] + y * src_frame->linesize[0],
src + y * row_bytes, width * src_bytes_per_pixel);
}
// Convert to destination format
return ConvertFrameIfNeeded(src_frame, params);
}
}
}
// Same format - direct copy
AVPixelFormat pix_fmt = GetDestinationAVPixelFormat(params);
if (pix_fmt == AV_PIX_FMT_NONE) {
return nullptr;
}
const int bytes_per_pixel =
params.channel_count() * params.format().byte_count();
if (bytes_per_pixel <= 0) {
return nullptr;
}
int row_bytes = image.getIntProperty(kOfxImagePropRowBytes);
if (row_bytes <= 0) {
row_bytes = width * bytes_per_pixel;
}
uint8_t *src = static_cast<uint8_t *>(data_ptr);
src += bounds[1] * row_bytes + bounds[0] * bytes_per_pixel;
olive::AVFramePtr frame = olive::CreateAVFramePtr();
frame->width = width;
frame->height = height;
@@ -750,11 +804,10 @@ static olive::AVFramePtr create_avframe_from_ofx_image_with_params(
return nullptr;
}
const int copy_bytes = width * bytes_per_pixel;
const int copy_bytes = width * std::min(src_bytes_per_pixel, dst_bytes_per_pixel);
for (int y = 0; y < height; ++y) {
std::memcpy(frame->data[0] + y * frame->linesize[0],
src + y * row_bytes,
copy_bytes);
memcpy(frame->data[0] + y * frame->linesize[0],
src + y * row_bytes, copy_bytes);
}
return frame;
@@ -1496,10 +1549,7 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
input_tex->handleFrame(ptr);
}
if (is_usable_input(input_tex)) {
input_textures[entry.first] = input_tex;
// First set the input texture (updates params_)
input_clip->setInputTexture(input_tex, frame);
// Then get the bitdepth/component from the instance
// Determine the plugin's preferred format for this clip
std::string bitdepth = input_clip->getUnmappedBitDepth();
std::string component = input_clip->getUnmappedComponents();
VideoParams params = input_tex->params();
@@ -1510,7 +1560,17 @@ void olive::plugin::PluginRenderer::RenderPlugin(TexturePtr src, olive::plugin::
if (!component.empty() && component != kOfxImageComponentNone) {
params.set_channel_count(component);
}
ConvertTextureForParams(input_tex, params);
// Convert the texture to the plugin's preferred format BEFORE
// setting it on the clip, so the OFX Image receives correctly
// formatted pixel data.
TexturePtr converted_tex =
ConvertTextureForParams(input_tex, params);
if (converted_tex && is_usable_input(converted_tex)) {
input_tex = converted_tex;
}
input_textures[entry.first] = input_tex;
// Now set the (possibly converted) texture on the clip
input_clip->setInputTexture(input_tex, frame);
OfxRectD rod;
rod.x1 = 0;
rod.y1 = 0;