Video Conversion: YUY2 to YV12

See topic on MSDN Forums about coloring issue.

This is a demo of YUY2 to YV12 conversion as suggested copying Y values and averaging U and V.

Original image is on the right.

Code snippet to perform the transformation:

ATLASSERT(pInputBitmapInfoHeader->biCompression == FOURCC_YUY2);
const CSize Extent = pInputVideoInfoHeader->GetExtent();
ATLASSERT(Extent == pOutputVideoInfoHeader->GetExtent());
const BYTE* pnInputData = InputMediaBuffer.m_pnData;
SSIZE_T nFirstInputRowOffset, nNextInputRowOffset;
pInputVideoInfoHeader->GetData(nFirstInputRowOffset, nNextInputRowOffset);
ATLASSERT(!nFirstInputRowOffset);
BYTE* pnOutputData = OutputMediaBuffer.m_pnData;
SSIZE_T nFirstOutputRowOffset, nNextOutputRowOffset;
pOutputVideoInfoHeader->GetData(nFirstOutputRowOffset, nNextOutputRowOffset);
ATLASSERT(!nFirstOutputRowOffset);
BYTE* pnOutputDataY = pnOutputData;
BYTE* pnOutputDataV = pnOutputDataY + Extent.cy * nNextOutputRowOffset;
BYTE* pnOutputDataU = pnOutputDataV + (Extent.cy * nNextOutputRowOffset) / 4;
ATLTRACE2(atlTraceGeneral, 5, _T("pnInputData 0x%08x - 0x%08x, Extent { %d, %d }, pnOutputData 0x%08x - 0x%08x\n"), pnInputData, pnInputData + pInputBitmapInfoHeader->biSizeImage, Extent.cx, Extent.cy, pnOutputData, pnOutputData + pOutputBitmapInfoHeader->biSizeImage);
ATLTRACE2(atlTraceGeneral, 5, _T("nFirstInputRowOffset %d, nNextInputRowOffset %d, nFirstOutputRowOffset %d, nNextOutputRowOffset %d\n"), nFirstInputRowOffset, nNextInputRowOffset, nFirstOutputRowOffset, nNextOutputRowOffset);
ATLTRACE2(atlTraceGeneral, 5, _T("pnOutputDataY 0x%08x, pnOutputDataV 0x%08x, pnOutputDataU 0x%08x\n"), pnOutputDataY, pnOutputDataV, pnOutputDataU);
SSIZE_T nInputRowOffset = nFirstInputRowOffset;
for(LONG nY = 0; nY < Extent.cy; nY += 2)
{
    SSIZE_T nInputOffset = nInputRowOffset;
    for(LONG nX = 0; nX < Extent.cx; nX += 2)
    {
        pnOutputDataY[0] = pnInputData[nInputOffset + 0];
        const BYTE nU0 = pnInputData[nInputOffset + 1];
        pnOutputDataY[1] = pnInputData[nInputOffset + 2];
        const BYTE nV0 = pnInputData[nInputOffset + 3];
        pnOutputDataY[nNextOutputRowOffset + 0] = pnInputData[nInputOffset + nNextInputRowOffset + 0];
        const BYTE nU1 = pnInputData[nInputOffset + nNextInputRowOffset + 1];
        pnOutputDataY[nNextOutputRowOffset + 1] = pnInputData[nInputOffset + nNextInputRowOffset + 2];
        const BYTE nV1 = pnInputData[nInputOffset + nNextInputRowOffset + 3];
        pnOutputDataU[0] = (nU0 + nU1) / 2;
        pnOutputDataV[0] = (nV0 + nV1) / 2;
        nInputOffset += 4;
        pnOutputDataY += 2;
        pnOutputDataV += 1;
        pnOutputDataU += 1;
    }
    nInputRowOffset += 2 * nNextInputRowOffset;
    pnOutputDataY += 2 * nNextOutputRowOffset - Extent.cx;
    pnOutputDataV += nNextOutputRowOffset / 2 - Extent.cx / 2;
    pnOutputDataU += nNextOutputRowOffset / 2 - Extent.cx / 2;
}
ATLTRACE2(atlTraceGeneral, 5, _T("pnOutputDataY 0x%08x, pnOutputDataV 0x%08x, pnOutputDataU 0x%08x\n"), pnOutputDataY, pnOutputDataV, pnOutputDataU)

See also:

Leave a Reply