【问题标题】:Writing alpha channel into decoded ffmpeg frame将 alpha 通道写入解码的 ffmpeg 帧
【发布时间】:2016-12-21 10:09:17
【问题描述】:

我正在寻找一种将我自己的 alpha 通道添加到解码的 ffmpeg 帧的快速方法。

我有一个包含 RGB 信息的 AVI 文件,并且我有一个描述透明度 Alpha 通道(灰度)的同步视频流。在使用 ffmpeg 解码 AVI 文件时,我想将输出帧转换为 RGBA,同时添加我自己的 alpha 信息。最后,我会得到一个半透明的视频流。

是否有任何优化函数(可能在 libswscale 或 libswresample 中)比仅通过像素迭代做得更好?

如果我有sws_scale_and_add_alpha这样的函数,基本上我希望能够编写这样的函数:

void* FFmpegLib_nextFrame_withAlpha(void* _handle, uint8_t* my_alpha_channel)
{
    FFmpegLibHandle* handle = (FFmpegLibHandle*)_handle;
    AVPacket        packet;
    int             frameFinished;

    while(av_read_frame(handle->pFormatCtx, &packet) >= 0) {
        // Is this a packet from the video stream?
        if(packet.stream_index==handle->videoStream) {
            // Decode video frame
            avcodec_decode_video2(handle->pCodecCtx, handle->pFrame, &frameFinished, &packet);
            // Did we get a video frame?
            if(frameFinished) {
                sws_scale_and_add_alpha
                (
                    handle->sws_ctx,
                    (uint8_t const * const *)handle->pFrame->data,
                    handle->pFrame->linesize,
                    0,
                    handle->pCodecCtx->height,
                    handle->pFrameARGB->data,
                    handle->pFrameARGB->linesize,
                    my_alpha_channel
                );

                return handle->pFrameARGB->data;
            }
        }
    }

    return NULL;
}

【问题讨论】:

    标签: c ffmpeg video-streaming


    【解决方案1】:

    我想了两种方法来做到这一点。通常如果我想在命令行中合并一个 alpha 通道,ffmpeg 会为此提供一个alphamerge 过滤器。而且我很确定你可以在 C 中做同样的事情,尽管它可能很难编程,(即使在 ffmpeg 源代码中有一个视频过滤器示例。)。

    第二个是我们自己编码,针对 AVFrame 结构。 AVFrame 的 data 字段保存像素信息。我们需要将我们的 alpha 通道打包进去。

    首先像往常一样将压缩的图像帧转换为打包的 ARGB

    // pFrameARGB should have been allocated and of pix_fmt `AV_PIX_FMT_ARGB`
    sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, height, pFrameARGB->data, pFrameARGB->linesize);
    

    AVFrame.data 是一个包含不同平面的多维数组。这里我们有一个压缩的 ARGB 图像,而不是平面图像,因此 data[0] 包含我们需要的所有像素。

    // cpp example, easy to convert to pure C
    auto p = pFrameARGB->data[0];
    for (auto i = 0; i < width * height; i++) {
        auto num = i * sizeof(uint8_t) * 4;
        auto div_result = std::div(num, width * sizeof(uint8_t) * 4);
    
        auto offset = pFrameARGB->linesize * div_result.quot + div_result.rem;
        p[offset] = my_alpha_channel[i];
    }
    

    【讨论】:

    • 谢谢@halfelf。我看到了 alphamerge 示例,甚至潜入了 c 实现。实际上,它有点像您的第二个编程选项,因为它循环遍历 argb 图像像素。出于性能原因,我希望一次性完成,例如使用 sws_scale 的替代品,它可以同时转换和添加 alpha 通道。实际上最后,我使用 rgb 和 alpha 通道作为 OpenGL 着色器的纹理,所以看起来最好和最并行的选项是在着色器中结合颜色和透明度。
    • @Mic 很高兴听到这个消息。其实我以前在CUDA中做过类似的事情。我相信它的性能和OpenGL一样好。
    猜你喜欢
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多