我正在尝试从avframe直接计算rgb缓冲区。由于获得的图像错误,所以出现了一些问题。从AVFrame-〉data[0]提取灰色图像工作正常。但我无法提取彩色图像
inline void YCrCb_to_RGB8(int Y, int Cr, int Cb, int& R, int& G, int& B){
R = (int)(Y + 1.402 *(Cr - 128));
G = (int)(Y - 0.344136*(Cb-128) -0.71414*(Cr-128));
B = (int)(Y + 1.772 *(Cb-128));
if (R < 0) R = 0; else if (R > 255) R = 255;
if (G < 0) G = 0; else if (G > 255) G = 255;
if (B < 0) B = 0; else if (B > 255) B = 255;
}
int getRGB8buffer(AVFrame* pFrame, byte* buffer){
const int width = pFrame->width, height = pFrame->height;
int Y, Cr, Cb;
int R, G, B;
int pixel = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Y = pFrame->data[0][x + y * width];
Cr = pFrame->data[1][x / 2 + ((int)(y / 2)) * pFrame->linesize[1]];
Cb = pFrame->data[2][x / 2 + ((int)(y / 2)) * pFrame->linesize[2]];
YCrCb_to_RGB8(Y, Cr, Cb, R, G, B);
buffer[pixel * 3 + 0] = R;
buffer[pixel * 3 + 1] = G;
buffer[pixel * 3 + 2] = B;
pixel++;
}
}
return 0;
}
当我使用将获得的图像保存为ppm时
int save_RGB_frame(unsigned char* buf, int wrap, int xsize,int ysize, const char* filename){
FILE* f;
int i;
f = fopen(filename, "w");
// portable ppm format -> https://en.wikipedia.org/wiki/Netpbm#PPM_example
fprintf(f, "P6\n%d %d\n%d\n", xsize, ysize, 255);
// writing line by line
for (i = 0; i < ysize; i++)
fwrite(buf + i * wrap, 1, xsize*3, f);
fclose(f);
return 0;
}
结果图像与结果图像https://github.com/hacenesh/ffmpeg_question/blob/main/img_2028144.ppm的链接错误
1条答案
按热度按时间wwtsj6pe1#
主要问题是使用
fopen(filename, "w")
而不是f = fopen(filename, "wb")
。在Windows操作系统中,二进制文件和文本文件之间有一个重要的区别。
默认的
"w"
选项将文件作为文本文件打开。写入文本文件时,每个新行字符
\n
转换为两个字符\r\n
。额外的字符打乱了图像的整个结构。
注意:如果您使用的是Linux,
"wb"
和"w"
应该是相同的。纠正了
save_RGB_frame
的代码:保存到PPM图像文件:
getRGB8buffer
中的问题:YUV 420 p格式的平面顺序是
Y
、U
、V
。U
应用Cb
,V
应用Cr
,因此顺序为:一米十六英寸,一米十七英寸,一米十八英寸。纠正了
getRGB8buffer
的代码:YCrCb_to_RGB8
中的问题:您问题中的转换公式采用JPEG转换公式。
FFmpeg默认使用的换算公式采用BT.601“有限范围”换算公式。
在“有限范围”中,Y范围为[16,235],与“全范围”[0,255]相对。
与“全范围”(PC范围/ JPEG范围)相比,使用“有限范围”(“TV范围”)更为常见。
BT.601对于高清视频来说可能没有BT.709那么常见,但是BT.601是FFmpeg默认转换(我们将坚持使用BT.601)。
注:我们这里使用的换算公式与MATLAB函数ycbcr2rgb相同。