Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android MediaCodec dequeueInputBuffer always returns -1

I'm trying to take raw data from the AudioRecord object and save it in a file using a MediaMuxer and MediaCodec.

I start the codec, start the muxer, load data into the input buffers and no such luck.

From debugging investigation, I've found that the problem is occurring in the call to dequeueInputBuffer(). It appears that the first few chunks of data succeed, but eventually dequeueInputBuffer() just returns -1 constantly.

Is there something obvious that I'm missing? This seems like what's happening is I'm filling up the input buffers but they're never being released by the codec.

Snippet of relevant code:

int numChunks = input.length / CHUNKSIZE;
mAudioEncoder.start();
    for (int chunk = 0; chunk <= numChunks; chunk++) {
        byte[] passMe = new byte[CHUNKSIZE];
        int inputBufferIndex = -1;
        Log.d("offerAudioEncoder","printing chunk #" + chunk + "of " + numChunks);
        //Copy the data into the chunk array
        if (chunk < input.length / CHUNKSIZE)
            for (int i = 0; i < CHUNKSIZE; i++)
                passMe[i] = input[chunk * CHUNKSIZE + i];
        else {
            eosReceived = true;
            for (int i = 0; chunk * CHUNKSIZE + i < input.length; i++)
                passMe[i] = input[chunk * CHUNKSIZE + i];
        }

        //Get the input buffer
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
            while(inputBufferIndex < 0)//justk keep trying.
                inputBufferIndex = mAudioEncoder.dequeueInputBuffer(100);
            inputBuffer = mAudioEncoder.getInputBuffer(inputBufferIndex);
        } else {
            //backwards compatibility.
            ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
            inputBufferIndex = mAudioEncoder.dequeueInputBuffer(-1);
            if (inputBufferIndex >= 0)
                inputBuffer = inputBuffers[inputBufferIndex];
        }

        //Plop the data into the input buffer
        if (inputBuffer != null) {
            inputBuffer.clear();
            inputBuffer.put(passMe);
        }
        long presentationTimeUs = chunk * 10000000; //each encoded chunk represents one second of audio
        //this is what the frame should be labeled as
        mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, passMe.length, presentationTimeUs, 0);

        //Pull the output buffer.
        int encoderStatus = -1;
        while(encoderStatus < 0) //Like, seriously, WAIT forever.
            encoderStatus = mAudioEncoder.dequeueOutputBuffer(mAudioBufferInfo, -1);//wait forever, why not?
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
            outputBuffer = mAudioEncoder.getOutputBuffer(encoderStatus);
        else {
            ByteBuffer[] encoderOutputBuffers = mAudioEncoder.getOutputBuffers();
            outputBuffer = encoderOutputBuffers[encoderStatus];
        }

        if(encoderStatus >= 0) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
                mMuxer.writeSampleData(audioTrackIndex, outputBuffer, mAudioBufferInfo);

            //Done with the output buffer, release it.
            mAudioEncoder.releaseOutputBuffer(encoderStatus, false);
        }//TODO: Add cases for what to do when the output format changes
like image 829
Daniel Kirby Avatar asked Jan 09 '17 01:01

Daniel Kirby


1 Answers

Okay, I figured it out. Ultimately I dumped the chunking logic and just increased the size of the input buffer by setting

audioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 14000000);

For the MediaFormat object passed to the MediaCodec's configure method.

Also a good tip: Make sure to use 16-bit audio encoding and to use the AudioRecord.read method that spits out shorts. Bytes seem to produce screwy audio (probably because AudioRecord wants to be operating in 16 bit).

like image 85
Daniel Kirby Avatar answered Sep 28 '22 09:09

Daniel Kirby