Android MediaCodec';没有任何可用的输入缓冲区

Android MediaCodec';没有任何可用的输入缓冲区,android,android-mediacodec,audiorecord,Android,Android Mediacodec,Audiorecord,我正在使用MediaCodec API将视频和音频编码到mp4文件中。在单独线程中编码的数据。有时在某些设备上,音频编码器停止返回任何可用的输入缓冲区,结果MediaMuxer在尝试停止时崩溃。这是我的密码: 配置媒体编解码器: public static final String MIME_TYPE_AUDIO = "audio/mp4a-latm"; public static final int SAMPLE_RATE = 44100; public static final int CH

我正在使用MediaCodec API将视频和音频编码到mp4文件中。在单独线程中编码的数据。有时在某些设备上,音频编码器停止返回任何可用的输入缓冲区,结果MediaMuxer在尝试停止时崩溃。这是我的密码:

配置媒体编解码器:

public static final String MIME_TYPE_AUDIO = "audio/mp4a-latm";
public static final int SAMPLE_RATE = 44100;
public static final int CHANNEL_COUNT = 1;
public static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
public static final int BIT_RATE_AUDIO = 128000;
public static final int SAMPLES_PER_FRAME = 1024 * 2;
public static final int FRAMES_PER_BUFFER = 24;
public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
public static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
public static final int MAX_INPUT_SIZE = 16384 * 4;
public static final int MAX_SAMPLE_SIZE = 256 * 1024;

private AudioRecord audioRecord;
private ByteBuffer[] inputBuffers;
private ByteBuffer inputBuffer;
private MediaExtractor mediaExtractor;

private boolean audioSended = false;
private boolean completed = false;
private int sampleCount;
private int iBufferSize;

public AudioEncoderCore(MovieMuxer muxer) throws IOException {
    this.muxer = muxer;
    bufferInfo = new MediaCodec.BufferInfo();

    MediaFormat mediaFormat = null;

        mediaFormat = MediaFormat.createAudioFormat(MIME_TYPE_AUDIO, SAMPLE_RATE, CHANNEL_COUNT);
        mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, MAX_INPUT_SIZE);
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE_AUDIO);

        encoder = MediaCodec.createEncoderByType(MIME_TYPE_AUDIO);
        encoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        encoder.start();
        iBufferSize = SAMPLES_PER_FRAME * FRAMES_PER_BUFFER;

        // Ensure buffer is adequately sized for the AudioRecord
        // object to initialize
        int iMinBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT);
        if (iBufferSize < iMinBufferSize)
            iBufferSize = ((iMinBufferSize / SAMPLES_PER_FRAME) + 1) * SAMPLES_PER_FRAME * 2;

        audioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, iBufferSize);
        audioRecord.startRecording();

}
漏极编码器:

    public void drainEncoder() {
    ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
    while (true) {
        int encoderStatus = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_NSECS);
        if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Log.d(TAG, "no output available, spinning to await EOS");
            break;
        } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
            encoderOutputBuffers = encoder.getOutputBuffers();
        else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat newFormat = encoder.getOutputFormat();
            Log.d(TAG, "encoder format changed: " + newFormat);
            trackIndex = muxer.addTrack(newFormat);
        } else if (muxer.isMuxerStarted()) {
            ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
            if (encodedData == null)
                throw new RuntimeException("encoded buffer " + encoderStatus + " was null");

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
                bufferInfo.size = 0;
            }

            if (bufferInfo.size != 0) {
                encodedData.position(bufferInfo.offset);
                encodedData.limit(bufferInfo.offset + bufferInfo.size);

                muxer.writeSampleData(trackIndex, encodedData, bufferInfo);

                Log.d(TAG, "sent " + bufferInfo.size + " bytes to muxer, ts=" +
                        bufferInfo.presentationTimeUs + " track index=" + trackIndex);
            }

            encoder.releaseOutputBuffer(encoderStatus, false);

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.d(TAG, "end of stream reached");
                completed = true;
                break;      // out of while
            }
        }
    }
}
    public void drainEncoder() {
    ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
    while (true) {
        int encoderStatus = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_NSECS);
        if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Log.d(TAG, "no output available, spinning to await EOS");
            break;
        } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
            encoderOutputBuffers = encoder.getOutputBuffers();
        else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat newFormat = encoder.getOutputFormat();
            Log.d(TAG, "encoder format changed: " + newFormat);
            trackIndex = muxer.addTrack(newFormat);
        } else if (muxer.isMuxerStarted()) {
            ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
            if (encodedData == null)
                throw new RuntimeException("encoded buffer " + encoderStatus + " was null");

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
                bufferInfo.size = 0;
            }

            if (bufferInfo.size != 0) {
                encodedData.position(bufferInfo.offset);
                encodedData.limit(bufferInfo.offset + bufferInfo.size);

                muxer.writeSampleData(trackIndex, encodedData, bufferInfo);
                Log.d(TAG, "sent " + bufferInfo.size + " bytes to muxer, ts=" +
                        bufferInfo.presentationTimeUs + " track index=" + trackIndex);
            }

            encoder.releaseOutputBuffer(encoderStatus, false);

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.d(TAG, "end of stream reached");
                completed = true;
                break;      // out of while
            }
        }
        else{
            //Muxer not ready, release buffer
            encoder.releaseOutputBuffer(encoderStatus, false);
            Log.d(TAG, "muxer not ready, skip data");
        }
    }
}

该漏洞在HTC One Galaxy S3上稳定复制,但在华为荣誉3C上运行良好。

在源代码调查后,我找到了解决方案。当我将输出缓冲区出列时,muxer可能尚未启动,在这种情况下,缓冲区未释放。下面是排水编码器的工作代码:

    public void drainEncoder() {
    ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
    while (true) {
        int encoderStatus = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_NSECS);
        if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Log.d(TAG, "no output available, spinning to await EOS");
            break;
        } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
            encoderOutputBuffers = encoder.getOutputBuffers();
        else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat newFormat = encoder.getOutputFormat();
            Log.d(TAG, "encoder format changed: " + newFormat);
            trackIndex = muxer.addTrack(newFormat);
        } else if (muxer.isMuxerStarted()) {
            ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
            if (encodedData == null)
                throw new RuntimeException("encoded buffer " + encoderStatus + " was null");

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
                bufferInfo.size = 0;
            }

            if (bufferInfo.size != 0) {
                encodedData.position(bufferInfo.offset);
                encodedData.limit(bufferInfo.offset + bufferInfo.size);

                muxer.writeSampleData(trackIndex, encodedData, bufferInfo);

                Log.d(TAG, "sent " + bufferInfo.size + " bytes to muxer, ts=" +
                        bufferInfo.presentationTimeUs + " track index=" + trackIndex);
            }

            encoder.releaseOutputBuffer(encoderStatus, false);

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.d(TAG, "end of stream reached");
                completed = true;
                break;      // out of while
            }
        }
    }
}
    public void drainEncoder() {
    ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
    while (true) {
        int encoderStatus = encoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_NSECS);
        if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Log.d(TAG, "no output available, spinning to await EOS");
            break;
        } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
            encoderOutputBuffers = encoder.getOutputBuffers();
        else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            MediaFormat newFormat = encoder.getOutputFormat();
            Log.d(TAG, "encoder format changed: " + newFormat);
            trackIndex = muxer.addTrack(newFormat);
        } else if (muxer.isMuxerStarted()) {
            ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
            if (encodedData == null)
                throw new RuntimeException("encoded buffer " + encoderStatus + " was null");

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
                bufferInfo.size = 0;
            }

            if (bufferInfo.size != 0) {
                encodedData.position(bufferInfo.offset);
                encodedData.limit(bufferInfo.offset + bufferInfo.size);

                muxer.writeSampleData(trackIndex, encodedData, bufferInfo);
                Log.d(TAG, "sent " + bufferInfo.size + " bytes to muxer, ts=" +
                        bufferInfo.presentationTimeUs + " track index=" + trackIndex);
            }

            encoder.releaseOutputBuffer(encoderStatus, false);

            if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.d(TAG, "end of stream reached");
                completed = true;
                break;      // out of while
            }
        }
        else{
            //Muxer not ready, release buffer
            encoder.releaseOutputBuffer(encoderStatus, false);
            Log.d(TAG, "muxer not ready, skip data");
        }
    }
}

我的问题与您的答案并不完全相关,但它促使我研究代码的某一部分,并发出砰的一声,这是因为我在某个案例中错过了一个版本。谢谢