新しい低レベルの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.NV21とImageFormat.YV2のみであることがわかります。
については、タイプvideo/avcのMediaCodecInfo.CodecCapabilities<2>
オブジェクトを取得しました。整数値は 19 ( MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planarおよび 2130708361 に対応します ( MediaCodecInfo.CodecCapabilitiesの値には対応しません) です)。
上記以外の値を指定すると、クラッシュが発生します。
これらの設定を組み合わせると、異なる結果が得られます。これを以下に示します。Android のスクリーンショット (つまり、「実際の」色) は次のとおりです。Gstreamer で表示される結果は次のとおりです。
<1>
= NV21, <2>
= COLOR_FormatYUV420Planar
<1>
= NV21, <2>
= 2130708361
<1>
= YV2, <2>
= COLOR_FormatYUV420Planar
<1>
= YV2, <2>
= 2130708361
ご覧のとおり、これらのどれも満足のいくものではありません。YV2 色空間が最も有望に見えますが、赤 (Cr) と青 (Cb) が反転しているように見えます。NV21 はインターレースのように見えます (しかし、私はこの分野の専門家ではありません)。
Skype との通信が目的なので、デコーダー (つまり Gstreamer コマンド) を変更するべきではないと思いますよね? これは Android で解決されますか?もしそうなら:どのように? それとも、特定の RTP ペイロード情報を追加することで解決できますか? 他の提案はありますか?