编码分为软编和硬编,毫无疑问,能用硬编就用硬编,而Android/ target=_blank class=infotextkey>安卓硬编,绕不开MediaCodec 。
MediaCodec关于MediaCodec,官方文档有着详细的解答,这里就不赘述了 。
![android 音视频硬编解码](http://img.jiangsulong.com/220525/1502142119-0.jpg)
文章插图
视频硬编码我这里需要将相机实时预览的YUV数据,编码为H.264格式的数据,在开始编码之前,首先要
MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIMETYPE_VIDEO_AVC, width, height);mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height * 5);mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);try {mMediaCodec = MediaCodec.createEncoderByType(MIMETYPE_VIDEO_AVC);mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);mMediaCodec.start();} catch (Exception e) {e.printStackTrace();}
接下来就可以传入数据进行编码了private void encodeBuffer(@NonNull byte[] buffer, long pts) {int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_S);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = mMediaCodec.getInputBuffer(inputBufferIndex);inputBuffer.clear();inputBuffer.put(buffer);mMediaCodec.queueInputBuffer(inputBufferIndex, 0, buffer.length, pts, 0);}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_S);while (outputBufferIndex >= 0) {ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(outputBufferIndex);if (bufferInfo.flags == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {bufferInfo.size = 0;}if (bufferInfo.size > 0) {outputBuffer.position(bufferInfo.offset);outputBuffer.limit(bufferInfo.offset + bufferInfo.size);bufferInfo.presentationTimeUs = pts;// todo 编码后的数据,可做回调处理...}mMediaCodec.releaseoutputBuffer(outputBufferIndex, false);bufferInfo = new MediaCodec.BufferInfo();outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_S);}}
音频硬编码同时,将麦克风录制的PCM数据,编码为AAC格式的数据,同理,在开始编码之前MediaFormat mediaFormat = MediaFormat.createAudioFormat(MIMETYPE_AUDIO_AAC, sampleRateInHz, channelConfig == AudioFormat.CHANNEL_IN_MONO ? 1 : 2);mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 64000);mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, AudioRecord.getMinBufferSize(DEFAULT_SAMPLE_RATE_IN_HZ, DEFAULT_CHANNEL_CONFIG, DEFAULT_ENCODING) * 3);mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, channelConfig == AudioFormat.CHANNEL_IN_MONO ? 1 : 2);try {mMediaCodec = MediaCodec.createEncoderByType(MIMETYPE_AUDIO_AAC);mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);mMediaCodec.start();} catch (Exception e) {e.printStackTrace();}
同理,接下来就可以传入数据进行编码了private void encodeBuffer(@NonNull byte[] buffer, long pts) {int inputBufferIndex = mMediaCodec.dequeueInputBuffer(TIMEOUT_S);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = mMediaCodec.getInputBuffer(inputBufferIndex);inputBuffer.clear();inputBuffer.limit(buffer.length);inputBuffer.put(buffer);mMediaCodec.queueInputBuffer(inputBufferIndex, 0, buffer.length, pts, 0);}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_S);while (outputBufferIndex >= 0) {ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(outputBufferIndex);if (bufferInfo.flags == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {bufferInfo.size = 0;}if (bufferInfo.size > 0) {outputBuffer.position(bufferInfo.offset);outputBuffer.limit(bufferInfo.offset + bufferInfo.size);bufferInfo.presentationTimeUs = pts;// todo 编码后的数据,可做回调处理...}mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);bufferInfo = new MediaCodec.BufferInfo();outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_S);}}
可以发现,音视频编码流程是一样的,通过上面的操作,看起来数据的编码流程已经完成,接下来,就是解码了,同样的,解码也要用到的MediaCodec视频硬解码解码之前
try {mMediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);mMediaCodec.configure(mediaFormat, surface, null, 0);mMediaCodec.start();} catch (Exception e) {throw new RuntimeException(e);}
接下来便是解码已经编码好的H.264帧数据并在Surface中进行渲染public void decodeAndRenderV(byte[] in, int offset, int length, long pts) {int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);if (inputBufferIndex >= 0) {ByteBuffer inputBuffer = mMediaCodec.getInputBuffer(inputBufferIndex);inputBuffer.clear();inputBuffer.put(in, offset, length);mMediaCodec.queueInputBuffer(inputBufferIndex, 0, length, pts, 0);}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);while (outputBufferIndex >= 0) {mMediaCodec.releaseOutputBuffer(outputBufferIndex, true);outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_US);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 抖音葫芦娃?葫芦娃抖音视频
- 华为|华为自研技术征服谷歌!曝Android 13出厂默认EROFS文件系统
- 抖音视频搬运工怎么赚钱?搬视频到抖音怎么赚钱
- Windows操作系统|微软让Windows 11深度绑定Android 12:多个更新 用起来更爽
- 安卓手机如何打开.psd文件?
- Wireshark抓取Android数据包
- 小米12对比小米mix4?小米12比小米mix4更香_1
- 安卓|Android 13看点汇总:首批支持设备公布
- vivo|首批六款机型!OriginOS Android 13内测来了
- 旗舰|直板旗舰的终极形态 中兴Axon 40 Ultra首批支持Android 13