Android音视频编码分为软编和硬编两种。所谓的硬编是用设备GPU去实现编解码,从而减轻CPU的压力,让程序更加的健壮,自然而然你就知道了软编其实就是让CPU编码(其实是在c层通过c/c++进行编码,之所以这样是因为c/c++平台上已经有很多比较好的音视频编解码库。比如著名ffmpeg,搞过音视频的相信对这个库绝对不会陌生)。那么或许你心目中有一个小小的疑问?为什么要编解码了?原因就是让数据更小便于传输。编解码就好比是压缩与解压!本文是把PCM数据硬编成ACC格式数据。如果对音频的采集不熟悉,请查阅Android 音频采集。

读取原始数据:

public class AudioData {public ByteBuffer buffer; //存储原始音频数据的bufferpublic int size; //buffer大小
}
  //读取音频数据(原始音频数据)private int readData(AudioData data){if(mAudioRecord==null){//检查是否初始化return -1;}if(data==null){return -1;}//开辟大小为640字节的byteBufferif(data.buffer==null){data.buffer=ByteBuffer.allocateDirect(640);}else{if(data.buffer.capacity()<640) {data.buffer=ByteBuffer.allocate(640);}}//把音频读取到data.buffer中,期望读取640个byte,返回值表示实际读取多个bytedata.size=mAudioRecord.read(data.buffer,640);if(data.size==AudioRecord.ERROR_BAD_VALUE){//AudioRecord对象参数不可用return -1;}return 0;}

把原始的音频数据读取到ByteBuffer中,ByteBuffer是nio包中引用的,相对传统的io包要快的多,如果对ByteBuffer不熟悉请查阅图解ByteBuffer。   android平台上的音视频硬编码主要就是通过MediaCodec进行实现的。

  //创建编码器@SuppressLint("NewApi")private int createEncoder(){//防止重复创建编码器if(mediaCodec!=null){return 0;}try {mediaCodec=MediaCodec.createEncoderByType("audio/mp4a-latm");} catch (Exception e) {e.printStackTrace();return -1;}// AAC 硬编码器MediaFormat format = new MediaFormat();format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");format.setInteger(MediaFormat.KEY_CHANNEL_COUNT,1); //声道数(这里是数字)format.setInteger(MediaFormat.KEY_SAMPLE_RATE,mSampleRateInHz); //采样率format.setInteger(MediaFormat.KEY_BIT_RATE,9600); //码率format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);bufferInfo=new MediaCodec.BufferInfo();//记录编码完成的buffer的信息mediaCodec.configure(format, null, null,MediaCodec.CONFIGURE_FLAG_ENCODE);// MediaCodec.CONFIGURE_FLAG_ENCODE 标识为编码器mediaCodec.start();return 0;}
  //停止编码@SuppressLint("NewApi")private int stopEncoder(){if(mediaCodec==null){return -1;}mediaCodec.stop();mediaCodec.release();return 0;}

