нужно создать вебм видео из кадров RGB - PullRequest
4 голосов
/ 22 января 2011

У меня есть приложение, которое генерирует кучу jpgs, которые мне нужно превратить в веб-видео. Я пытаюсь получить мои данные RGB из JPEG в образце vpxenc. Я могу видеть основные формы из исходных jpgs в выходном видео, но все окрашено в зеленый цвет (даже пиксели, которые должны быть черными, примерно наполовину зеленые), и на каждой другой линии сканирования есть какой-то мусор.

Я пытаюсь передать им данные VPX_IMG_FMT_YV12, которые, как я предполагаю, структурированы так:

за каждый кадр 8-битные данные Y 8-битные средние значения каждого блока 2x2 В 8-битные средние значения каждого блока 2x2 U

Вот исходное изображение и скриншот выходящего видео:

Изображения

Вполне возможно, что я неправильно выполняю преобразование RGB-> YV12, но даже если я только кодирую 8-битные данные Y и устанавливаю блоки 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 каждого блока пикселей 2x2.

Так что мне интересно:

  1. Есть ли более простой способ (в коде) взять данные RGB и передать их в vpx_codec_encode для получения хорошего веб-видео?

  2. Является ли мое преобразование RGB-> YV12 где-то неправильным?

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

5 голосов
/ 29 марта 2011

freefallr: Конечно. Вот код Обратите внимание, что он конвертирует RGB-> YUV на месте, а также помещает вывод YV12 в pFullYPlane / 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;
        }
    }
}
0 голосов
/ 24 января 2011

Неважно. Схема, которую я использовал, была правильной, но у меня была ошибка в коде понижающей дискретизации U / V.

...