下面列出了android.media.MediaCodec# getInputBuffer ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private ByteBuffer getInputBuffer(MediaCodec codec, int index){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return codec.getInputBuffer(index);
}else{
return codec.getInputBuffers()[index];
}
}
private ByteBuffer getInputBuffer(MediaCodec codec, int index){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return codec.getInputBuffer(index);
}else{
return codec.getInputBuffers()[index];
}
}
public static ByteBuffer getInputBuffer(MediaCodec codec, int index){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return codec.getInputBuffer(index);
}else{
return codec.getInputBuffers()[index];
}
}
/**
* Handle providing raw audio to MediaCodec InputBuffer
* @param codec
* @param inputBufferId
* @return number bytes provided
* @throws IOException
*/
private int queueCodecInputBuffer(MediaCodec codec, int inputBufferId) throws IOException {
ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
inputBuffer.clear();
int bytesAvailable = inputAudioStream.available();
int bytesToWrite = bytesAvailable < inputBuffer.limit() ? bytesAvailable : inputBuffer.limit();
inputBuffer.put(IOUtils.toByteArray(inputAudioStream, bytesToWrite));
codec.queueInputBuffer(inputBufferId, 0, bytesToWrite, 0, 0);
return bytesToWrite;
}
@Override
public void inputAvailable(@NonNull MediaCodec mediaCodec, int inBufferIndex, Frame frame)
throws IllegalStateException {
ByteBuffer byteBuffer;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
byteBuffer = mediaCodec.getInputBuffer(inBufferIndex);
} else {
byteBuffer = mediaCodec.getInputBuffers()[inBufferIndex];
}
processInput(byteBuffer, mediaCodec, inBufferIndex, frame);
}
/**
* 防止出现 http://stackoverflow.com/q/30646885 的问题
*
* @param codec
* @param index
* @return
*/
public static ByteBuffer getInputBuffer(MediaCodec codec, int index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return codec.getInputBuffer(index);
} else {
return codec.getInputBuffers()[index];
}
}
/**
* バイト配列をエンコードする場合(API21/Android5以降)
* @param buffer
* @param length 書き込むバイト配列の長さ。0ならBUFFER_FLAG_END_OF_STREAMフラグをセットする
* @param presentationTimeUs [マイクロ秒]
*/
@SuppressLint("NewApi")
private void encodeV21(@NonNull final MediaCodec encoder,
@Nullable final ByteBuffer buffer, final int length, final long presentationTimeUs) {
for ( ; isRecording() && !mIsEos ;) {
final int inputBufferIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
if (inputBufferIndex >= 0) {
final ByteBuffer inputBuffer = encoder.getInputBuffer(inputBufferIndex);
inputBuffer.clear();
if (buffer != null) {
inputBuffer.put(buffer);
}
// if (DEBUG) Log.v(TAG, "encode:queueInputBuffer");
if (length <= 0) {
// エンコード要求サイズが0の時はEOSを送信
mIsEos = true;
// if (DEBUG) Log.i(TAG, "send BUFFER_FLAG_END_OF_STREAM");
encoder.queueInputBuffer(inputBufferIndex, 0, 0,
presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
encoder.queueInputBuffer(inputBufferIndex, 0, length,
presentationTimeUs, 0);
}
break;
// } else if (inputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
// 送れるようになるまでループする
// MediaCodec#dequeueInputBufferにタイムアウト(10ミリ秒)をセットしているのでここでは待機しない
}
}
}
private ByteBuffer getInputBuffer(MediaCodec codec, int index) {
return codec.getInputBuffer(index);
}
private void decodeFrames(final MediaCodec decoder, MediaExtractor extractor, MediaFormat mediaFormat) {
boolean sawInputEOS = false;
sawOutputEOS = false;
decoder.configure(mediaFormat, null, null, 0);
decoder.start();
if(!Helper.isUpperThanAPI21()) {
inputByteBuffers = decoder.getInputBuffers();
outputByteBuffers = decoder.getOutputBuffers();
}
while (!sawOutputEOS && !stopDecode) {
if (!sawInputEOS) {
int inputBufferId = decoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);
if (inputBufferId >= 0) {
ByteBuffer inputBuffer = null;
if (Helper.isUpperThanAPI21()) {
inputBuffer = decoder.getInputBuffer(inputBufferId);
} else {
inputBuffer = inputByteBuffers[inputBufferId];
}
int sampleSize = extractor.readSampleData(inputBuffer, 0);
if (sampleSize < 0) {
decoder.queueInputBuffer(inputBufferId, 0, 0, 0L, 0);
sawInputEOS = false;
extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
} else {
long presentationTimeUs = extractor.getSampleTime();
decoder.queueInputBuffer(inputBufferId, 0, sampleSize, presentationTimeUs, 0);
extractor.advance();
}
}
}
if(displayThread==null) {
displayThread = new Thread(new Runnable() {
@Override
public void run() {
while (!sawOutputEOS && !stopDisplay) {
frameDisplay(decoder);
}
}
});
displayThread.start();
}
}
}
/**
* 需要改变音频速率的情况下,需要先解码->改变速率->编码
*/
private void decodeToPCM(MediaCodec decoder, MediaExtractor extractor, MediaFormat oriAudioFormat, String outPath, Long endTimeUs) throws IOException {
int maxBufferSize = getAudioMaxBufferSize(oriAudioFormat);
ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
//调整音频速率需要重解码音频帧
decoder.configure(oriAudioFormat, null, null, 0);
decoder.start();
boolean decodeDone = false;
boolean decodeInputDone = false;
final int TIMEOUT_US = 2500;
File pcmFile = new File(outPath);
FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel();
ByteBuffer[] inputBuffers = null;
ByteBuffer[] outputBuffers = null;
try {
while (!decodeDone) {
if (!decodeInputDone) {
boolean eof = false;
int decodeInputIndex = decoder.dequeueInputBuffer(TIMEOUT_US);
if (Build.VERSION.SDK_INT < 21 && decodeInputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
outputBuffers = decoder.getOutputBuffers();
inputBuffers = decoder.getInputBuffers();
} else if (decodeInputIndex >= 0) {
long sampleTimeUs = extractor.getSampleTime();
if (sampleTimeUs == -1) {
eof = true;
} else if (endTimeUs != null && sampleTimeUs > endTimeUs) {
eof = true;
}
if (eof) {
decodeInputDone = true;
decoder.queueInputBuffer(decodeInputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
info.size = extractor.readSampleData(buffer, 0);
info.presentationTimeUs = sampleTimeUs;
info.flags = extractor.getSampleFlags();
ByteBuffer inputBuffer = null;
if (android.os.Build.VERSION.SDK_INT >= 21) {
inputBuffer = decoder.getInputBuffer(decodeInputIndex);
} else {
inputBuffer = inputBuffers[decodeInputIndex];
}
inputBuffer.put(buffer);
MLog.i(TAG, "audio decode queueInputBuffer " + info.presentationTimeUs / 1000);
decoder.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags);
extractor.advance();
}
}
}
while (!decodeDone) {
int outputBufferIndex = decoder.dequeueOutputBuffer(info, TIMEOUT_US);
if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
break;
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = decoder.getOutputFormat();
MLog.i(TAG, "audio decode newFormat = " + newFormat);
} else if (outputBufferIndex < 0) {
//ignore
MLog.e(TAG, "unexpected result from audio decoder.dequeueOutputBuffer: " + outputBufferIndex);
} else {
if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
decodeDone = true;
} else {
ByteBuffer decodeOutputBuffer = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
decodeOutputBuffer = decoder.getOutputBuffer(outputBufferIndex);
} else {
decodeOutputBuffer = outputBuffers[outputBufferIndex];
}
MLog.i(TAG, "audio decode saveFrame " + info.presentationTimeUs / 1000);
writeChannel.write(decodeOutputBuffer);
}
decoder.releaseOutputBuffer(outputBufferIndex, false);
}
}
}
} finally {
writeChannel.close();
extractor.release();
decoder.stop();
decoder.release();
}
}
/**
* 需要改变音频速率的情况下,需要先解码->改变速率->编码
*/
public static void decodeToPCM(VideoProcessor.MediaSource audioSource, String outPath, Integer startTimeUs, Integer endTimeUs) throws IOException {
MediaExtractor extractor = new MediaExtractor();
audioSource.setDataSource(extractor);
int audioTrack = VideoUtil.selectTrack(extractor, true);
extractor.selectTrack(audioTrack);
if (startTimeUs == null) {
startTimeUs = 0;
}
extractor.seekTo(startTimeUs, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
MediaFormat oriAudioFormat = extractor.getTrackFormat(audioTrack);
int maxBufferSize;
if (oriAudioFormat.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
maxBufferSize = oriAudioFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
} else {
maxBufferSize = 100 * 1000;
}
ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
//调整音频速率需要重解码音频帧
MediaCodec decoder = MediaCodec.createDecoderByType(oriAudioFormat.getString(MediaFormat.KEY_MIME));
decoder.configure(oriAudioFormat, null, null, 0);
decoder.start();
boolean decodeDone = false;
boolean decodeInputDone = false;
final int TIMEOUT_US = 2500;
File pcmFile = new File(outPath);
FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel();
try {
while (!decodeDone) {
if (!decodeInputDone) {
boolean eof = false;
int decodeInputIndex = decoder.dequeueInputBuffer(TIMEOUT_US);
if (decodeInputIndex >= 0) {
long sampleTimeUs = extractor.getSampleTime();
if (sampleTimeUs == -1) {
eof = true;
} else if (sampleTimeUs < startTimeUs) {
extractor.advance();
continue;
} else if (endTimeUs != null && sampleTimeUs > endTimeUs) {
eof = true;
}
if (eof) {
decodeInputDone = true;
decoder.queueInputBuffer(decodeInputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
} else {
info.size = extractor.readSampleData(buffer, 0);
info.presentationTimeUs = sampleTimeUs;
info.flags = extractor.getSampleFlags();
ByteBuffer inputBuffer = decoder.getInputBuffer(decodeInputIndex);
inputBuffer.put(buffer);
CL.it(TAG, "audio decode queueInputBuffer " + info.presentationTimeUs / 1000);
decoder.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags);
extractor.advance();
}
}
}
while (!decodeDone) {
int outputBufferIndex = decoder.dequeueOutputBuffer(info, TIMEOUT_US);
if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
break;
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = decoder.getOutputFormat();
CL.it(TAG, "audio decode newFormat = " + newFormat);
} else if (outputBufferIndex < 0) {
//ignore
CL.et(TAG, "unexpected result from audio decoder.dequeueOutputBuffer: " + outputBufferIndex);
} else {
if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
decodeDone = true;
} else {
ByteBuffer decodeOutputBuffer = decoder.getOutputBuffer(outputBufferIndex);
CL.it(TAG, "audio decode saveFrame " + info.presentationTimeUs / 1000);
writeChannel.write(decodeOutputBuffer);
}
decoder.releaseOutputBuffer(outputBufferIndex, false);
}
}
}
} finally {
writeChannel.close();
extractor.release();
decoder.stop();
decoder.release();
}
}
private static void renderHevcImage(ByteBuffer bitstream, ImageInfo info, Surface surface) {
long beginTime = SystemClock.elapsedRealtimeNanos();
// configure HEVC decoder
MediaCodec decoder = configureDecoder(info, bitstream.limit(), surface);
MediaFormat outputFormat = decoder.getOutputFormat();
Log.d(TAG, "HEVC output-format=" + outputFormat);
decoder.start();
try {
// set bitstream to decoder
int inputBufferId = decoder.dequeueInputBuffer(-1);
if (inputBufferId < 0) {
throw new IllegalStateException("dequeueInputBuffer return " + inputBufferId);
}
ByteBuffer inBuffer = decoder.getInputBuffer(inputBufferId);
inBuffer.put(bitstream);
decoder.queueInputBuffer(inputBufferId, 0, bitstream.limit(), 0, 0);
// notify end of stream
inputBufferId = decoder.dequeueInputBuffer(-1);
if (inputBufferId < 0) {
throw new IllegalStateException("dequeueInputBuffer return " + inputBufferId);
}
decoder.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
// get decoded image
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
while (true) {
int outputBufferId = decoder.dequeueOutputBuffer(bufferInfo, -1);
if (outputBufferId >= 0) {
decoder.releaseOutputBuffer(outputBufferId, true);
break;
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
outputFormat = decoder.getOutputFormat();
Log.d(TAG, "HEVC output-format=" + outputFormat);
} else {
Log.d(TAG, "HEVC dequeueOutputBuffer return " + outputBufferId);
}
}
decoder.flush();
} finally {
decoder.stop();
decoder.release();
}
long endTime = SystemClock.elapsedRealtimeNanos();
Log.i(TAG, "HEVC decoding elapsed=" + (endTime - beginTime) / 1000000.f + "[msec]");
}