4

私はwebmビデオに変換する必要があるjpgの束を生成するアプリを持っています。jpegからvpxencサンプルにrgbデータを取得しようとしています。出力ビデオの元のjpgから基本的な形状を見ることができますが、すべてが緑色に着色されており(黒であるはずのピクセルでさえ、約半分の緑色です)、他のすべてのスキャンラインにはゴミが含まれています。

VPX_IMG_FMT_YV12データをフィードしようとしています。これは、次のように構成されていると想定しています。

フレームごとに8ビットYデータ各2x2Vブロックの8ビット平均各2x2Uブロックの8ビット平均

これがソース画像と出てくるビデオのスクリーンショットです:

画像

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;

..次に、vpxencに書き込むUおよびVの2x2フィルター処理された値を生成するには、(a + b + c + d)/ 4を実行します。ここで、a、b、c、dはのUまたはV値です。各2x2ピクセルブロック。

だから私は疑問に思っています:

  1. RGBデータを取得してvpx_codec_encodeにフィードして素敵なwebmビデオを取得する(コード内の)簡単な方法はありますか?

  2. RGB-> YV12変換がどこか間違っていますか?

どんな助けでも大歓迎です。

4

2 に答える 2

5

freefallr:もちろんです。これがコードです。RGB-> YUVを適切に変換し、YV12出力をpFullYPlane / pDownsampledUPlane/pDownsampledVPlaneに配置していることに注意してください。このデータを使用するようにvpxencサンプルを変更すると、このコードは見栄えの良いWebMビデオを生成しました。

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;
        }
    }
}
于 2011-03-29T19:17:25.770 に答える
0

どうでも。私が使用していたスキームは正しいのですが、U/Vダウンサンプリングコードにバグがありました。

于 2011-01-24T20:27:29.093 に答える