Pregunta

Tengo una aplicación que genera un montón de archivos JPG que tengo que convertir en un video WebM. Estoy tratando de conseguir mis datos RGB de los archivos JPEG en la muestra vpxenc. Puedo ver las formas básicas de los archivos JPG originales en el vídeo de salida, pero todo es de color verde (incluso los píxeles que debe ser negro están a mitad de camino verde) y todos los demás scanline tiene un poco de basura en él.

Estoy tratando de alimentarlo VPX_IMG_FMT_YV12 datos, que estoy suponiendo que se estructura así:

para cada trama datos Y de 8 bits promedios de 8 bits de cada bloque de 2x2 V promedios de 8 bits de cada bloque de 2x2 U

Aquí está una imagen de origen y una captura de pantalla del vídeo que está saliendo:

Imágenes

Es muy posible que yo estoy haciendo la conversión RGB-> YV12 incorrectamente, pero incluso si sólo codificar los datos del eje Y de 8 bits y establecer la U y bloques en V a 0, las miradas de vídeo sobre el mismo. básicamente estoy pasando mis datos RGB a través de esta ecuación:

// (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;

.. y luego para producir el 2x2 valores filtrados para U y V que escribo en vpxenc, sólo lo hacen (a + b + c + d) / 4, donde a, b, c, d son la U o valores de V de cada bloque de 2x2 píxeles.

Así que me pregunto:

  1. ¿Hay una manera más fácil (en código) para tomar los datos RGB y alimentar a vpx_codec_encode para conseguir un buen vídeo WebM?

  2. Es mi RGB-> conversión YV12 en algún mal?

Cualquier ayuda sería muy apreciada.

¿Fue útil?

Solución

freefallr: Claro. Aquí está el código. Nota que está convirtiendo el RGB-> YUV en su lugar, así como poner en la salida YV12 pFullYPlane / pDownsampledUPlane / pDownsampledVPlane. Este código agradable produjo mirando vídeos WebM cuando lo modifico su muestra vpxenc utilizar estos datos.

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

Otros consejos

No importa. El esquema que estaba usando era correcto, pero tuve un error en el / código de reducción de muestreo T V.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top