播放.ogg文件时,.dequeueOutputBuffer()在调用MediaExtractor.seekTo()后总是超时使用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()的调用发生在不同的线程上,但它们在同一个Object上同步。
synchronized (decodeLock)
{
decoder.seek(timeInUs);
}
synchronized (decodeLock)
{
input = decoder.decodeChunk();
...
}
答案 0 :(得分:0)
seek
调用codec.flush
的实现,它将丢弃输出队列中的任何已解码缓冲区。如果decoder.seek
正好在decoder.decodeChunk
之前,那么输出队列将为空。确保在调用seek
之前已将输出出列。
此外,某些解码器(芯片组/ OEM相关)将具有输入阈值。在期待任何输出缓冲区之前,尝试多次调用advanceInput
。
例如,请参阅ExoPlayer的输入/输出工作循环 MediaCodecTrackRenderer.java