Question

J'ai une application qui génère un tas de jpgs que je dois transformer en une vidéo WebM. Je suis en train de récupérer mes données rgb des fichiers JPEG dans l'échantillon de vpxenc. Je peux voir les formes de base des jpgs d'origine dans la vidéo de sortie, mais tout est teinté vert (même pixels qui devraient être noirs sont à mi-chemin vert) et tous les autres a scanline des ordures en elle.

Je suis en train de le nourrir VPX_IMG_FMT_YV12 données, ce qui je suppose est structuré comme ceci:

pour chaque trame        8 bits de données Y        Moyennes de 8 bits de chaque bloc de 2x2 V        Moyennes de 8 bits de chaque bloc 2x2 U

Voici une image source et une capture d'écran de la vidéo qui sort:

Images

Il est tout à fait possible que je fais la RVB-> conversion YV12 mal, mais même si j'encoder uniquement les données Y 8 bits et définissez les U et les blocs de V à 0, les regards vidéo sur le même. Je suis fondamentalement en cours d'exécution mes données RVB par cette équation:

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

.. et ensuite pour produire le 2x2 valeurs filtrées pour U et V que j'écrire dans vpxenc, je fais juste (a + b + c + d) / 4, où a, b, c, d sont les U ou les valeurs de V de chaque bloc de pixels 2x2.

Je me demande:

  1. Y at-il un moyen plus facile (en code) pour prendre des données RVB et nourrir à vpx_codec_encode pour obtenir une belle vidéo WebM?

  2. Mon RVB-> conversion YV12 mal quelque part?

Toute aide serait grandement appréciée.

Était-ce utile?

La solution

freefallr: Bien sûr. Voici le code. Notez qu'il est la conversion du RVB-> YUV en place ainsi que de mettre la sortie YV12 dans pFullYPlane / pDownsampledUPlane / pDownsampledVPlane. Ce code produit agréable à regarder des vidéos WebM quand je modifièrent leur échantillon de vpxenc utiliser ces données.

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

Autres conseils

Qu'à cela ne tienne. Le système que j'utilisais était correct, mais j'ai eu un bug dans le code U downsampling / V.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top