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 を使用して) まだ見つけることができません。