欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FFmpeg AVFrame变量的YUV Frame旋转

程序员文章站 2022-07-01 23:26:28
...

最近在用FFmpeg和DShow框架交互,在Frame的层面处理一些数据。

需要从DShow FIlter获取数据,然后用buffer初始化AVFrame,再交给FFmpeg的Filter处理。

我在Dshow Filter上做了输入输出格式的兼容处理,支持输入输出IYUV、YV12、NV12、RGB24、RGB32等五种格式。(其中RGB24格式的输入还是有点问题,做sws_scale转换的时候,会报内存读写错误,但偶尔却可以正常通过)

这个时候会发现,ffmpeg下用buffer初始化AVFrame数据的时候,如果是RGB色系的,会发生一些问题。

1.RGB24:上下颠倒、色差

2.RGB32:上下颠倒

对于DShow中的RGB24,FFmpeg实际应该用BGR24初始化AVFrame。否则输出的buffer数据使用RGB24色彩空间读取,会发生明显的色彩偏差。

对于所有RGB色彩,FFmpeg直接取出,都会发现图像是“上下颠倒”


我在做DShow交互的时候发现,如果输入输出都是RGB色彩空间,排除色差的问题(使用BGR24就解决了),“上下颠倒”的问题就不会产生。

因此,如何对于输入输出仅有一方是RGB色系的颠倒现象进行纠正,同时不过多的影响时间复杂度,是最主要需要解决的问题。

这篇博文,主要是借这个问题,描述一下如何在ffmpeg里面进行图像颠倒操作。


在面临需要进行图像旋转、反转操作的时候,通常还需要兼顾效率问题(时间复杂度、空间复杂度)。

如果不需要考虑上述问题,那么进行一次O(n)的逐字节拷贝,完全可以解决任意的旋转、反转问题。

不过,既然FFmpeg会存在RGB的倒转问题,那么就一定有可以高速便捷处理的办法。


首先,分析一下问题。存在使RGB发生倒转现象的操作,应该是av_image_fill_arrays填充Frame的操作。但同时也注意到,如果使用了sws_scale发生从RGB——YUV——RGB的时候,翻转就正常了。

因此,我尝试借助ffmpeg现成的函数进行一些高效的处理:

1.进行两次av_image_fill_arrays

2.进行两次sws_scale,获得正常的YUV

然而上述的操作全部都失败了


后来,经过不懈的查找,发现仅需要修改AVFrame的linesize属性,就可以让AVFrame在ffmpeg中的处理被视为图像反转。

    //关键是这一步,上下翻转图像
    pFrame_->data[0] += pFrame_->linesize[0] * (codec_->height - 1);
    pFrame_->linesize[0] = -pFrame_->linesize[0];
    pFrame_->data[1]+= pFrame_->linesize[1] * (codec_->height / 2 - 1);
    pFrame_->linesize[1] = -pFrame_->linesize[1];
    pFrame_->data[2] += pFrame_->linesize[2]* (codec_->height / 2 - 1);
    pFrame_->linesize[2] = -pFrame_->linesize[2];

   //图像翻转完之后回到正常的读写步骤     
    length = av_image_copy_to_buffer((unsigned char*)vopBuf, 640*480*4,
                                                (const uint8_t* const *)pFrame_->data, (const int*) pFrame_->linesize,
                                                codec_->pix_fmt, codec_->width, codec_->height, 1);