博客原文: 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