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.
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;
}