web-dev-qa-db-ja.com

使用方法Android MediaCodecエンコードカメラデータ(YUV420sp)

集中していただきありがとうございます! Android MediaCodec APIを使用して、カメラから取得したビデオフレームをエンコードしたいのですが、残念ながら、それを実行できませんでした。まだMediaCodecAPIに精通していません。以下は私のコードです。 、私は私が何をすべきかを理解するためにあなたの助けが必要です。

1、カメラ設定:

Parameters parameters = mCamera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setPreviewSize(320, 240);
mCamera.setParameters(parameters);

2、エンコーダを設定します。

private void initCodec() {
    try {
        fos = new FileOutputStream(mVideoFile, false);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    mMediaCodec = MediaCodec.createEncoderByType("video/avc");
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc",
            320,
            240);
    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 125000);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
    mMediaCodec.configure(mediaFormat,
            null,
            null,
            MediaCodec.CONFIGURE_FLAG_ENCODE);
    mMediaCodec.start();
    inputBuffers = mMediaCodec.getInputBuffers();
    outputBuffers = mMediaCodec.getOutputBuffers();
}

private void encode(byte[] data) {
    int inputBufferIndex = mMediaCodec.dequeueInputBuffer(0);
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
        inputBuffer.clear();
        inputBuffer.put(data);
        mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0);
    } else {
        return;
    }

    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0);
    Log.i(TAG, "outputBufferIndex-->" + outputBufferIndex);
    do {
        if (outputBufferIndex >= 0) {
            ByteBuffer outBuffer = outputBuffers[outputBufferIndex];
            System.out.println("buffer info-->" + bufferInfo.offset + "--"
                    + bufferInfo.size + "--" + bufferInfo.flags + "--"
                    + bufferInfo.presentationTimeUs);
            byte[] outData = new byte[bufferInfo.size];
            outBuffer.get(outData);
            try {
                if (bufferInfo.offset != 0) {
                    fos.write(outData, bufferInfo.offset, outData.length
                            - bufferInfo.offset);
                } else {
                    fos.write(outData, 0, outData.length);
                }
                fos.flush();
                Log.i(TAG, "out data -- > " + outData.length);
                mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,
                        0);
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            outputBuffers = mMediaCodec.getOutputBuffers();
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat format = mMediaCodec.getOutputFormat();
        }
    } while (outputBufferIndex >= 0);
}

エンコーダーメソッドで問題が発生したと思います。このメソッドは、カメラプレビューコールバックで使用されます。

initCodec();

//mCamera.setPreviewCallback(new MyPreviewCallback());
mCamera.setPreviewCallback(new PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        encode(data);
    }
});

MediaCodec APIを使用して正しく行う方法がわかりません。アドバイスやリンクを教えていただけますか?

ありがとうございました!

13
Read Mark

私は問題を解決しました。次のように:

private synchronized void encode(byte[] data)
{
    inputBuffers = mMediaCodec.getInputBuffers();// here changes
    outputBuffers = mMediaCodec.getOutputBuffers();

    int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);
    Log.i(TAG, "inputBufferIndex-->" + inputBufferIndex);
    //......

そして次に、エンコードされたビデオの色が正しくないことがわかります。詳細については、ここにアクセスしてください MediaCodecとカメラ:色空間が一致しません

7
Read Mark

カメラによって出力されるYUV420形式は、MediaCodecAVCエンコーダーによって受け入れられる形式と互換性がありません。最良の場合、それは本質的にNV12対NV21(U面とV面が逆になっている)であり、手動で並べ替える必要があります。最悪の場合、Android 4.2の時点で、エンコーダの入力形式はデバイス固有である可能性があります。

MediaRecorder を使用して、カメラハードウェアをエンコーダーに接続することをお勧めします。

更新:MediaCodecのYUVデータを使用する代わりに、カメラのSurfaceプレビューをByteBufferに渡すことができるようになりました。これはより速く、よりポータブルです。 CameraToMpegTestサンプルを参照してください ここ

5
fadden