Need to create web video from RGB frames

I have an application that generates a bunch of jpg that I need to turn into video on the Internet. I am trying to get rgb data from jpegs into a vpxenc sample. I can see the main shapes from the original jpg in the output video, but everything is colored green (even pixels that should be black are about half green), and every other scan line contains garbage.

I am trying to pass VPX_IMG_FMT_YV12 data, which I assume is structured like this:

for each frame 8-bit data Y 8-bit average values ​​of each block 2x2 V 8-bit average values ​​of each block 2x2 U

Here is the original image and a screenshot of the video that comes out:

Images

It is possible that I am doing RGB-> YV12 incorrectly, but even if I only encode 8-bit Y data and set the U and V blocks to 0, the video looks pretty much the same. I basically control RGB data through this equation:

// (R, G, and B are 0-255) float y = 0.299f*R + 0.587f*G + 0.114f*B; float v = (Ry)*0.713f; float u = (Bv)*0.565f; 

.. and then produce 2x2 filtered values ​​for U and V that I write in vpxenc, I just do (a + b + c + d) / 4, where a, b, c, d is the U or V of each block 2x2 pixels .

So, I am wondering:

  • Is there an easier way (in code) to take RGB data and pass it to vpx_codec_encode to get a good video on the Internet?

  • Am I somewhere incorrectly converting RGB-> YV12?

Any help would be greatly appreciated.

+4
source share
2 answers

freefallr: Of course. Here is the code. Note that this converts RGB-> YUV to place, as well as the output of YV12 to pFullYPlane / pDownsampledUPlane / pDownsampledVPlane. This code created nice WebM videos when I changed their vpxenc pattern to use this data.

 void RGB_To_YV12( unsigned char *pRGBData, int nFrameWidth, int nFrameHeight, void *pFullYPlane, void *pDownsampledUPlane, void *pDownsampledVPlane ) { int nRGBBytes = nFrameWidth * nFrameHeight * 3; // Convert RGB -> YV12. We do this in-place to avoid allocating any more memory. unsigned char *pYPlaneOut = (unsigned char*)pFullYPlane; int nYPlaneOut = 0; for ( int i=0; i < nRGBBytes; i += 3 ) { unsigned char B = pRGBData[i+0]; unsigned char G = pRGBData[i+1]; unsigned char R = pRGBData[i+2]; float y = (float)( R*66 + G*129 + B*25 + 128 ) / 256 + 16; float u = (float)( R*-38 + G*-74 + B*112 + 128 ) / 256 + 128; float v = (float)( R*112 + G*-94 + B*-18 + 128 ) / 256 + 128; // NOTE: We're converting pRGBData to YUV in-place here as well as writing out YUV to pFullYPlane/pDownsampledUPlane/pDownsampledVPlane. pRGBData[i+0] = (unsigned char)y; pRGBData[i+1] = (unsigned char)u; pRGBData[i+2] = (unsigned char)v; // Write out the Y plane directly here rather than in another loop. pYPlaneOut[nYPlaneOut++] = pRGBData[i+0]; } // Downsample to U and V. int halfHeight = nFrameHeight >> 1; int halfWidth = nFrameWidth >> 1; unsigned char *pVPlaneOut = (unsigned char*)pDownsampledVPlane; unsigned char *pUPlaneOut = (unsigned char*)pDownsampledUPlane; for ( int yPixel=0; yPixel < halfHeight; yPixel++ ) { int iBaseSrc = ( (yPixel*2) * nFrameWidth * 3 ); for ( int xPixel=0; xPixel < halfWidth; xPixel++ ) { pVPlaneOut[yPixel * halfWidth + xPixel] = pRGBData[iBaseSrc + 2]; pUPlaneOut[yPixel * halfWidth + xPixel] = pRGBData[iBaseSrc + 1]; iBaseSrc += 6; } } } 
+5
source

Nothing. The circuit I used was correct, but I had an error in the U / V downsampling code.

0
source

Source: https://habr.com/ru/post/1336541/


All Articles