正确的 AVFrame RGB 值

Posted

技术标签:

【中文标题】正确的 AVFrame RGB 值【英文标题】:Correct RGB values for AVFrame 【发布时间】:2022-01-11 18:48:23 【问题描述】:

我必须从 cairo 表面像素数据中填充 ffmpeg AVFrame->数据。我有这个代码:

/* Image info and pixel data */
width  = cairo_image_surface_get_width( surface );
height = cairo_image_surface_get_height( surface );
stride = cairo_image_surface_get_stride( surface );
pix    = cairo_image_surface_get_data( surface );

for( row = 0; row < height; row++ )

    data = pix + row * stride;
    for( col = 0; col < width; col++ )
    
        img->video_frame->data[0][row * img->video_frame->linesize[0] + col] = data[0];
        img->video_frame->data[1][row * img->video_frame->linesize[1] + col] = data[1];
        //img->video_frame->data[2][row * img->video_frame->linesize[2] + col] = data[2];
        data += 4;
    
    img->video_frame->pts++;

但是导出的视频中的颜色是错误的。原来的心是红色的。有人可以指出我正确的方向吗?遗憾的是,encode.c 示例毫无用处,并且在 Internet 上存在很多关于 Y、Cr 和 Cb 的混淆,我真的不明白。请随时询问更多详情。非常感谢。

【问题讨论】:

能否请您发布一个完整的代码示例 - 我们可以编译和执行的东西?您可能需要有创意 - 考虑将 8x8 输入图像发布为 C 数组(由代码初始化)。你能描述一下pix 的数据排列吗(是widthheightstride 的行主要RGBA)吗? YCbCr像素格式在哪一部分使用? 非常感谢您的回复。我很感激。该代码是 GTK3 GUI 的一部分,它将一系列图片转换为电影。这是我自 2009 年以来一直在开发的项目。遗憾的是,我无法提供代码 sn-p,但该软件是开源的。 cairo 表面为 RGB24。 AV 上下文创建为 AV_PIX_FMT_YUV420P,因为如果我使用 AV_PIX_FMT_RGB24,我会在编码期间收到错误消息:“输入宽度大于步幅”。希望这会有所帮助,请随时询问更多信息。 我目前对 YCbCr 的理解是它是由 Luminance/Red-diff/Blue-diff 组成的,其中 Luminance 是亮度,Red-diff 和 Blue-diff 是色度值,带有关于 Red/green 的信息和蓝/绿分别。它通过将黑白图像与两个色度通道相结合来工作 【参考方案1】:

您需要使用libswscale将源图像数据从RGB24转换为YUV420P

类似:

int width  = cairo_image_surface_get_width( surface );
int height = cairo_image_surface_get_height( surface );
int stride = cairo_image_surface_get_stride( surface );
uint8_t *pix = cairo_image_surface_get_data( surface );

uint8_t *data[1] =  pix ;
int linesize[1]  =  stride ;

struct SwsContext *sws_ctx = sws_getContext(width, height, AV_PIX_FMT_RGB24 ,
                                            width, height, AV_PIX_FMT_YUV420P,
                                            SWS_BILINEAR, NULL, NULL, NULL);

sws_scale(sws_ctx, data, linesize, 0, height, 
          img->video_frame->data, img->video_frame->linesize);

sws_freeContext(sws_ctx);

在此处查看示例:scaling_video

【讨论】:

感谢您的回复。我还使用了 sws_scale,在编码过程中没有错误,但视频甚至无法播放,VLC 在终端窗口中显示了一堆这些无用的消息:[h264 @ 0x7f1508c82700] 位于 POC 不可用 [h264 @ 0x7f1508c9f400] mmco: unref short失败 [h264 @ 0x7f1508cd8f80] 位于 POC 不可用 该示例没有帮助,因为它从 YUV420P 转换,但感谢我很感激。如果您想了解更多信息,我可以将更改提交到 SVN 服务器,您可以看看,它是一个不错的 GUI 和一个不错的软件,可惜被低估了。 @GiuTor 您能否将示例 cairo 图像转储到某个文件并发布格式、宽度和高度? 这段代码对于转储图像是否正确: /* 图像信息和像素数据 */ width = cairo_image_surface_get_width(surface);高度 = cairo_image_surface_get_height( 表面 ); stride = cairo_image_surface_get_stride(surface); pix = cairo_image_surface_get_data(表面);文件 *fp = fopen("cairo_image.raw","w"); fwrite (pix, 4*width, sizeof(pix), fp); fclose(fp);

以上是关于正确的 AVFrame RGB 值的主要内容,如果未能解决你的问题,请参考以下文章

Fffmpeg:从AVFrame中由YUV获取RGB

AVFrame转换到Mat,yuv420p转换到RGB

如何获得具有 GD 的像素的正确 rgb 值?

如何正确地从 RGB 值初始化 UIColor?

如何将像素格式为 AV_PIX_FMT_CUDA 的 FFmpeg AVFrame 转换为像素格式为 AV_PIX_FMT_RGB 的新 AVFrame

将 AVFrame 转换为 RGB32 时在 sws_scale 处崩溃