MediaCodec编码-dequeueInputBuffer返回INFO_TRY_AGAIN_LATER吗?

时间:2018-07-16 13:52:13

标签: java android mediacodec audiorecord mediamuxer

我正在一个项目中,我正在使用AudioRecord类记录音频,并使用MediaMuxer将编码后的数据写入输出文件。一旦开始记录,一切似乎都正常,但是在对下面的writeRecordingAudioFileSampleData方法进行了几次调用之后,dequeueInputBuffer方法不断返回INFO_TRY_AGAIN_LATER (-1)

每次调用该方法时,我都尝试刷新编码器,并且不再发生此问题。但是,当我在媒体混合器上调用stop方法时,应用程序崩溃了(它说“无法停止混合器”)。我不必调用flush MediaCodec,但没有它,我会不断得到INFO_TRY_AGAIN_LATER

这是开始记录过程的方法。为简便起见,我没有包括获取演示时间的方法或初始化AudioRecord实例,MediaMuxerMediaCodec编码器的方法。我认为问题与他们无关,但是如果他们可能有帮助,请告诉我,我将其发布。

    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;
    }

这是我正在从AudioRecord实例读取数据的地方:

        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 >= 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);
            }
        }
    };

这是writeRecordingAudioFileSampleData方法:

        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 >= 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 > 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 < 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 & 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 & 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;
    }

最后,这是运行该应用程序时获得的输出示例,其中显示了记录的停止位置:

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 -> 41035517230 us
D/MPEG4Writer: Audio track stopping. Stop source
E/Recording Error: Dequeue input buffer returned: -1

有人曾经经历过吗?这是我第一次使用Android中的低级媒体类,并且在网上或文档中找不到很多好的示例。感谢您的帮助。谢谢。

更新:停止媒体多路复用器时应用程序崩溃的问题是由于发送0作为最后一次呼叫的演示时间戳,即流的结尾。但是由于某种原因,我得到了一个空文件作为输出。

0 个答案:

没有答案