或许你在烦恼配置MediaCodec时用到的MediaFormat 我怎么知道其中应该配置哪些属性了? 放心答案就在下图:(也可直接访问官网查,当然需要翻墙 编解码所需要的MediaFormat属性)

  //编码@SuppressLint("NewApi")private int encode(AudioData result){if(mediaCodec==null){return -1;}//把数据拷贝到byte数组中byte[] data=new byte[result.size];result.buffer.get(data);result.buffer.flip();inputBuffers=mediaCodec.getInputBuffers();outputBuffers=mediaCodec.getOutputBuffers();//  <0一直等待可用的byteBuffer 索引;=0 马上返回索引 ;>0 等待相应的毫秒数返回索引inputBufferIndex=mediaCodec.dequeueInputBuffer(-1); //一直等待(阻塞)if(inputBufferIndex>=0){  //拿到可用的buffer索引了inputBuffer=inputBuffers[inputBufferIndex];inputBuffer.clear();inputBuffer.put(data);mediaCodec.queueInputBuffer(inputBufferIndex,0,result.size,0,0); //投放到编码队列里去}//获取已经编码成的buffer的索引  0表示马上获取 ,>0表示最多等待多少毫秒获取outputBufferIndex=mediaCodec.dequeueOutputBuffer(bufferInfo,0);while(outputBufferIndex>=0){//------------添加头信息--------------int outBitsSize = bufferInfo.size;int outPacketSize = outBitsSize + 7; // 7 is ADTS sizebyte[]outData= new byte[outPacketSize];outputBuffer = outputBuffers[outputBufferIndex];outputBuffer.position(bufferInfo.offset);outputBuffer.limit(bufferInfo.offset + bufferInfo.size);addADTStoPacket(outData,outPacketSize,mSampleRateInHz,1);//添加头outputBuffer.get(outData,7,outBitsSize);try {ou.write(outData);} catch (IOException e) {e.printStackTrace();}mediaCodec.releaseOutputBuffer(outputBufferIndex, false);outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);}return 0;}
   /*** 添加头部信息* Add ADTS header at the beginning of each and every AAC packet. This is* needed as MediaCodec encoder generates a packet of raw AAC data.* Note the packetLen must count in the ADTS header itself.* packet 数据* packetLen 数据长度* sampleInHz 采样率* chanCfgCounts 通道数**/private  void addADTStoPacket(byte[] packet, int packetLen,int sampleInHz,int chanCfgCounts) {int profile = 2; // AAC LCint freqIdx = 8; // 16KHz    39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;switch (sampleInHz){case 8000:{freqIdx = 11; break;  }case 16000:{freqIdx = 8; break;}default:break;}int chanCfg = chanCfgCounts; // CPE// fill in ADTS datapacket[0] = (byte) 0xFF;packet[1] = (byte) 0xF9;packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));packet[4] = (byte) ((packetLen & 0x7FF) >> 3);packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);packet[6] = (byte) 0xFC;}

整片文章中最重要的就是编码这部分 ,编码AAC文件格式的音频时需要添加头的,要不然是没有办法进行正常播放的。添加头部信息,详细可以查阅该文:ADTS格式解析

最后是录音以及编码的调用封装方法:(全部完整代码,请在文章最后下载AAC音频硬编可播放Demo查阅)

  //录音以及编码private void Recording(){isStart=true;File file=null;int result=startRecord();//开始录音if(result==0){file=new File(parent,String.valueOf(SystemClock.elapsedRealtime())+".aac"); final String a=file.getAbsolutePath();try {file.createNewFile();runOnUiThread(new Runnable() {@Overridepublic void run() {path.setText("文件存目路径:"+a);}});} catch (IOException e) {e.printStackTrace();Log.e("ZL","创建文件出错");}}if(file!=null){try {ou=new FileOutputStream(file);} catch (FileNotFoundException e) {e.printStackTrace();Log.e("ZL","创建输出流出错");}}int result1=createEncoder(); //创建编码器if(result1==0){runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(MainActivity.this,"创建编码器成功",Toast.LENGTH_SHORT).show();}});}AudioData data=new AudioData();while(isStart){int result2=readData(data);if(result2==0){encode(data);Log.e("ZL","录音成功");}}stopRecord();  //停止录音stopEncoder(); //停止编码if(ou!=null){try {ou.close();} catch (IOException e) {e.printStackTrace();Log.e("ZL","关闭输出流出错");}}}

截止至2016/10/10为止,目前android平台支持的音视频硬编码格式(当然大家也可访问这个网址android平台支持的音视频硬编码格式进行查看。ps:要想打开这个网址需要翻墙,中国长城防火墙实在是太厚太高啦,翻墙的方法大家百度下就知道啦。),如下图所示:

转载请申明出处 http://blog.csdn.net/java_android_c/article/details/52775769

备注:

AAC音频硬编可播放Demo 用手机上支持aac格式的播放器就可以播放

注意添加相应的权限:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Android音频AAC硬编码相关推荐

  1. 1小时学会:最简单的iOS直播推流(七)h264/aac 硬编码

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  2. 大厂卡你的学历,究竟是为了什么?,android开发视频硬编码

    因此Android工程师的养成,一部分依然靠纯自学,大部分则靠培训,无论「培训」背负了多少的骂名,但整个Android行业,二三十万的从业者,抛开少部分大学计算机科班和软件工程相关专业的,绝大多数都是 ...

  3. android aac硬解码,android AAC的音频硬解码

    android AAC的音频硬解码 上一篇写了AAC音频的硬编码,今天补充硬解码,其实就是硬编码反过来,非常简单 初始化AAC硬解码资源: public int Start() { int iRet ...

  4. 1小时学会:最简单的iOS直播推流(八)h264/aac 软编码

    最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!! 源 ...

  5. 视频直播推流技术(MediaCodec硬编码+libRTMP,编码器),Demo - Android

    - aac audio_codec; h264,video_codec;25 framerate 25帧; - Camera-YUV帧序列-YUV帧预处理(镜像 缩放 旋转)-编码器-H264数据 从 ...

  6. 音频编解码(软/硬编码),音频转码

    > 音频编解码(软编码) FFMpeg视频软件编解码的.B站的ijkplayer等. 音频数据的编解码- http://blog.51cto.com/ticktick/1760191 1.And ...

  7. android硬编码封装mp4,【Android 音视频开发打怪升级:音视频硬解码篇】四、音视频解封和封装:生成一个MP4...

    [声 明] 首先,这一系列文章均基于自己的理解和实践,可能有不对的地方,欢迎大家指正. 其次,这是一个入门系列,涉及的知识也仅限于够用,深入的知识网上也有许许多多的博文供大家学习了. 最后,写文章过程 ...

  8. iOS音频AAC视频H264编码 推流最佳方案

    1    功能概况 *  实现音视频的数据的采集 *  实现音视频数据的编码,视频编码成h264,音频编码成aac *  实现音视频数据的发布,将编码好的音视频数据传输到服务器 2 视频和音频编码方案 ...

  9. Android安全开发之浅谈密钥硬编码

    Android安全开发之浅谈密钥硬编码 作者:伊樵.呆狐@阿里聚安全 1 简介 在阿里聚安全的漏洞扫描器中和人工APP安全审计中,经常发现有开发者将密钥硬编码在Java代码.文件中,这样做会引起很大风 ...

最新文章

  1. HDU4920(矩阵连乘)
  2. 汇编语言随笔(13)- 外中断(可屏蔽中断)、实验15
  3. java 在线支付_java如何实现在线支付讲解
  4. 可到了关键部分的作文
  5. shell中 if else以及大于、小于、等于逻辑表达式介绍
  6. “七”待已久,“夕”望是你,“快”来学习,“乐”在其中!
  7. LTE物理层一些基本概念
  8. [经验教程]2022网线水晶头插座接头排线接线顺序与方法图解
  9. Adobe Premiere基础-声音调整(音量矫正,降噪,电话音,音高换挡器,参数均衡器)(十八)
  10. 腾讯认证QQ空间秒升级为专业版方法!
  11. html5中的 hr定位,被大家遗忘的 hr 标签元素
  12. keras调试的正确打开方式: 一句话让你把tensorflow当pytorch用
  13. WORD2003相关问题
  14. 谁应该去读 C++ Programming Language
  15. matlab 三叶线,面积计算求三叶线r=asin3φ所围成的面 – 手机爱问
  16. 最近,我读完了张小龙的2351条饭否
  17. java+mysql简单实现点赞评论转发帖子
  18. 【酒店管理系统】(三)项目介绍-RuoYi
  19. Beam Cannon HDU - 5091 (扫描线) 求矩形内的点的数量
  20. 2012互联网趋势报告详览:互联网女皇眼中的移动互联网

热门文章

  1. redis学习之redis的发布和订阅
  2. 小程序源码:独家修复登录接口社区论坛-多玩法安装简单
  3. 高德地图只显示部分区域
  4. Windows超级管理器-便携版
  5. MySQL高可用架构-MMM环境部署记录
  6. 元宇宙:虚拟仿真技术的全面提升
  7. 高数下|级数4|手写笔记(绝对收敛与条件收敛)
  8. python基础思维导图
  9. YOLO算法(一)——Yolo介绍 Yolov1
  10. 音频直播,这里面到底有多少坑