MediaCodec编译pcm为aac

音视频的编码可以使用硬编码和软编码两钟,在项目开始之初,由于种种原因选择了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;

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左右,这个时间大大缩小了编码时间。

你可能感兴趣的:(音视频)