You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AE插件中使用Cairo的CAIRO_FORMAT_RGBA128F实现32位色彩输出

适配CAIRO_FORMAT_RGBA128F的After Effects插件代码改写

首先明确核心差异:

  • CAIRO_FORMAT_RGBA128F每个像素由**4个64位浮点数(double)**组成,顺序为R, G, B, A,分量范围0.0~1.0
  • 需要切换使用After Effects的PF_PixelFloat类型处理32位浮点色彩通道,避免精度损失
  • 内存访问必须严格对齐,否则会触发崩溃

改写后的完整代码

// 针对浮点像素的采样函数,返回PF_PixelFloat指针
PF_PixelFloat* sampleIntegralFloat(PF_EffectWorld& def, int x, int y) {
    return reinterpret_cast<PF_PixelFloat*>(
        reinterpret_cast<char*>(def.data) +
        (y * def.rowbytes) +
        (x * sizeof(PF_PixelFloat))
    );
}

PF_Err cairoCopyRGBA128F(void* refcon, A_long threadInd, A_long itemNum, A_long iterTotal) {
    cairoRefcon* data = reinterpret_cast<cairoRefcon*>(refcon);
    int rowIdx = static_cast<int>(itemNum);
    PF_Err err = PF_Err_NONE;

    // 确保输出是浮点格式的PF_EffectWorld
    if (data->output.pixel_format != PF_PixelFormat_FLOAT32) {
        return PF_Err_BAD_FORMAT;
    }

    // Cairo RGBA128F的行指针:每个像素是4个double,顺序R/G/B/A
    double* cairoRowPtr = reinterpret_cast<double*>(
        data->data + rowIdx * data->stride
    );
    // AE输出的行指针
    PF_PixelFloat* aeRowPtr = sampleIntegralFloat(data->output, 0, rowIdx);

    const int width = static_cast<int>(data->output.width);
    for (int x = 0; x < width; ++x) {
        // 读取Cairo的浮点分量
        double cairoR = cairoRowPtr[x * 4 + 0];
        double cairoG = cairoRowPtr[x * 4 + 1];
        double cairoB = cairoRowPtr[x * 4 + 2];
        double cairoA = cairoRowPtr[x * 4 + 3];

        // 处理预乘/非预乘转换(与原8位代码逻辑保持一致)
        if (cairoA > 1e-6) { // 避免除以极小值
            aeRowPtr[x].red = static_cast<float>(cairoR / cairoA);
            aeRowPtr[x].green = static_cast<float>(cairoG / cairoA);
            aeRowPtr[x].blue = static_cast<float>(cairoB / cairoA);
        } else {
            aeRowPtr[x].red = aeRowPtr[x].green = aeRowPtr[x].blue = 0.0f;
        }
        aeRowPtr[x].alpha = static_cast<float>(cairoA);

        // 约束AE浮点通道值在有效范围(0.0~1.0)
        aeRowPtr[x].red = std::clamp(aeRowPtr[x].red, 0.0f, 1.0f);
        aeRowPtr[x].green = std::clamp(aeRowPtr[x].green, 0.0f, 1.0f);
        aeRowPtr[x].blue = std::clamp(aeRowPtr[x].blue, 0.0f, 1.0f);
        aeRowPtr[x].alpha = std::clamp(aeRowPtr[x].alpha, 0.0f, 1.0f);
    }

    return err;
}

关键注意事项(崩溃排查要点)

  • 输出格式初始化:必须在插件的SetRenderFormat或初始化阶段,将output的pixel_format设置为PF_PixelFormat_FLOAT32,否则内存访问会错位崩溃
  • Cairo Surface创建:创建RGBA128F表面时,必须使用正确的stride,推荐直接让Cairo计算:
    cairo_surface_t* surface = cairo_image_surface_create(
        CAIRO_FORMAT_RGBA128F,
        width,
        height
    );
    int stride = cairo_image_surface_get_stride(surface);
    
  • 内存对齐:RGBA128F要求内存按8字节对齐,Cairo创建的surface会自动满足,但如果是手动分配内存,必须使用aligned_alloc或平台对齐函数
  • 线程安全:AE的线程回调按行分配任务,只要保证每行数据独立访问,就不会出现线程冲突问题

内容的提问来源于stack exchange,提问作者Rich95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 15:47:12