Нужно создать видео Webm из RGB -кадров
-
16-10-2019 - |
Вопрос
У меня есть приложение, которое генерирует кучу JPG, которые мне нужно превратить в видео WebM. Я пытаюсь получить данные RGB от JPEGS в образец VPXENC. Я вижу основные формы из оригинальных JPG в выходном видео, но все окрашено зеленым (даже пиксели, которые должны быть черными, примерно наполовину зеленые), и у любой другой линии Scanline есть немного мусора.
Я пытаюсь накормить его данные vpx_img_fmt_yv12, которые, как я предполагаю, структурированы так:
Для каждого кадров 8-битный y 8-разрядные средние значения каждые 2x2 В 8-битные средние значения каждого блока 2x2 U
Вот исходное изображение и скриншот выходящего видео:
Вполне возможно, что я неправильно делаю преобразование RGB-> YV12, но даже если я кодирую только 8-битные данные и устанавливаю блоки U и V на 0, видео выглядит примерно так же. Я в основном запускаю данные RGB через это уравнение:
// (R, G, and B are 0-255)
float y = 0.299f*R + 0.587f*G + 0.114f*B;
float v = (R-y)*0.713f;
float u = (B-v)*0.565f;
.., а затем, чтобы создать фильтрованные значения 2x2 для u и v, которые я пишу в vpxenc, я просто делаю (a + b + c + d) / 4, где a, b, c, d - значения U или v Каждый 2х2 пиксельного блока.
Так что мне интересно:
Есть ли более простой способ (в коде) брать данные RGB и подавать их в vpx_codec_encode, чтобы получить хорошее видео Webm?
Мое преобразование RGB-> YV12 неправильно?
Любая помощь будет очень оценена.
Решение
Freefallr: конечно. Вот код. Обратите внимание, что он преобразует RGB-> YUV на месте, а также вкладывает выход YV12 в plyplane/pdownsampleduplane/pdownsampledvplane. Этот код создал красивые видео Webm, когда я изменил их образец VPXENC, чтобы использовать эти данные.
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;
}
}
}
Другие советы
Неважно. Схема, которую я использовал, была правильной, но у меня была ошибка в коде u/v Downsampling.