安卓支持aac编码吗_aac音频格式

安卓支持aac编码吗_aac音频格式android音频AAC硬编码,完整事例,可用播放器播放收听…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

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

读取原始数据:

public class AudioData {
    public ByteBuffer buffer; //存储原始音频数据的buffer
    public int size; //buffer大小
}
  //读取音频数据(原始音频数据)
		private int readData(AudioData data){
			
			if(mAudioRecord==null){//检查是否初始化
				return -1;
			}
			
			if(data==null){
				return -1;
			}
			
			//开辟大小为640字节的byteBuffer
			if(data.buffer==null){
				 data.buffer=ByteBuffer.allocateDirect(640);
			}else{
				if(data.buffer.capacity()<640) {
				   data.buffer=ByteBuffer.allocate(640);
				}
			}
			
			//把音频读取到data.buffer中,期望读取640个byte,返回值表示实际读取多个byte
			data.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属性

安卓支持aac编码吗_aac音频格式

  //编码
	@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 size
            byte[]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 LC
	  int 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 data
	  packet[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() {
					@Override
					public 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() {
				@Override
				public 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:要想打开这个网址需要翻墙,中国长城防火墙实在是太厚太高啦,翻墙的方法大家百度下就知道啦。),如下图所示:

安卓支持aac编码吗_aac音频格式

    转载请申明出处 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" />
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/179191.html原文链接:https://javaforall.net

(0)
上一篇 2022年8月30日 上午11:36
下一篇 2022年8月30日 上午11:36


相关推荐

  • 〖Python零基础入门篇④〗- Pycharm插件安装与常用的插件

    〖Python零基础入门篇④〗- Pycharm插件安装与常用的插件插件是安装在特定程序上软件组件,以增强程序某项功能。一个好的IDE都会提供插件平台,允许第三方在遵循插件平台集成条款的前提下,使用插件平台对外提供的能力,扩展出更广泛更丰富的功能。PyCharm提供了大量商业与免费插件,内容涉及了方方面面,开发者根据工作的实际需要,可以在Marketplace搜索对应的插件,合理的使用正确插件,将极大的提高开发效率,并且保证代码质量。

    2022年6月24日
    35
  • Teradata SQL 笔记

    Teradata SQL 笔记HELP 帮助用户了解数据库中各种对象的结构 nbsp SHOW 帮助用户了解某种对象的定义 即返回其 DDL 语句 nbsp EXPLAIN 返回一个 SQL 语句经优化处理后的执行步骤 注意并未真正执行 nbsp FALLBACK 对数据加以保护的一种方式 是冗余的备份 nbsp RENAME 对表重命名 nbsp NULLIFZERO 对数据作累计处理时 忽略零值 nbsp ZEROIFNULL 对数据作累计处理时 将空值作零处理 nbsp

    2026年3月17日
    2
  • wireshark抓包分析TCP和UDP_ipv4数据包分析

    wireshark抓包分析TCP和UDP_ipv4数据包分析在命令行输入ifconfig,查看本机网络接口。$ifconfigenp4s0:flags=4099<UP,BROADCAST,MULTICAST>mtu1500etherc8:5b:76:f6:44:d2txqueuelen1000(Ethernet)RXpackets0bytes0(0.0B)…

    2025年7月3日
    5
  • sap 获取计划订单bapi_SAP 生产模块常用BAPI「建议收藏」

    sap 获取计划订单bapi_SAP 生产模块常用BAPI「建议收藏」工艺路线BAPI_ROUTING_CREATE创建工艺路线BAPI_ROUTING_EXISTENCE_CHECK检查工艺路线是否存在参考操作集BAPI_REFSETOFOPERATIONS_CREATE创建参考操作集BAPI_REFSETOFOPR_EXISTENCE_CHK检查参考操作集是否存在计划订单BAPI_PLANNEDORDER_CREATE创建计划订单BAPI_PLANNEDORDE…

    2022年7月24日
    68
  • 深入浅出WPF——什么是WPF

    深入浅出WPF——什么是WPF什么是 WPF WPF WindowsPrese 也 译过来就是 Windows 呈现基础 你看它的目的非常明确 就是用来把数据 显示 给用户看的 说白了就是用来做 UI 的 如果只是给用户显示几串文本 两三张图片或者几个表格那 WPF 就太糗了 幸乎 WPF 可不是这等素食动物 大家都见过 Flash 动画吧 WPF 的显示能力丝毫不亚于 Flash 以及 Flash 的同门师弟

    2026年3月16日
    1
  • Cursor 进阶课程:从入门到精通的AI编程助手完全指南

    Cursor 进阶课程:从入门到精通的AI编程助手完全指南

    2026年3月16日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号