3
votes

I am using MediaCodec API's to play the video stream(H.264) I am receiving through ethernet port.

From what I understood from official documentation and various examples, I need to perform the following operations.

  1. Create a MediaCodec instance based on the mimetype(video/avc for H.264)
  2. Feed "csd-0" with SPS frame data. SPS frame should start with 0x00000001
  3. Feed "csd-1" buffer with PPS frame data. PPS frame should start with 0x00000001
  4. Call decoder.configure() and decoder.start(). If all goes well, decoder is correctly configured and there is no exception.
  5. Once the MediaCodec is configured, we can supply to the decoder all the rest of the frames (depacketed NAL units).
  6. Upon successfull dequeue operation, the decoded buffer can be rendered onto the screen as follows.

outputBufferId = decoder.dequeueOutputBuffer(info, 1000); decoder.releaseOutputBuffer(outputBufferId, true);

Problem

decoder.dequeueOutputBuffer() Is returning -3 on android 6.0. Official documentation says that in the case of any errors during dequeueOutputBuffer() only -1 (INFO_TRY_AGAIN_LATER) and -2 (INFO_OUTPUT_FORMAT_CHANGED) are returned and that -3 (INFO_OUTPUT_BUFFERS_CHANGED) is deprecated. So why am I receiving -3?

How am I supposed to correct this?

Code Snippet :

String mimeType = "video/avc";
decoder = MediaCodec.createDecoderByType(mimeType);
mformat = MediaFormat.createVideoFormat(mimeType, 1920, 1080);

while (!Thread.interrupted()) {
    byte[] data = new byte[size];
    bin.read(data, 0, size);
    if (data is SPS frame) {
        mformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
        mformat.setByteBuffer("csd-0", ByteBuffer.wrap(data));
        continue;
    }

    if (data is PPS frame) {
        mformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
        mformat.setByteBuffer("csd-1", ByteBuffer.wrap(data));
        decoder.configure(mformat. surface, null, 0);
        decoder.start();
        is_decoder_configured = true;
        continue;
    }

    if (!is_decoder_configured)
        continue;

    index = decoder.dequeueInputBuffer(1000);
    if (index < 0) {
        Log.e(TAG, "Dequeue in put buffer failed..\n");
        continue;
    }

    buf = decoder.getInputBuffer(index);
    if (buf == null)
        continue;
    buf.put(data);

    decoder.queueInputBuffer(index, 0, data.length, 0, 0);
    int outputBufferId = decoder.dequeueOutputBuffer(info, 1000);
    switch (outputBufferId) {
        case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
            Log.i("DecodeActivity", "New format " + decoder.getOutputFormat());
            break;
        case MediaCodec.INFO_TRY_AGAIN_LATER:
            Log.i("DecodeActivity", "dequeueOutputBuffer timed out!");
            break;
        default:
            Log.i(TAG, "Successfully decoded the output : " + outputBufferId);
            decoder.releaseOutputBuffer(outputBufferId, true);
            break;
    }
}

if (is_decoder_configured()) {
    decoder.stop();
    decoder.release();
}

In the case you see any other errors, please let me know. Will be grateful!

1

1 Answers

1
votes

I don't see anything saying that it will never be returned. The documentation says this:

This constant was deprecated in API level 21. This return value can be ignored as getOutputBuffers() has been deprecated. Client should request a current buffer using on of the get-buffer or get-image methods each time one has been dequeued.

That is, if you're using getOutputBuffers(), you need to listen for this return value and act on it - but doing this is deprecated. If you're not using getOutputBuffers(), just ignore this return value, i.e. call dequeueOutputBuffer() again with the same parameters and see what it returns afterwards.