现在的位置: 首页 > 综合 > 正文

(十五)用JAVA编写MP3解码器——音频输出

2018年01月30日 ⁄ 综合 ⁄ 共 2021字 ⁄ 字号 评论关闭

解码一帧Layer3第10步:音频输出  -- class Audio

 

      这里给出音频输出的示例代码,后文给出的播放器是基于命令行,所以音频输出模块就写得很简单,如果你想了解音频输出细节,请查阅《Java API文档》中javax.sound.sampled库相关方法的文档。源码中第37行调用objSDL.open方法时设置了音频缓冲区大小为176400字节。音频缓冲应该设置多大比较好呢?这和你的音频硬件有关,缓冲区设置为合适的值有利于提高性能(官方文档上是这么说的)。前面讲到采用标准立体声编码的MP3一帧有2304个PCM样本,16位PCM输出时长度为4608字节。若PCM样本的采样率为44100Hz,那么解码端播放时一个声道每秒送入音频硬件的PCM样本数为44100个,立体声的话就是44100*2=88200个,这88200个PCM样本的长度为88200*2=176400字节。MP3一帧的播放时长为4608/176400秒(约等于26毫秒),解码器显然能在26ms内完成解码一帧并将PCM写入到音频输出模块。无论采用什么样的MP3编码方式,每帧的播放时长是相同的。关于音频缓冲区就说到这儿,缓冲区设为多大,你自己看着办哈~

 

class Audio 源码如下:

/*
* Audio.java -- 音频输出示例
* Copyright (C) 2010
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to negotiate alternate licensing terms, you may do
* so by contacting the author: <http://jmp123.sourceforge.net/>
*/
package output;

import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;

public final class Audio {
	private static SourceDataLine objSDL;

	// Start Output
	public static void open(int intFreq, int iBits, int channels) throws Exception {
		AudioFormat af = new AudioFormat(intFreq, 16, channels, true, false);
		DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
		objSDL = (SourceDataLine) AudioSystem.getLine(info);
		//objSDL.open(af);
		objSDL.open(af, 176400);
		objSDL.start();
	}

	public static void write(byte[] b, int len) {
		objSDL.write(b, 0, len);
	}

	/*
	* bPause=true pause; bPause=false resume
	*/
	public static void pause(boolean bPause) {
		if(bPause)
			objSDL.stop();
		else
			objSDL.start();
	}

	// Close Output
	public static void close() {
		objSDL.drain();
		objSDL.stop();
		objSDL.close();
		objSDL = null;
	}
}

抱歉!评论已关闭.