2014-03-01 2 views
1

.ogg 파일을 재생할 때 MediaExtractor.seekTo() 호출 후 .dequeueOutputBuffer()가 항상 MediaCodec.INFO_TRY_AGAIN_LATER로 시간 초과됩니다. 거의 끊임없이 추구하기 때문에 문제가 발생합니다. 최대 블로킹 시간은 무의미하며 설정된 시간과 관계없이 항상 타임 아웃됩니다.Ogg 오디오 파일을 검색 할 때 MediaCodec.dequeueOutputBuffer 시간 초과가 발생했습니다.

모든 .ogg 파일 및 다른 오디오 파일 형식에서 발생합니다.

다음은이 문제를 해결하려면 어쨌든, 거기 관련 코드이며, 제한 시간은 오그 파일 seekTo()를 호출 할 때마다 후

final int res = codec.dequeueOutputBuffer(info, TIMEOUT_US); 

그런 일에 어떻게됩니까? 여기

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() 후 AudioTrack에 버퍼 언더런 I은 또한

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 

dequeueOutputBuffer()에 설정 한 1 초 시간 제한에 기인 I seekTo() 및 decodeChunk()에 대한 호출이 다른 스레드에서 발생하지만 동일한 객체에서 동기화된다는 점에 유의해야합니다.

synchronized (decodeLock) 
{ 
    decoder.seek(timeInUs); 
} 

synchronized (decodeLock) 
{ 
    input = decoder.decodeChunk(); 
... 
} 
+0

logcat을 공유 할 수 있습니까? 검색을 한 후 readSampleData가 반환하는 크기는 무엇입니까? – Marlon

+0

LogCat을 게시했습니다. 시크 (seek) 후에 sampleSize는 147이며, 정상 작동 중에 크기와 일치하는 정상 크기입니다. presentationTimeUs와 동일합니다. –

+0

안드로이드 버전을보고 계십니까? KLP에서 수정 된 문제와 관련된 몇 가지 문제점이 있습니다. – marcone

답변

0

seek 호출하는 출력 큐 버퍼에서 디코딩 폐기한다 codec.flush 구현. decoder.seekdecoder.decodeChunk 바로 앞에 있으면 출력 대기열이 비어 있습니다. seek을 호출하기 전에 출력을 큐에서 제거했는지 확인하십시오.

또한 일부 디코더 (칩셋/OEM 종속)에는 입력 임계 값이 있습니다. 출력 버퍼를 예상하기 전에 advanceInput 번을 여러 번 호출 해보십시오.

예를 들어 ExoPlayer의 입출력 작업 루프는 MediaCodecTrackRenderer.java입니다.

관련 문제