YUV420p 中的 RGB32

RGB32 in YUV420p

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

第一个问题是您让 YUV 值超出了允许的范围(这甚至比 0x00..0xFF 更严格。但是您无论如何都不做任何上限)。 See:

Y' values are conventionally shifted and scaled to the range [16, 235] (referred to as studio swing or "TV levels") rather than using the full range of [0, 255] (referred to as full swing or "PC levels"). This confusing practice derives from the MPEG standards and explains why 16 is added to Y' and why the Y' coefficients in the basic transform sum to 220 instead of 255.[8] U and V values, which may be positive or negative, are summed with 128 to make them always positive, giving a studio range of 16–240 for U and V. (These ranges are important in video editing and production, since using the wrong range will result either in an image with "clipped" blacks and whites, or a low-contrast image.)

第二个问题是4:2:0意味着每个像素有一个Y值,每四个像素有一个U值和一个V值。也就是说,U 和 V 应该是相应像素的平均值,您的循环只是用第四个输入像素的 U 和 V 覆盖值,忽略前三个。

您用 标记了问题,您之前的问题也与 FFmpeg 相关。请注意,FFmpeg 提供了 swscale 库,sws_scale 与您的循环和您可以添加的优化相比,它可以更有效地进行转换。在 SO 上查看相关问题:

  • avcodec YUV to RGB
  • Video from pipe->YUV with libAV->RGB with sws_scale->Draw with Qt