MediaExtractor を使用した正確なシークに苦労していseekTo()
ます。問題なくフレームの同期を求めることができますが、特定の時間を求めたいと思います。この質問により、これを行う方法をいくつか考えましたが、それらが有効かどうかはわかりません。advance()
基本的に、ターゲット時間に達するまで、最も近い前の同期フレームを探してからエクストラクタを探す必要があります。処理中のすべてのフレーム、つまり最初の I フレームと残りの P フレームがデコーダに供給されます。これは関連するコード スニペットです ( google/grafikaの MoviePlayer に基づく):
extractor.seekTo((long) seekTarget[threadNr], MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
...
while (extractor.getSampleTime() < (long) seekTarget[threadNr]) {
Log.d(TAG, "Thread " + threadNr + " advanced to timestamp " + extractor.getSampleTime());
int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufIndex >= 0) {
ByteBuffer inBufer = decoderInputBuffers[inputBufIndex];
int chunkSize = extractor.readSampleData(inBufer, 0);
if (chunkSize < 0) {
// End of stream -- send empty frame with EOS flag set.
decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L,
MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputDone = true;
if (VERBOSE) Log.d(TAG, "sent input EOS");
} else {
if (extractor.getSampleTrackIndex() != trackIndex) {
Log.w(TAG, "WEIRD: got sample from track " +
extractor.getSampleTrackIndex() + ", expected " + trackIndex);
}
long presentationTimeUs = extractor.getSampleTime();
decoder.queueInputBuffer(inputBufIndex, 0, chunkSize,
presentationTimeUs, 0 /*flags*/);
if (VERBOSE) {
Log.d(TAG, "submitted frame " + inputChunk + " to dec, size=" +
chunkSize + " inputBufIndex: " + inputBufIndex);
}
inputChunk++;
extractor.advance();
}
}
}
ご想像のとおり、通常は大量のフレームをキューに入れていますが、今のところ、メモリ消費や最終的な遅延は問題ありません。問題は、dequeueInputBuffer()
メソッドがループ内でしばらくの間しか機能せず、最終的に -1 を返すことでスタックすることです。これは、ドキュメントによると、バッファーが利用できないことを意味します。を に変更するTIMEOUT_USEC
と-1
、無限ループになります。
このアプローチが正しいかどうか、またはある時点でアクセスできない理由を教えてくださいinputBuffer
。