title: MediaCodec encoding - dequeueInputBuffer returns INFO_TRY_AGAIN_LATER?
body: <p>I'm working on a project where I'm using the <code>AudioRecord</code> class to record audio and <code>MediaMuxer</code> to write the encoded data to an output file. Everything seems to be working fine once I start recording but after a few calls to the <code>writeRecordingAudioFileSampleData</code> method below, the <code>dequeueInputBuffer</code> method continuously returns <code>INFO_TRY_AGAIN_LATER (-1)</code>. </p>
  
  <p>I tried flushing the encoder every time I call the method and the issue no longer occurs. But then the app crashes when I call the stop method on the the media muxer (it says "Failed to stop the muxer"). I shouldn't have to call flush the MediaCodec but without it, I keep getting <code>INFO_TRY_AGAIN_LATER</code>.</p>
  
  <p>Here is the method that starts the recording process. For brevity, I have not included the methods that get the presentation time or the methods that initialize the AudioRecord instance, the <code>MediaMuxer</code>, and the <code>MediaCodec</code> encoder. I don't believe the issue has to do with them but if they may be helpful, let me know and I'll post them. </p>
  
  <pre><code>    public ActionResponse startRecording()
      {
          ActionResponse response = new ActionResponse();
          try
          {
              File recordDir = new File(RECORD_TEMP_DIR);
              if(!recordDir.exists())
              {
                  if(!recordDir.mkdirs())
                      throw new IOException("Could not create file");
              }
  
              String fileName = generateRecordingName();
              String path = RECORD_TEMP_DIR + "/" + fileName + "." + recordingOutputOptions.recordAudioFormat.name;
              currentTrack = new AudioFile();
              currentTrack.setName(fileName);
              currentTrack.setPath(path);
              currentTrack.setFormat(recordingOutputOptions.recordAudioFormat);
  
              this.initializeAudioRecord();
              if(audioRecord.getState() != AudioRecord.STATE_INITIALIZED)
                  throw new IOException("Could not initialize audio record instance");
  
              this.initializeRecordingAudioEncoder();
              this.initializeRecordingMediaMuxer();
  
              encoder.start();
  
              audioRecord.startRecording();
  
              recordReadThread = new Thread(readAudioRecordRunnable);
              recordReadThread.start();
  
              recorderState = MEDIA_RECORDER_STATE.RECORDING;
              response.setStatus(ActionResponse.ResponseStatus.SUCCESS);
          }
          catch (IOException e)
          {
              response.setStatus(ActionResponse.ResponseStatus.FAILURE);
              response.setError(e);
          }
  
          return response;
      }
  </code></pre>
  
  <p>And here is the runnable where I'm reading data from the AudioRecord instance:</p>
  
  <pre><code>        private Runnable readAudioRecordRunnable = new Runnable()
      {
          @Override
          public void run()
          {
              ActionResponse response = new ActionResponse(ActionResponse.ResponseStatus.SUCCESS);
              File outFile = new File(currentTrack.path);
              try
              {
                  if(outFile.exists())
                      outFile.delete();
  
                  // Parent directory should have already been created before we started recording
                  if(!outFile.createNewFile())
                  {
                      response.setStatusMessage("Could not create file");
                      response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                  }
                  else
                  {
                      ByteBuffer buffer = ByteBuffer.allocateDirect(recordingOutputOptions.bufferSize);
                      int numReads = 0;
                      while (recorderState == MEDIA_RECORDER_STATE.RECORDING)
                      {
                          int result = audioRecord.read(buffer, recordingOutputOptions.bufferSize);
  
                          if (result &gt;= 0)
                          {
                              audioAbsolutePtsUs = (System.nanoTime()) / 1000L;
                              int samplesPerBuffer = recordingOutputOptions.bufferSize / recordingOutputOptions.bytesPerSample;
                              long presentationTime = getPresentationTimeUs(audioAbsolutePtsUs,samplesPerBuffer);
  
                              Log.e("TAG","Writing " + result + " bytes of recorded data with presentation time: " + String.valueOf(presentationTime));
                              ActionResponse encodeResponse = writeRecordingAudioFileSampleData(buffer,false,presentationTime);
                              if(!encodeResponse.isSuccess())
                              {
                                  response = encodeResponse;
                                  break;
                              }
  
                              buffer.clear();
                              numReads++;
                              //encoder.flush();
                          }
                          else
                          {
                              response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                              response.setStatusMessage("Audio record return result: " + result);
                              break;
                          }
                      }
                  }
  
                  if(response.isSuccess())
                      writeRecordingAudioFileSampleData(null,true,0);
              }
              catch (Exception e)
              {
                  response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                  response.setStatusMessage("Error occurred while recording");
                  response.setError(e);
              }
              finally
              {
                  try
                  {
                      encoder.stop();
                      encoder.release();
                      encoder = null;
  
                      muxer.stop();
                      muxer.release();
                      muxer = null;
                      isMuxerStarted = false;
                  }
                  catch (Exception ex)
                  {
                      Log.e("Recording Error","Error stopping and cleaning up encoder and muxer",ex);
                  }
              }
  
              if(!response.isSuccess())
              {
                  stopRecording();
  
                  outFile.delete();
  
                  Log.e("Recording Error",response.statusMessage,response.error);
                  if(recordEventHandler!=null)
                      recordEventHandler.onRecordError(response);
              }
          }
      };
  </code></pre>
  
  <p>And here is the writeRecordingAudioFileSampleData method:</p>
  
  <pre><code>        public ActionResponse writeRecordingAudioFileSampleData(final ByteBuffer data,boolean isEndOfStream, long presentationTime)
      {
          ActionResponse response = new ActionResponse(ActionResponse.ResponseStatus.SUCCESS);
          try
          {
              boolean doneSubmittingInput = false;
              int index;
              int numBytesSubmitted = 0;
              int numBytesEncoded = 0;
              int numRetriesDequeueOutputBuffer = 0;
              ByteBuffer[] inputBuffers = encoder.getInputBuffers();
              ByteBuffer[] outputBuffers = encoder.getOutputBuffers();
  
              while (true)
              {
                  if (!doneSubmittingInput)
                  {
                      index = encoder.dequeueInputBuffer(ENCODER_BUFFER_TIMEOUT_US);
                      if (index != MediaCodec.INFO_TRY_AGAIN_LATER)
                      {
                          Log.e("TAG","Dequeued input buffer: " + index);
                          if(isEndOfStream)
                          {
                              doneSubmittingInput = true;
                              encoder.queueInputBuffer(index, 0, 0, 0, BUFFER_FLAG_END_OF_STREAM);
                          }
                          else
                          {
                              int dataSize = data.capacity();
                              if (numBytesSubmitted &gt;= dataSize)
                              {
                                  doneSubmittingInput = true;
                              }
                              else
                              {
                                  ByteBuffer buffer = inputBuffers[index];
                                  buffer.clear();
                                  buffer.put(data);
                                  encoder.queueInputBuffer(index, 0, buffer.remaining(), presentationTime, 0);
                                  Log.e("TAG","Queued input buffer: " + index);
                                  numBytesSubmitted += buffer.remaining();
                              }
                          }
                      }
                      else
                      {                            response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                          response.setStatusMessage("Dequeue input buffer returned: " + index);
                          break;
                      }
                  }
  
                  MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                  index = encoder.dequeueOutputBuffer(info, ENCODER_BUFFER_TIMEOUT_US);
  
                  if (index == MediaCodec.INFO_TRY_AGAIN_LATER)
                  {
                      Log.e("TAG","No output buffer available");
  
                      if (++numRetriesDequeueOutputBuffer &gt; MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER)
                      {
                          if(!isEndOfStream)
                          {
                              // All data encoded
                              Log.e("TAG","Max Retries Exceeded. All data has been encoded.");
                              break;
                          }
                          else
                          {
                              Log.e("TAG","Max Retries Exceeded. End of stream input has been queued.");
                              // EOS Input Queued, Continue Loop to Receive output
                          }
                      }
                  }
                  else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
                  {
                      // should only happen once before receiving buffers
                      if (isMuxerStarted)
                      {
                          // should not occur
                          response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                          response.setStatusMessage("Output format changed after muxer started");
                          break;
                      }
  
                      MediaFormat newFormat = encoder.getOutputFormat();
                      muxerTrackIndex = muxer.addTrack(newFormat);
                      muxer.start();
                      isMuxerStarted = true;
                      Log.e("TAG","Started Muxer");
                  }
                  else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
                  {
                      // should not occur
                      Log.e("TAG","Output buffers changed");
                      outputBuffers = encoder.getOutputBuffers();
                  }
                  else if (index &lt; 0)
                  {
                      Log.e("TAG","Unexpected index " + index + " received from dequeueOutputBuffer");
                      // Unexpected result - should not occur. Ignore it
                  }
                  else
                  {
                      Log.e("TAG","Dequeued output buffer: " + index);
                      ByteBuffer encodedData = outputBuffers[index];
                      if ((info.flags &amp; MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0)
                      {
                          // The codec config data was pulled out and fed to the muxer when we got
                          // the INFO_OUTPUT_FORMAT_CHANGED status.  Ignore it.
                          Log.e("TAG","Ignoring codec config data");
                          info.size = 0;
                      }
  
                      if (info.size != 0)
                      {
                          if (!isMuxerStarted)
                          {
                              // should not occur
                              response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                              response.setStatusMessage("Attempting to write data but muxer was not started");
                              break;
                          }
  
  
                          info.presentationTimeUs = presentationTime;
                          muxer.writeSampleData(muxerTrackIndex,encodedData,info);
                          Log.e("TAG","Wrote " + info.size + " bytes to muxer");
                          numBytesEncoded += info.size;
                      }
  
                      encoder.releaseOutputBuffer(index, false);
                      Log.e("TAG","Releasing output buffer: " + index);
  
                      if ((info.flags &amp; MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
                      {
                          // EOS Submitted
                          if(!isEndOfStream)
                          {
                              // Unexpected EOS
                              response.setStatus(ActionResponse.ResponseStatus.FAILURE);
                              response.setStatusMessage("Unexpected buffer end of stream flag");
                          }
                          else
                              Log.e("TAG","Dequeued end of stream reached. All data has been encoded.");
  
                          break;
                      }
                  }
              }
          }
          catch (Exception exc)
          {
              response.setStatus(ActionResponse.ResponseStatus.FAILURE);
              response.setStatusMessage(exc.getMessage());
              response.setError(exc);
          }
          finally
          {
  
          }
  
          return response;
      }
  </code></pre>
  
  <p>Finally, here is a sample of the output I get when running the app, which shows where the recording stops:</p>
  
  <pre><code>W/ExtendedACodec: Failed to get extension for extradata parameter
  E/TAG: Writing 28288 bytes of recorded data with presentation time: 41035517230
  E/TAG: Dequeued input buffer: 0
  E/TAG: Queued input buffer: 0
  I/MPEG4Writer: limits: 4294967295/0 bytes/us, bit rate: -1 bps and the estimated moov size 3195 bytes
  D/MPEG4Writer: Audio track starting
  E/TAG: Started Muxer
  E/TAG: Dequeued input buffer: 1
  E/TAG: Dequeued output buffer: 0
         Ignoring codec config data
  E/TAG: Releasing output buffer: 0
  E/TAG: Dequeued output buffer: 1
  I/MPEG4Writer: setStartTimestampUs: 41035517230
                 Earliest track starting time: 41035517230
  E/TAG: Wrote 371 bytes to muxer
         Releasing output buffer: 1
  E/TAG: Dequeued output buffer: 2
  E/TAG: Wrote 372 bytes to muxer
  E/TAG: Releasing output buffer: 2
  E/TAG: Dequeued output buffer: 3
  W/MPEG4Writer: 0-duration samples found: 1
  E/TAG: Wrote 520 bytes to muxer
         Releasing output buffer: 3
  E/TAG: No output buffer available
  E/TAG: No output buffer available
  I/chatty: uid=10286(com.bandindustries.musicjournal) Thread-4 identical 3 lines
  E/TAG: No output buffer available
  E/TAG: Max Retries Exceeded. All data has been encoded.
         Writing 28288 bytes of recorded data with presentation time: 41035677592
         Dequeued input buffer: 2
  E/TAG: Queued input buffer: 2
  E/TAG: Dequeued output buffer: 0
  W/MPEG4Writer: 0-duration samples found: 1
  E/TAG: Wrote 513 bytes to muxer
  E/TAG: Releasing output buffer: 0
  E/TAG: Dequeued input buffer: 3
  E/TAG: Dequeued output buffer: 1
         Wrote 462 bytes to muxer
  E/TAG: Releasing output buffer: 1
  E/TAG: Dequeued output buffer: 2
         Wrote 433 bytes to muxer
  E/TAG: Releasing output buffer: 2
  E/TAG: No output buffer available
  I/chatty: uid=10286(com.bandindustries.musicjournal) Thread-4 identical 4 lines
  E/TAG: No output buffer available
         Max Retries Exceeded. All data has been encoded.
  E/TAG: Writing 28288 bytes of recorded data with presentation time: 41035837955
  E/TAG: Dequeued input buffer: 0
  E/TAG: Queued input buffer: 0
  E/TAG: Dequeued output buffer: 3
  W/MPEG4Writer: 0-duration samples found: 2
  E/TAG: Wrote 407 bytes to muxer
  E/TAG: Releasing output buffer: 3
  E/TAG: Dequeued input buffer: 2
  E/TAG: Dequeued output buffer: 0
         Wrote 408 bytes to muxer
  E/TAG: Releasing output buffer: 0
  E/TAG: Dequeued output buffer: 1
  E/TAG: Wrote 392 bytes to muxer
  E/TAG: Releasing output buffer: 1
  E/TAG: Dequeued output buffer: 2
  E/TAG: Wrote 390 bytes to muxer
  E/TAG: Releasing output buffer: 2
  E/TAG: No output buffer available
  I/chatty: uid=10286(com.bandindustries.musicjournal) Thread-4 identical 4 lines
  E/TAG: No output buffer available
  E/TAG: Max Retries Exceeded. All data has been encoded.
  E/TAG: Writing 28288 bytes of recorded data with presentation time: 41035998318
  E/TAG: Dequeued input buffer: 0
  E/TAG: Queued input buffer: 0
  E/TAG: Dequeued output buffer: 3
  W/MPEG4Writer: 0-duration samples found: 3
  E/TAG: Wrote 356 bytes to muxer
  E/TAG: Releasing output buffer: 3
  I/zygote64: Do partial code cache collection, code=27KB, data=29KB
              After code cache collection, code=27KB, data=29KB
              Increasing code cache capacity to 128KB
  D/MPEG4Writer: Audio track stopping. Stop source
                 Audio track source stopping
                 Audio track source stopped
  I/MPEG4Writer: Received total/0-length (11/0) buffers and encoded 11 frames. - Audio
                 Audio track drift time: 0 us
  D/MPEG4Writer: Audio track stopped. Stop source
                 Audio track stopped. Stop source
                 Stopping writer thread
  D/MPEG4Writer: 0 chunks are written in the last batch
  D/MPEG4Writer: Writer thread stopped
  I/MPEG4Writer: Ajust the moov start time from 41035517230 us -&gt; 41035517230 us
  D/MPEG4Writer: Audio track stopping. Stop source
  E/Recording Error: Dequeue input buffer returned: -1
  </code></pre>
  
  <p>Has anyone ever experienced this before? This is my first time working with low-level media classes in Android and I couldn't find many good examples online or in the documentation. I appreciate any help. Thank you.</p>
  
  <p><strong>UPDATE:</strong> The issue where the app crashes when stopping the media muxer was due to sending 0 as the presentation time stamp for the last call, which is the end of stream. But I'm getting an empty file as output for some reason.</p>