播放 .ogg 文件时,在调用 MediaExtractor.seekTo() 后,.dequeueOutputBuffer() 总是超时,MediaCodec.INFO_TRY_AGAIN_LATER。这会导致问题,因为我正在尝试创建近乎无缝的搜索。最大阻塞时间无关紧要,无论设置多长时间它总是超时。
所有 .ogg 文件都会发生这种情况,而没有其他音频文件类型。
这是相关代码,超时发生在
final int res = codec.dequeueOutputBuffer(info, TIMEOUT_US);
每次使用 .ogg 文件调用 seekTo() 后都会发生这种情况,有没有办法纠正这个问题?
public MediaCodecMp3Decoder(String fullPath) throws IOException
{
extractor = new MediaExtractor();
extractor.setDataSource(fullPath);
format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);
durationUs = format.getLong(MediaFormat.KEY_DURATION);
codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, null, null, 0);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
extractor.selectTrack(0);
info = new MediaCodec.BufferInfo();
}
public byte[] decodeChunk()
{
advanceInput();
final int res = codec.dequeueOutputBuffer(info, TIMEOUT_US);
if (res >= 0)
{
int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
if(chunk == null || chunk.length != info.size)
{
chunk = new byte[info.size];
}
buf.get(chunk);
buf.clear();
codec.releaseOutputBuffer(outputBufIndex, false);
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
{
sawOutputEOS = true;
}
else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
codecOutputBuffers = codec.getOutputBuffers();
}
else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
format = codec.getOutputFormat();
Log.d("MP3", "Output format has changed to " + format);
}
return chunk;
}
private void advanceInput()
{
boolean sawInputEOS = false;
int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_US);
if (inputBufIndex >= 0)
{
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize = extractor.readSampleData(dstBuf, 0);
long presentationTimeUs = 0;
if (sampleSize < 0)
{
sawInputEOS = true;
sampleSize = 0;
}
else
{
presentationTimeUs = extractor.getSampleTime();
currentTimeUs += presentationTimeUs - lastPresentationTime;
lastPresentationTime = presentationTimeUs;
}
codec.queueInputBuffer(inputBufIndex,
0,
sampleSize,
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS)
{
extractor.advance();
}
}
}
public void seek(long timeInUs)
{
extractor.seekTo(timeInUs, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
lastPresentationTime = currentTimeUs = timeInUs;
codec.flush();
}
这是在 seekTo() 之前和之后唯一的 logcat,AudioTrack 上的缓冲区不足是由于我目前为 dequeueOutputBuffer() 设置的 1 秒超时
03-01 13:48:25.042: I/AudioFlinger(125): BUFFER TIMEOUT: remove(4099) from active list on thread 0x40b42008
03-01 13:48:25.312: W/AudioTrack(29349): releaseBuffer() track 0x6a110c10 name=s:125;n:3;f:-1 disabled due to previous underrun, restarting
另外我应该注意到对 seekTo() 和 decodeChunk() 的调用发生在不同的线程上,但它们在同一个对象上同步。
synchronized (decodeLock)
{
decoder.seek(timeInUs);
}
synchronized (decodeLock)
{
input = decoder.decodeChunk();
...
}