Android音频编解码和混音实现

本文详细介绍了Android平台下数字音频的基本概念,包括采样频率、采样精度和声道数。接着,通过MediaExtractor和MediaCodec进行音频解码,将编码数据恢复为原始PCM数据。然后,探讨了音频混音的原理和简单的平均算法,并提供了混音数据的播放验证。最后,使用MediaCodec对混音后的音频进行ACC编码,讲解了ADTS帧结构和如何构建AAC音频文件。同时,文章提供相关参考资料和源代码链接。
摘要由CSDN通过智能技术生成


博客原文: http://www.darcye.com/article/00301860

相关源码:https://github.com/YeDaxia/MusicPlus



认识数字音频:

在实现之前,我们先来了解一下数字音频的有关属性。

采样频率(Sample Rate):每秒采集声音的数量,它用赫兹(Hz)来表示。(采样率越高越靠近原声音的波形)
采样精度(Bit Depth):指记录声音的动态范围,它以位(Bit)为单位。(声音的幅度差)
声音通道(Channel):声道数。比如左声道右声道。

采样量化后的音频最终是一串数字,声音的大小(幅度)会体现在这个每个数字数值大小上;而声音的高低(频率)和声音的音色(Timbre)都和时间维度有关,会体现在数字之间的差异上。

    在编码解码之前,我们先来感受一下原始的音频数据究竟是什么样的。我们知道wav文件里面放的就是原始的PCM数据,下面我们通过AudioTrack来直接把这些数据write进去播放出来。下面是某个wav文件的格式,关于wav的格式内容可以看:http://soundfile.sapp.org/doc/WaveFormat/ ,可以通过Binary Viewer等工具去查看一下wav文件的二进制内容。

播放wav文件:

int sampleRateInHz = 44100;
int channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

int bufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
AudioTrack audioTrack = new  AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, AudioTrack.MODE_STREAM);
audioTrack.play();
			
FileInputStream audioInput = null;
try {
	audioInput = new FileInputStream(audioFile);//put your wav file in

	audioInput.read(new byte[44]);//skid 44 wav header
	
	byte[] audioData = new byte[512];
	
	while(audioInput.read(audioData)!= -1){
		audioTrack.write(audioData, 0, audioData.length); //play raw audio bytes
	}
	
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}finally{
	audioTrack.stop();
	audioTrack.release();
	if(audioInput != null)
		try {
			audioInput.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
}

如果你有试过一下上面的例子,那你应该对音频的源数据有了一个概念了。

 音频的解码:

通过上面的介绍,我们不难知道,解码的目的就是让编码后的数据恢复成wav中的源数据。

利用MediaExtractor和MediaCodec来提取编码后的音频数据并解压成音频源数据:

final String encodeFile = "your encode audio file path";
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(encodeFile);

MediaFormat mediaFormat = null;
for (int i = 0; i < extractor.getTrackCount(); i++) {
	MediaFormat format = extractor.getTrackFormat(i);
	String mime = format.getString(MediaFormat.KEY_MIME);
	if (mime.startsWith("audio/")) {
		extractor.selectTrack(i);
		mediaFormat = format;
		break;
	}
}

if(mediaFormat == null){
	DLog.e("not a valid file with audio track..");
	extractor.release();
	return null;
}

FileOutputStream fosDecoder = new FileOutputStream(outDecodeFile);//your out file path

String mediaMime = mediaFormat.getString(MediaFormat.KEY_MIME);
MediaCodec codec = MediaCodec.createDecoderByType(mediaMime);
codec.configure(mediaFormat, null, null, 0);
codec.start();

ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();

final long kTimeOutUs = 5000;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
int totalRawSize = 0;
try{
	while (!sawOutputEOS
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值