// 添加数据 inputByteBuf.put(data); // 限制ByteBuffer的访问长度 inputByteBuf.limit(data.length); // 把输入缓存塞回去给MediaCodec mMediaEncoder.queueInputBuffer(inputIndex, 0, data.length, 0, 0); // mAudioEncoder.queueInputBuffer(inputBufIndex, 0, data.length, (1000000 * mEncodedSize / AUDIO_BYTE_PER_SAMPLE), 0); // 有些设备不设置好presentationTimeUs会丢帧 // 这里的1000000是把秒变成微秒,音频输出的时间戳是微秒,输出到surface的视频是纳秒,源码中是这么说的: // * @param presentationTimeUs The presentation timestamp in microseconds for this // * buffer. This is normally the media time at which this // * buffer should be presented (rendered). When using an output // * surface, this will be propagated as the {@link // * SurfaceTexture#getTimestamp timestamp} for the frame (after // * conversion to nanoseconds).
获取输出缓存和获取输入缓存类似,首先通过dequeueOutputBuffer(BufferInfo info, long timeoutUs)来请求一个输出缓存,这里需要传入一个BufferInfo对象,用于存储ByteBuffer的信息
MediaCodeccodec= MediaCodec.createByCodecName(name); codec.configure(format, …); MediaFormatoutputFormat= codec.getOutputFormat(); // option B codec.start(); for (;;) { intinputBufferId= codec.dequeueInputBuffer(timeoutUs); if (inputBufferId >= 0) { ByteBufferinputBuffer= codec.getInputBuffer(…); // fill inputBuffer with valid data … codec.queueInputBuffer(inputBufferId, …); } intoutputBufferId= codec.dequeueOutputBuffer(…); if (outputBufferId >= 0) { ByteBufferoutputBuffer= codec.getOutputBuffer(outputBufferId); MediaFormatbufferFormat= codec.getOutputFormat(outputBufferId); // option A // bufferFormat is identical to outputFormat // outputBuffer is ready to be processed or rendered. … codec.releaseOutputBuffer(outputBufferId, …); } elseif (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { // Subsequent data will conform to new format. // Can ignore if using getOutputFormat(outputBufferId) outputFormat = codec.getOutputFormat(); // option B } } codec.stop(); codec.release();
MediaCodeccodec= MediaCodec.createByCodecName(name); MediaFormat mOutputFormat; // member variable codec.setCallback(newMediaCodec.Callback() { @Override voidonInputBufferAvailable(MediaCodec mc, int inputBufferId) { ByteBufferinputBuffer= codec.getInputBuffer(inputBufferId); // fill inputBuffer with valid data … codec.queueInputBuffer(inputBufferId, …); } @Override voidonOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) { ByteBufferoutputBuffer= codec.getOutputBuffer(outputBufferId); MediaFormatbufferFormat= codec.getOutputFormat(outputBufferId); // option A // bufferFormat is equivalent to mOutputFormat // outputBuffer is ready to be processed or rendered. … codec.releaseOutputBuffer(outputBufferId, …); } @Override voidonOutputFormatChanged(MediaCodec mc, MediaFormat format) { // Subsequent data will conform to new format. // Can ignore if using getOutputFormat(outputBufferId) mOutputFormat = format; // option B } @Override voidonError(…) { … } }); codec.configure(format, …); mOutputFormat = codec.getOutputFormat(); // option B codec.start(); // wait for processing to complete codec.stop(); codec.release();
/** * 寻找指定buffer中AAC帧头的开始位置 * * @param startIndex 开始的位置 * @param data 数据 * @param max 需要检测的最大值 * @return */ privateintfindHead(byte[] data, int startIndex, int max) { int i; for (i = startIndex; i <= max; i++) { // 发现帧头 if (isHead(data, i)) break; } // 检测到最大值,未发现帧头 if (i == max) { i = -1; } return i; }