16

MediaCodecファイルにバイト配列として保存された一連の画像をビデオファイルに保存するために使用しようとしています。SurfaceViewこれらの画像を(連続して再生して)テストしましたが、問題なく表示されます。を使用して多くの例を見てきましたMediaCodecが、これが私が理解していることです(間違っている場合は修正してください):

MediaCodec オブジェクトから InputBuffers を取得 -> フレームの画像データで埋める -> 入力バッファをキューに入れる -> コード化された出力バッファを取得 -> ファイルに書き込む -> プレゼンテーション時間を増やして繰り返す

ただし、これを何度もテストした結果、次の 2 つのケースのいずれかになります。

  • 私が真似ようとしたすべてのサンプル プロジェクトqueueInputBufferでは、2 回目の呼び出し時にメディア サーバーが停止しました。
  • 最後に呼び出しcodec.flush()てみました (出力バッファーをファイルに保存した後、私が見た例はどれもこれを行いませんでした)、メディアサーバーは停止しませんでしたが、どのメディアプレーヤーでも出力ビデオファイルを開くことができませんでした。何かが間違っている。

これが私のコードです:

MediaCodec codec = MediaCodec.createEncoderByType(MIMETYPE);
        MediaFormat mediaFormat = null;
        if(CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)){
            mediaFormat = MediaFormat.createVideoFormat(MIMETYPE, 1280 , 720);
        } else {
            mediaFormat = MediaFormat.createVideoFormat(MIMETYPE, 720, 480);
        }


        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 700000);
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
        codec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

        codec.start();

        ByteBuffer[] inputBuffers = codec.getInputBuffers();
        ByteBuffer[] outputBuffers = codec.getOutputBuffers();
        boolean sawInputEOS = false;
        int inputBufferIndex=-1,outputBufferIndex=-1;
        BufferInfo info=null;

                    //loop to read YUV byte array from file

            inputBufferIndex = codec.dequeueInputBuffer(WAITTIME);
            if(bytesread<=0)sawInputEOS=true;

            if(inputBufferIndex >= 0){
                if(!sawInputEOS){
                    int samplesiz=dat.length;
                    inputBuffers[inputBufferIndex].put(dat);
                    codec.queueInputBuffer(inputBufferIndex, 0, samplesiz, presentationTime, 0);
                    presentationTime += 100;

                    info = new BufferInfo();
                    outputBufferIndex = codec.dequeueOutputBuffer(info, WAITTIME);
                    Log.i("BATA", "outputBufferIndex="+outputBufferIndex);
                    if(outputBufferIndex >= 0){
                        byte[] array = new byte[info.size];
                        outputBuffers[outputBufferIndex].get(array);

                        if(array != null){
                            try {
                                dos.write(array);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                        codec.releaseOutputBuffer(outputBufferIndex, false);
                        inputBuffers[inputBufferIndex].clear();
                        outputBuffers[outputBufferIndex].clear();

                        if(sawInputEOS) break;
                    }
                }else{
                    codec.queueInputBuffer(inputBufferIndex, 0, 0, presentationTime, MediaCodec.BUFFER_FLAG_END_OF_STREAM);

                    info = new BufferInfo();
                    outputBufferIndex = codec.dequeueOutputBuffer(info, WAITTIME);

                    if(outputBufferIndex >= 0){
                        byte[] array = new byte[info.size];
                        outputBuffers[outputBufferIndex].get(array);

                        if(array != null){
                            try {
                                dos.write(array);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                        codec.releaseOutputBuffer(outputBufferIndex, false);
                        inputBuffers[inputBufferIndex].clear();
                        outputBuffers[outputBufferIndex].clear();
                        break;
                    }
                }


            }
        }

        codec.flush();

        try {
            fstream2.close();
            dos.flush();
            dos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        codec.stop();
        codec.release();
        codec = null;

        return true;

    }

私の質問は、MediaCodec を使用して画像のストリームから作業ビデオを取得するにはどうすればよいかということです。私は何を間違っていますか?

もう 1 つの質問 (欲張りではない場合)、このビデオにオーディオ トラックを追加したいのですが、MediaCodec でも実行できますか、それとも FFmpeg を使用する必要がありますか?

:Android 4.3については知ってMediaMuxいますが、アプリはAndroid 4.1以降で動作する必要があるため、これはオプションではありません。

更新 fadden answer のおかげで、メディアサーバーが停止することなく EOS に到達できました (上記のコードは変更後です)。ただし、取得しているファイルは意味不明です。これは、私が取得したビデオのスナップショットです (.h264 ファイルとしてのみ機能します)。

ビデオ出力

入力画像形式は YUV 画像 (カメラ プレビューの NV21) です。再生可能なフォーマットにすることはできません。すべての COLOR_FormatYUV420 形式と同じ意味不明な出力を試しました。そして、オーディオを追加する方法を (MediaCodec を使用して) まだ見つけることができません。

4

1 に答える 1