public static MediaCodec getAudioMediaCodec(AudioConfiguration configuration){ MediaFormat format = MediaFormat.createAudioFormat(configuration.mime, configuration.frequency, configuration.channelCount); if(configuration.mime.equals(AudioConfiguration.DEFAULT_MIME)) { format.setInteger(MediaFormat.KEY_AAC_PROFILE, configuration.aacProfile); } format.setInteger(MediaFormat.KEY_BIT_RATE, configuration.maxBps * 1024); format.setInteger(MediaFormat.KEY_SAMPLE_RATE, configuration.frequency); int maxInputSize = AudioUtils.getRecordBufferSize(configuration); format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, maxInputSize); format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, configuration.channelCount); MediaCodec mediaCodec = null; try { mediaCodec = MediaCodec.createEncoderByType(configuration.mime); mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); } catch (Exception e) { e.printStackTrace(); if (mediaCodec != null) { mediaCodec.stop(); mediaCodec.release(); mediaCodec = null; } } return mediaCodec; } }
synchronized void offerEncoder(byte[] input) { if(mMediaCodec == null) { return; } ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers(); ByteBuffer[] outputBuffers = mMediaCodec.getOutputBuffers(); int inputBufferIndex = mMediaCodec.dequeueInputBuffer(12000); if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(input); mMediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0); } int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 12000); while (outputBufferIndex >= 0) { ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; if(mListener != null) { mListener.onAudioEncode(outputBuffer, mBufferInfo); } mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); outputBufferIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 0); } } }
mEncoder = MediaCodec.createByCodecName(codecInfo.getName()); mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mEncoder.start(); mEncoder.stop(); mEncoder.release();
private void getCodecBuffers(MediaCodec codec) { if (Util.SDK_INT < 21) { inputBuffers = codec.getInputBuffers(); outputBuffers = codec.getOutputBuffers(); } }
private void releaseEncoder() { if (mMediaCodec != null) { mMediaCodec.signalEndOfInputStream(); mMediaCodec.stop(); mMediaCodec.release(); mMediaCodec = null; } if (mInputSurface != null) { mInputSurface.release(); mInputSurface = null; } }
mEncoder.signalEndOfInputStream(); } catch (Exception e) ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers(); while (true) int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC); if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) encoderOutputBuffers = mEncoder.getOutputBuffers(); } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) MediaFormat newFormat = mEncoder.getOutputFormat(); if (VERBOSE) Log.i(TAG, "encoder output format changed: " + newFormat); mEncoder.releaseOutputBuffer(encoderStatus, false);
mExtractor.selectTrack(mTrackIndex); try { mEncoder = MediaCodec.createEncoderByType(mOutputFormat.getString(MediaFormat.KEY_MIME)); } catch (IOException e) { throw new IllegalStateException(e); mEncoder.configure(mOutputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mEncoderInputSurfaceWrapper = new InputSurface(mEncoder.createInputSurface()); mEncoderInputSurfaceWrapper.makeCurrent(); mEncoder.start(); mEncoderStarted = true; mEncoderOutputBuffers = mEncoder.getOutputBuffers(); mDecoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME)); } catch (IOException e) { throw new IllegalStateException(e); mDecoder.configure(inputFormat, mDecoderOutputSurfaceWrapper.getSurface(), null, 0); mDecoder.start(); mDecoderStarted = true; mDecoderInputBuffers = mDecoder.getInputBuffers();
private int drainExtractor(long timeoutUs) { if (mIsExtractorEOS) return DRAIN_STATE_NONE; int trackIndex = mExtractor.getSampleTrackIndex(); if (trackIndex >= 0 && trackIndex != mTrackIndex) { return DRAIN_STATE_NONE; } int result = mDecoder.dequeueInputBuffer(timeoutUs); if (result < 0) return DRAIN_STATE_NONE; if (trackIndex < 0) { mIsExtractorEOS = true; mDecoder.queueInputBuffer(result, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); return DRAIN_STATE_NONE; } int sampleSize = mExtractor.readSampleData(mDecoderInputBuffers[result], 0); boolean isKeyFrame = (mExtractor.getSampleFlags() & MediaExtractor.SAMPLE_FLAG_SYNC) != 0; mDecoder.queueInputBuffer(result, 0, sampleSize, mExtractor.getSampleTime(), isKeyFrame ? MediaCodec.BUFFER_FLAG_SYNC_FRAME : 0); mExtractor.advance(); return DRAIN_STATE_CONSUMED; }
private void drainEncoder() { ByteBuffer[] outBuffers = mMediaCodec.getOutputBuffers(); while (isStarted) { encodeLock.lock(); if(mMediaCodec != null) { int outBufferIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 12000); if (outBufferIndex >= 0) { ByteBuffer bb = outBuffers[outBufferIndex]; if (mListener != null) { mListener.onVideoEncode(bb, mBufferInfo); } mMediaCodec.releaseOutputBuffer(outBufferIndex, false); } else { try { // wait 10ms Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } encodeLock.unlock(); } else { encodeLock.unlock(); break; } } } }
private MediaCodecWrapper(MediaCodec codec) { mDecoder = codec; codec.start(); mInputBuffers = codec.getInputBuffers(); mOutputBuffers = codec.getOutputBuffers(); mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length]; mAvailableInputBuffers = new ArrayDeque<>(mOutputBuffers.length); mAvailableOutputBuffers = new ArrayDeque<>(mInputBuffers.length); }
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int generateIndex = 0; int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC); if (inputBufIndex >= 0) encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputDone = true; encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0); drainEncoder(false, info);
try { outputIndex = codec.dequeueOutputBuffer(outputBufferInfo, getDequeueOutputBufferTimeoutUs()); } catch (IllegalStateException e) { processEndOfStream(); codec.dequeueOutputBuffer(outputBufferInfo, getDequeueOutputBufferTimeoutUs()); codec.releaseOutputBuffer(outputIndex, false); return true; } else if (outputBufferInfo.size == 0
private int drainDecoder(long timeoutUs) { if (mIsDecoderEOS) return DRAIN_STATE_NONE; int result = mDecoder.dequeueOutputBuffer(mBufferInfo, timeoutUs); switch (result) { case MediaCodec.INFO_TRY_AGAIN_LATER: return DRAIN_STATE_NONE; case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: mAudioChannel.setActualDecodedFormat(mDecoder.getOutputFormat()); case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: return DRAIN_STATE_SHOULD_RETRY_IMMEDIATELY; } if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { mIsDecoderEOS = true; mAudioChannel.drainDecoderBufferAndQueue(AudioChannel.BUFFER_INDEX_END_OF_STREAM, 0); } else if (mBufferInfo.size > 0) { mAudioChannel.drainDecoderBufferAndQueue(result, mBufferInfo.presentationTimeUs); } return DRAIN_STATE_CONSUMED; }
@Override public void setup() { mExtractor.selectTrack(mTrackIndex); try { mEncoder = MediaCodec.createEncoderByType(mOutputFormat.getString(MediaFormat.KEY_MIME)); } catch (IOException e) { throw new IllegalStateException(e); } mEncoder.configure(mOutputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mEncoder.start(); mEncoderStarted = true; mEncoderBuffers = new MediaCodecBufferCompatWrapper(mEncoder); final MediaFormat inputFormat = mExtractor.getTrackFormat(mTrackIndex); try { mDecoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME)); } catch (IOException e) { throw new IllegalStateException(e); } mDecoder.configure(inputFormat, null, null, 0); mDecoder.start(); mDecoderStarted = true; mDecoderBuffers = new MediaCodecBufferCompatWrapper(mDecoder); mAudioChannel = new AudioChannel(mDecoder, mEncoder, mOutputFormat); }
@Test @Config(minSdk = LOLLIPOP) public void doesNotPresentInputBufferAfterReleasingOutputBufferFinished() { ArgumentCaptor<Integer> indexCaptor = ArgumentCaptor.forClass(Integer.class); verify(callback).onInputBufferAvailable(same(codec), indexCaptor.capture()); ByteBuffer buffer = codec.getInputBuffer(indexCaptor.getValue()); int start = buffer.position(); // "Write" to the buffer. buffer.position(buffer.limit()); codec.queueInputBuffer( indexCaptor.getValue(), /* offset= */ start, /* size= */ buffer.position() - start, /* presentationTimeUs= */ 0, /* flags= */ MediaCodec.BUFFER_FLAG_END_OF_STREAM); verify(callback).onOutputBufferAvailable(same(codec), indexCaptor.capture(), any()); codec.releaseOutputBuffer(indexCaptor.getValue(), /* render= */ false); verify(callback, times(1)).onInputBufferAvailable(same(codec), anyInt()); }
final int encoderInBuffIndex = mEncoder.dequeueInputBuffer(timeoutUs); if (encoderInBuffIndex < 0) { if (hasOverflow) { final long presentationTimeUs = drainOverflow(outBuffer); mEncoder.queueInputBuffer(encoderInBuffIndex, 0, outBuffer.position() * BYTES_PER_SHORT, presentationTimeUs, 0); mEncoder.queueInputBuffer(encoderInBuffIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); return false; mEncoder.queueInputBuffer(encoderInBuffIndex, 0, outBuffer.position() * BYTES_PER_SHORT, presentationTimeUs, 0); if (inBuffer != null) { mDecoder.releaseOutputBuffer(inBuffer.bufferIndex, false); mEmptyBuffers.add(inBuffer);
private int drainEncoder(long timeoutUs) { if (mIsEncoderEOS) return DRAIN_STATE_NONE; int result = mEncoder.dequeueOutputBuffer(mBufferInfo, timeoutUs); switch (result) { case MediaCodec.INFO_TRY_AGAIN_LATER: throw new RuntimeException("Audio output format changed twice."); mActualOutputFormat = mEncoder.getOutputFormat(); mMuxer.setOutputFormat(SAMPLE_TYPE, mActualOutputFormat); return DRAIN_STATE_SHOULD_RETRY_IMMEDIATELY; mEncoder.releaseOutputBuffer(result, false); return DRAIN_STATE_SHOULD_RETRY_IMMEDIATELY; mEncoder.releaseOutputBuffer(result, false); return DRAIN_STATE_CONSUMED;
private void startMediaCodec() throws IOException { if (mMediaCodec != null) { return; } mMediaCodec = MediaCodec.createEncoderByType(MIME_TYPE); mMediaCodec.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mMediaCodec.start(); Log.i(TAG, "prepareAudio finishing"); prepareAudioRecord(); isStart = true; }
@Before public void startMediaCodec() throws IOException { MediaFormat format = getBasicAACFormat(); callback = mock(MediaCodecCallback.class); codec = MediaCodec.createByCodecName("fakePassthroughCodec"); codec.setCallback(callback); codec.configure( format, /* surface= */ null, /* crypto= */ null, MediaCodec.CONFIGURE_FLAG_ENCODE); codec.start(); }