音视频的编码可以使用硬编码和软编码两钟,在项目开始之初,由于种种原因选择了ffmpeg软编码音视频,软编码可想而知,花费时间太长,编码一帧视频在不同的设备上可以达到几十毫秒到几百毫秒,编码太长,后来才发现android早在4.1就有MediaCodec的硬编码功能(项目开始调研不足,功力不够总是要走很多弯路),这个时候也能满足我们的需求,我们就推翻了ffmpeg编码,转而使用MediaCodec编码AAC和H264。MediaCode编码应该是只要会写andriod,应该都能用,非常之简单,填上需要的参数,基本就可以编码了。(下一篇将介绍,ffmpeg编码音视频,虽然现在没用上,也许以后有用也未必哇)
下面介绍使用MediaCodec编码AAC音频:
1,音频源来自AudioRecord
初始化AudioRecord需要三个参数
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
public static int sampleRateInHz = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
aac格式对应的encoder type是audio/mp4a-latm,MediaCodec还支持amr mp3等音频格式和avc mpeg4 h263等视频格式,可以参考 ./frameworks/av/media/libstagefright/omx/tests/OMXHarness.cpp类寻找需要的音频和视频格式。声道数和AudioRecord的声道数相同,为双声道,码率64kbps
其中需要注意的有dequeueInputBuffer(-1),参数表示需要得到的毫秒数,-1表示一直等,0表示不需要等,传0的话程序不会等待,但是有可能会丢帧。
dequeueOutputBuffer方法表示dequeue output buffer ,返回成功decode的output buffer的index,返回值有时候有时候大于等于0有时候小于0,
小于0表示MediaCodec没有成功decode,大于等于0表示成功decode。编码器正常的流程是喂一次数据吐一次数据,但少数时候,编码器并不会严格按照这个流程执行,有可能你往编码器喂了几次数据,编码器都没有准备好输出数据,那么编码器将不会吐出数据,有的时候编码器把之前没有处理好的数据,在这一次吐出数据的时候,又会吐出多次数据,所以这里用了while,在结束的时候去查询是否编码器的还有数据没有吐出来。
这里基本可以成功,加上aac头就可以播放流或者保存为aac文件了。
然后呢,h264的硬编码就和音频差不多了,设置MediaCodec的mime ,宽高,码率,帧率,i帧就可以转码视频,在视频编码所需时间比较多,可以设置两个buffer
mFormat->setInt32("nbbf", 2);//kKeyNumBuffers
使用MediaCodec对视频的编码,平均耗费2ms左右,这个时间大大缩小了编码时间。
下面介绍使用MediaCodec编码AAC音频:
1,音频源来自AudioRecord
初始化AudioRecord需要三个参数
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
public static int sampleRateInHz = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
2,MediaCodec的初始化
mediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm");
MediaFormat mediaFormat = new MediaFormat();
mediaFormat.setString("mime", "audio/mp4a-latm");
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, TestHardWareAAC.sampleRateInHz);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 64000);// AAC-HE // 64kbps
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,MediaCodecInfo.CodecProfileLevel.AACObjectLC);//AACObjectLC
mediaCodec.configure(mediaFormat, null, null,MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
aac格式对应的encoder type是audio/mp4a-latm,MediaCodec还支持amr mp3等音频格式和avc mpeg4 h263等视频格式,可以参考 ./frameworks/av/media/libstagefright/omx/tests/OMXHarness.cpp类寻找需要的音频和视频格式。声道数和AudioRecord的声道数相同,为双声道,码率64kbps
3,从AudioRecord出来的数据通过MediaCodec处理,输出硬编码需要的格式
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length,0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);
while (outputBufferIndex >= 0) {
outputBuffer = outputBuffers[outputBufferIndex];
outputBuffer.position(bufferInfo.offset);
outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
System.arraycopy(outData, 0, output, pos, outData.length);
pos += outData.length;
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
其中需要注意的有dequeueInputBuffer(-1),参数表示需要得到的毫秒数,-1表示一直等,0表示不需要等,传0的话程序不会等待,但是有可能会丢帧。
dequeueOutputBuffer方法表示dequeue output buffer ,返回成功decode的output buffer的index,返回值有时候有时候大于等于0有时候小于0,
小于0表示MediaCodec没有成功decode,大于等于0表示成功decode。编码器正常的流程是喂一次数据吐一次数据,但少数时候,编码器并不会严格按照这个流程执行,有可能你往编码器喂了几次数据,编码器都没有准备好输出数据,那么编码器将不会吐出数据,有的时候编码器把之前没有处理好的数据,在这一次吐出数据的时候,又会吐出多次数据,所以这里用了while,在结束的时候去查询是否编码器的还有数据没有吐出来。
这里基本可以成功,加上aac头就可以播放流或者保存为aac文件了。
然后呢,h264的硬编码就和音频差不多了,设置MediaCodec的mime ,宽高,码率,帧率,i帧就可以转码视频,在视频编码所需时间比较多,可以设置两个buffer
mFormat->setInt32("nbbf", 2);//kKeyNumBuffers
使用MediaCodec对视频的编码,平均耗费2ms左右,这个时间大大缩小了编码时间。