Search code examples
c++image-processingyuv

Convert YUY2 to YV12


I am almost sure that this is much simpler than I think it is, but I have been scouring the internet for a much longer time than I care to admit to try and figure out how the frig to convert the two formats. I am able to extract the Y0, Cb, Y1, Cr data from a stream of unsigned bytes (unsigned char), but I have no idea how these bytes are arranged in YV12 - is this document implying that the various values are actually contained in different rows?

I've literally been searching all day for things like "c++ convert YUY2 to YV12," and have turned up absolutely no tutorials or code samples. I would think that this would have some form of documentation that I could use, but the information seems to be scarce on this particular subject.


Solution

  • Looks like the linked entry on YUY2 together with the Wikipedia article on YV12 makes this pretty clear:

    • YUY2 stores every two adjacent, horizontal pixels as four bytes, [Y1, U, Y2, V].

    • YV12 stores an entire M × N frame in a contiguous array of M*N + 2 * (M/2 * N/2) bytes. Let's call the array byte frame[M * N * 3 / 2]. We have:

      • frame[i] for i in [0, M * N) are the Y-values of the pixels.
      • frame[j] for j in [M * N, M * N * 5/4) are the V-values of each 2 × 2-pixel tile.
      • frame[j] for k in [M * N * 5/4, M * N * 6/4) are the U-values of each 2 × 2-pixel tile.

    So as you convert from YUY2 to YV12, you have to halve the amount of U- and V-data, possibly by taking the average of two adjacent rows.

    Example:

    byte YUY2Source[M * N * 2] = /* source frame */;
    byte YV12Dest[M * N * 3/2];
    
    for (unsigned int i = 0; i != M * N; ++i)
    {
        YV12Dest[i] = YUY2Source[2 * i];
    }
    
    for (unsigned int j = 0; j != M * N / 4; ++j)
    {
        YV12Dest[M * N + j]       = ( YUY2Source[N*(j / N/2    ) + 4 * j + 3]
                                    + YUY2Source[N*(j / N/2 + 1) + 4 * j + 3] ) / 2;
    
        YV12Dest[M * N * 5/4 + j] = ( YUY2Source[N*(j / N/2    ) + 4 * j + 1]
                                    + YUY2Source[N*(j / N/2 + 1) + 4 * j + 1] ) / 2;
    }