我尝试将rgb32图像转换为yuv420p以获取录制视频。
我有图片
QImage image = QGuiApplication::primaryScreen()->grabWindow(0, rect_x, rect_y, rect_width, rect_height).toImage().convertToFormat(QImage::Format_RGB32);
AVFrame *frame;
并转换
for (y = 0; y < c->height; y++) {
QRgb *rowData = (QRgb*)image.scanLine(y);
for (x = 0; x < c->width; x++) {
QRgb pixelData = rowData[x];
int r = qRed(pixelData);
int g = qGreen(pixelData);
int b = qBlue(pixelData);
int y0 = (int)(0.2126 * (float)(r) + 0.7152 * (float)(g) + 0.0722 * (float)(b));
int u = 128 + (int)(-0.09991 * (float)(r) - 0.33609 * (float)(g) + 0.436 * (float)(b));
int v = 128 + (int)(0.615 * (float)(r) - 0.55861 * (float)(g) - 0.05639 * (float)(b));
frame->data[0][y * frame->linesize[0] + x] = y0;
frame->data[1][y / 2 * frame->linesize[1] + x / 2] = u;
frame->data[2][y / 2 * frame->linesize[2] + x / 2] = v;
}
}
但是在结果图片中我看到了人工制品。文字外观混合http://joxi.ru/eAORRX0u4d46a2
转换alogritm或其他什么的这个错误?
UDP
for (y = 0; y < c->height; y++) {
QRgb *rowData = (QRgb*)image.scanLine(y);
for (x = 0; x < c->width; x++) {
QRgb pixelData = rowData[x];
int r = qRed(pixelData);
int g = qGreen(pixelData);
int b = qBlue(pixelData);
int y0 = (int)(0.2126 * (float)(r) + 0.7152 * (float)(g) + 0.0722 * (float)(b));
if (y0 < 0)
y0 = 0;
if (y0 > 255)
y0 = 255;
frame->data[0][y * frame->linesize[0] + x] = y0;
}
}
int x_pos = 0;
int y_pos = 0;
for (y = 1; y < c->height; y+=2) {
QRgb *pRow = (QRgb*)image.scanLine(y - 1);
QRgb *sRow = (QRgb*)image.scanLine(y);
for (x = 1; x < c->width; x+=2) {
QRgb pd1 = pRow[x - 1];
QRgb pd2 = pRow[x];
QRgb pd3 = sRow[x - 1];
QRgb pd4 = sRow[x];
int r = (qRed(pd1) + qRed(pd2) + qRed(pd3) + qRed(pd4)) / 4;
int g = (qGreen(pd1) + qGreen(pd2) + qGreen(pd3) + qGreen(pd4)) / 4;
int b = (qBlue(pd1) + qBlue(pd2) + qBlue(pd3) + qBlue(pd4)) / 4;
int u = 128 + (int)(-0.147 * (float)(r) - 0.289 * (float)(g) + 0.436 * (float)(b));
int v = 128 + (int)(0.615 * (float)(r) - 0.515 * (float)(g) - 0.1 * (float)(b));
if (u < 0)
u = 0;
if (v > 255)
v = 255;
frame->data[1][y_pos * frame->linesize[1] + x_pos] = u;
frame->data[2][y_pos * frame->linesize[2] + x_pos] = v;
x_pos++;
}
x_pos = 0;
y_pos++;
}
这项工作适合我,但它的速度很慢,一帧60-70毫秒
答案 0 :(得分:3)
第一个问题是你让你的YUV值超出允许范围(甚至比0x00..0xFF更严格。但是你无论如何都不做任何封顶)。 See:
Y'值通常被移位并缩放到范围[16,235](称为工作室摇摆或“电视水平”),而不是使用[0,255]的全范围(称为全摆或“个人电脑水平”)。这种令人困惑的做法源于MPEG标准,并解释了为什么16被添加到Y'以及为什么基本变换中的Y'系数总和为220而不是255. [8] U和V值(可以是正数或负数)与128相加以使它们始终为正,为U和V提供16-240的工作室范围。(这些范围在视频编辑和制作中很重要,因为使用了错误范围将导致带有“剪裁”黑色和白色的图像,或低对比度图像。)
第二个问题是4:2:0意味着每个像素最终得到一个Y值,每四个像素得到一个U和一个V值。也就是说,U和V应该是相应像素的平均值,你的循环只是用第四个输入像素的U和V覆盖这些值,忽略前三个。
您使用ffmpeg标记了问题,之前的问题也与FFmpeg相关。请注意,FFmpeg提供swscale库,与您可以添加的循环和优化相比,sws_scale
更有效地执行转换方式。请参阅有关SO的相关问题: