private void recordVideo() { ByteBuffer[] encodeOutputBuffers = mEncoder.getOutputBuffers(); while (!endEncode.get()) { int encoderIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US); if (encoderIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { if (mediaMuxerStarted) { throw new IllegalStateException("output format already changed"); } MediaFormat newFormat = mEncoder.getOutputFormat(); videoTrackIndex = mediaMuxer.addTrack(newFormat); mediaMuxer.start(); mediaMuxerStarted = true; } else if (encoderIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } else if (encoderIndex < 0) { Log.w(TAG, "encoderIndex 非法" + encoderIndex); } else if (encoderIndex >= 0) { ByteBuffer encodeData = encodeOutputBuffers[encoderIndex]; if (encodeData == null) { throw new RuntimeException("编码数据为空"); } if (mBufferInfo.size != 0) { if (!mediaMuxerStarted) throw new RuntimeException("混合器未开启"); encodeData.position(mBufferInfo.offset); encodeData.limit(mBufferInfo.offset + mBufferInfo.size); mediaMuxer.writeSampleData(videoTrackIndex, encodeData, mBufferInfo); mEncoder.releaseOutputBuffer(encoderIndex, false); } } } }
/** * Do encoding by using MediaCodec encoder, then extracts all pending data from the encoder and * forwards it to the muxer. * * <p>If notifyEndOfStream is not set, this returns when there is no more data to output. If it is * set, we send EOS to the encoder, and then iterate until we see EOS on the output. Calling this * with notifyEndOfStream set should be done once, before stopping the muxer. * * <p>We're just using the muxer to get a .mp4 file and audio is not included here. */ private void doMediaCodecEncoding(boolean notifyEndOfStream) { if (VERBOSE) { Log.v(TAG, "doMediaCodecEncoding(" + notifyEndOfStream + ")"); } if (notifyEndOfStream) { mEncoder.signalEndOfInputStream(); } ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers(); boolean notDone = true; while (notDone) { int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC); if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { if (!notifyEndOfStream) { /** * Break out of the while loop because the encoder is not ready to output anything yet. */ notDone = false; } else { if (VERBOSE) { Log.v(TAG, "no output available, spinning to await EOS"); } } } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { // generic case for mediacodec, not likely occurs for encoder. encoderOutputBuffers = mEncoder.getOutputBuffers(); } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { /** should happen before receiving buffers, and should only happen once */ if (mMuxerStarted) { throw new IllegalStateException("format changed twice"); } MediaFormat newFormat = mEncoder.getOutputFormat(); if (VERBOSE) { Log.v(TAG, "encoder output format changed: " + newFormat); } mTrackIndex = mMuxer.addTrack(newFormat); mMuxer.start(); mMuxerStarted = true; } else if (encoderStatus < 0) { Log.w(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus); } else { // Normal flow: get output encoded buffer, send to muxer. ByteBuffer encodedData = encoderOutputBuffers[encoderStatus]; if (encodedData == null) { throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null"); } if ((mBufferInfo.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. */ if (VERBOSE) { Log.v(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG"); } mBufferInfo.size = 0; } if (mBufferInfo.size != 0) { if (!mMuxerStarted) { throw new RuntimeException("muxer hasn't started"); } /** It's usually necessary to adjust the ByteBuffer values to match BufferInfo. */ encodedData.position(mBufferInfo.offset); encodedData.limit(mBufferInfo.offset + mBufferInfo.size); mMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo); if (VERBOSE) { Log.v(TAG, "sent " + mBufferInfo.size + " bytes to muxer"); } } mEncoder.releaseOutputBuffer(encoderStatus, false); if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { if (!notifyEndOfStream) { Log.w(TAG, "reached end of stream unexpectedly"); } else { if (VERBOSE) { Log.v(TAG, "end of stream reached"); } } // Finish encoding. notDone = false; } } } // End of while(notDone) }