/**
   * Processes, releases and optionally renders the output buffer available at the head of the
   * queue. All observers are notified with a callback. See {@link
   * OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
   * java.nio.ByteBuffer)}
   *
   * @param render True, if the buffer is to be rendered on the {@link Surface} configured
   */
  public void popSample(boolean render) {
    // dequeue available buffers and synchronize our data structures with the codec.
    update();
    if (!mAvailableOutputBuffers.isEmpty()) {
      int index = mAvailableOutputBuffers.remove();

      if (render && mOutputSampleListener != null) {
        ByteBuffer buffer = mOutputBuffers[index];
        MediaCodec.BufferInfo info = mOutputBufferInfo[index];
        mOutputSampleListener.outputSample(this, info, buffer);
      }

      // releases the buffer back to the codec
      mDecoder.releaseOutputBuffer(index, render);
    }
  }