YUV420p中的RGB32

时间:2016-03-17 11:45:19

标签: ffmpeg rgb yuv qimage libavcodec

我尝试将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毫秒

1 个答案:

答案 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覆盖这些值,忽略前三个。

enter image description here

您使用标记了问题,之前的问题也与FFmpeg相关。请注意,FFmpeg提供swscale库,与您可以添加的循环和优化相比,sws_scale更有效地执行转换方式。请参阅有关SO的相关问题: