34

新しい低レベルのMediaCodecを使用して、H264 エンコーディングを Android タブレットのカメラでキャプチャされた入力で動作させようとしています。MediaCodecAPI の文書化が不十分であるため、これにはいくつかの困難がありましたが、ようやく機能するようになりました。

次のようにカメラを設定しています。

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewFormat(ImageFormat.YV12); // <1>
        parameters.setPreviewFpsRange(4000,60000);
        parameters.setPreviewSize(640, 480);            
        mCamera.setParameters(parameters);

エンコーディング部分については、次のように MediaCodec オブジェクトをインスタンス化しています。

    mediaCodec = MediaCodec.createEncoderByType("video/avc");
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 640, 480);
    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 500000);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar); // <2>
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
    mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
    mediaCodec.start();

最終的な目標は、RTP ストリームを作成する (そして Skype に対応させる) ことですが、これまでのところ、生の H264 をデスクトップに直接ストリーミングしているだけです。そこで、次の GStreamer パイプラインを使用して結果を表示します。

gst-launch udpsrc port=5555 ! video/x-h264,width=640,height=480,framerate=15/1 ! ffdec_h264 ! autovideosink

色を除いて、すべてがうまく機能します。コンピューターに 2 つの colorformats を設定する必要があります<1><2>

<1>私が使用した行の許容値を決定するためにparameters.getSupportedPreviewFormats(). このことから、カメラでサポートされている形式はImageFormat.NV21ImageFormat.YV2のみであることがわかります。

については、タイプvideo/avcのMediaCodecInfo.CodecCapabilities<2>オブジェクトを取得しました。整数値は 19 ( MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planarおよび 2130708361 に対応します ( MediaCodecInfo.CodecCapabilitiesの値には対応しません) です)。

上記以外の値を指定すると、クラッシュが発生します。

これらの設定を組み合わせると、異なる結果が得られます。これを以下に示します。Android のスクリーンショット (つまり、「実際の」色) Android タブレットでの入力 は次のとおりです。Gstreamer で表示される結果は次のとおりです。

<1>= NV21, <2>= COLOR_FormatYUV420Planar NV21-COLOR_FormatYUV420Planar の Gstreamer 出力

<1>= NV21, <2>= 2130708361 NV21-2130708361 の Gstreamer 出力

<1>= YV2, <2>= COLOR_FormatYUV420Planar YV2-COLOR_FormatYUV420Planar の Gstreamer 出力

<1>= YV2, <2>= 2130708361 YV2-2130708361 の Gstreamer 出力

ご覧のとおり、これらのどれも満足のいくものではありません。YV2 色空間が最も有望に見えますが、赤 (Cr) と青 (Cb) が反転しているように見えます。NV21 はインターレースのように見えます (しかし、私はこの分野の専門家ではありません)。

Skype との通信が目的なので、デコーダー (つまり Gstreamer コマンド) を変更するべきではないと思いますよね? これは Android で解決されますか?もしそうなら:どのように? それとも、特定の RTP ペイロード情報を追加することで解決できますか? 他の提案はありますか?

4

5 に答える 5

7

シンプルな関数を使用して、Android レベルでバイトプレーンを自分で交換することで解決しました。

public byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
    byte[] i420bytes = new byte[yv12bytes.length];
    for (int i = 0; i < width*height; i++)
        i420bytes[i] = yv12bytes[i];
    for (int i = width*height; i < width*height + (width/2*height/2); i++)
        i420bytes[i] = yv12bytes[i + (width/2*height/2)];
    for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
        i420bytes[i] = yv12bytes[i - (width/2*height/2)];
    return i420bytes;
}
于 2012-12-10T10:38:12.387 に答える
6

値をその場で交換する方が効率的だと思います。

        int wh4 = input.length/6; //wh4 = width*height/4
        byte tmp;
        for (int i=wh4*4; i<wh4*5; i++)
            {
            tmp = input[i];
            input[i] = input[i+wh4];
            input[i+wh4] = tmp;
            }

代わりに置き換えることができます

            inputBuffer.put(input);

正しい順序で 3 つの平面スライスを使用

            inputBuffer.put(input, 0, wh4*4);
            inputBuffer.put(input, wh4*5, wh4);
            inputBuffer.put(input, wh4*4, wh4);

オーバーヘッドはごくわずかであるべきだと思います

于 2013-07-10T05:29:52.763 に答える
3

AndroidはYV12で送信しているようですが、H264ヘッダーに設定されているフォーマットはYUV420です。これらの形式は、U チャネルと V チャネルの順序が異なることを除いて同じです。これにより、赤と青が入れ替わります。

もちろん、Android側の設定を修正するのが最善でしょう。ただし、カメラとエンコーダーに互換性のある設定を行う方法がない場合は、GStreamer 側でフォーマットを強制する必要があります。

capssetterこれは、要素の後に要素を追加することで実行できますffdec_h264

... ! ffdec_h264 ! capssetter caps="video/x-raw-yuv, format=(fourcc)YV12" ! colorspace ! ...

于 2012-12-05T16:54:49.017 に答える
0

カメラに ImageFormat.NV21 を設定し、エンコーダーに COLOR_FormatYUV420Planar を設定すると、私の場合、同様の青い影が重なって表示されます。私の場合、上記のスワップ関数は使用できないことを理解しているので、これに使用できるアルゴリズムに関する提案はありますか? ps: カメラのプレビュー形式が YV12 に設定されている場合、デコーダーで完全に黒い画面になります。

于 2012-12-17T12:34:51.313 に答える