将 V4L2_PIX_FMT_YUYV(YUV 4:2:2) 转换为 V4L2_PIX_FMT_YVU420(YUV 4:2:0)

Convert V4L2_PIX_FMT_YUYV(YUV 4:2:2) to V4L2_PIX_FMT_YVU420(YUV 4:2:0)

我一直在尝试用 C++ 将 YUYV 原始文件转换为 YUV420 原始文件。格式记录在 YUV Formats Page. My output file shows a greenish look after conversion. I adopted the source code from Experts Exchange 中,以从 YUYV 而不是 UYVY 转换。这是我的源代码:

void conv422to420(uint8_t* src, uint8_t* dst)
{
  uint8_t* pyFrame = dst;
  uint8_t* puFrame = pyFrame + width_*height_; // Cb
  uint8_t* pvFrame = puFrame + width_*height_/4; // Cr

  int uvOffset = width_ * 2 * sizeof(uint8_t);

  int i,j;

  for(i=0; i<height_-1; i++)
  {
    for(j=0; j<width_; j+=2)
    {
        auto evenRow = ((i&1) == 0);
        *pyFrame++ = *src++;
        ++src;
        uint16_t calc;
        if (evenRow)
        {
            calc = *src;
            calc += *(src + uvOffset);
            calc /= 2;
            *pvFrame++ = (uint8_t) calc;
        }
        *pyFrame++ = *src++;
        ++src;
        if (evenRow)
        {
            calc = *src;
            calc += *(src + uvOffset);
            calc /= 2;
            *puFrame++ = (uint8_t) calc;
        }
    }
  }
}

一般我取YUYV中相邻两行的两个U值和两个V值的平均值作为YUV420中的值。我只是不确定 "averaging it" 是否是执行此操作的正确方法。因为我用了

ffmpeg -y -r 25.0 -f rawvideo -s 1280x720 -pix_fmt yuyv422 -i yuyv422.yuv -pix_fmt yuv420p -f rawvideo -r 25.0 -s 1280x720 -v debug yuv420p.yuv

成功生成 YUV420 原始文件,我自己的输出文件的差异与在 U 和 Y 通道中生成的一个 ffmpeg 完全不同。

所以我的问题是,这种转换有没有开源解决方案?我的解决方案有什么问题?

经过几次调试,结果是一个小问题:我应该在分配 U V 值后增加 src 指针。这是代码:

uint8_t* pyFrame = dst;
uint8_t* puFrame = pyFrame + width_*height_* sizeof(uint8_t); // Cb
uint8_t* pvFrame = puFrame + width_*height_* sizeof(uint8_t)/4; // Cr

int uvOffset = width_ * 2 * sizeof(uint8_t);

int i,j;

for(i=0; i<height_-1; i++)
{
    for(j=0; j<width_; j+=2)
    {
        auto evenRow = ((i&1) == 0);
        *pyFrame++ = *src++;
        if (evenRow)
        {
            uint16_t calc = *src;
            calc += *(src + uvOffset);
            calc /= 2;
            *puFrame++ = *src;
        }
        ++src;
        *pyFrame++ = *src++;
        if (evenRow)
        {
            uint16_t calc = *src;
            calc += *(src + uvOffset);
            calc /= 2;
            *pvFrame++ = (uint8_t) calc;
        }
        ++src;
    }
}

现在我可以看到图像已正确转换。仍然不确定平均它是否是最好的做法。如果有人有 "best practise",请告诉我。