Java 播放MP3 的六种方法
Java Sound Api(JDK)原生支 .wav .au .aiff 这些格式的音频文件,当然 PCM文件也是可以直接播放的,如果是 mp3,ogg,ape,flac 则需要第三方 jar 。
package com.xu.music;
import javax.sound.sampled.AudioSystem;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
// 查看系统支持音频文件
Stream.of(AudioSystem.getAudioFileTypes()).forEach(System.out::println);
}
}
WAVE
AU
AIFF
Process finished with exit code 0
音频格式 | 添加依赖 |
---|---|
*.wav *.au *.aiff | java sound api(JDK原生支持) |
*.mp3 *.mp4 *.ogg *.flac *.wav *.aif *.dsf *.wma (获取音频标签) | jaudiotagger.jar |
*.mp3 | mp3spi.jar |
*.mp3 | jl1.0.jar |
*.mp3 | jmp123.jar |
*.flac | jflac.jar |
1 使用官方的解决方案
使用官方开发的 JMF (Java Media Framework),现在JMF已经不再更新了。如果使用方法1,你必须安装好 JMF 软件并导入JMF安装目录下对应的jar包。
音频格式 | 添加依赖 |
---|---|
*.mp3 | jmf 安装目录的 jar 包 |
package com.xu.musicplayer.player;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;
/**
* Java 播放音频
* @ClassName: MusicPlayer
* @Description: TODO
* @author: hyacinth
* @date: 2019年8月9日 上午12:10:53
* @Copyright: hyacinth
*/
public class MusicPlayer {
public static void main(String[] args) throws NoPlayerException, MalformedURLException, IOException {
File file = new File("F:\\KuGou\\张婉清、童英然、薛之谦、黄云龙 - 丑八怪.mp3");
Player player = Manager.createPlayer(file.toURL());
player.start();//开始播放
}
}
2 使用第三方解决方案 (jl1.0.jar)
使用第三方jar包 jl1.0.jar。
音频格式 | 添加依赖 |
---|---|
*.mp3 | jl1.0.jar |
package com.xu.musicplayer.player;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
/**
* Java 播放音频
* @ClassName: MusicPlayer
* @Description: TODO
* @author: hyacinth
* @date: 2020年3月5日 上午12:10:53
* @Copyright: hyacinth
*/
public class MusicPlayer {
static Player player = null;
public static void main(String[] args) throws FileNotFoundException, JavaLayerException {
File file = new File("C:\\Users\\hyacinth\\Desktop\\Work\\花涵 - 假行僧.mp3");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream stream = new BufferedInputStream(fis);
Player player = new Player(stream);
player.play();
}
/**
* 播放 20 秒并结束播放
*/
public void play() {
new Thread(new Runnable() {
@Override
public void run() {
try {
File file = new File("C:\\Users\\hyacinth\\Desktop\\Work\\花涵 - 假行僧.mp3");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream stream = new BufferedInputStream(fis);
player = new Player(stream);
player.play();
} catch (Exception e) {
// TODO: handle exception
}
}
}).start();
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
player.close();
}
}
3 使用第三方解决方案 (jmp123.jar)
3 使用第三方jar包 jmp123.jar。CSDN jmp
音频格式 | 添加依赖 |
---|---|
*.mp3 | jmp123.jar |
package com.xu.musicplayer.player;
import java.io.File;
import java.io.IOException;
import jmp123.output.Audio;
/**
* Java 播放音频
* @ClassName: MusicPlayer
* @Description: TODO
* @author: hyacinth
* @date: 2019年8月9日 上午12:10:53
* @Copyright: hyacinth
*/
public class MusicPlayer {
public static void main(String[] args) {
String path="G:\\KuGou\\梦涵 - 爱的故事上集.mp3";
MiniPlayer player = new MiniPlayer(new Audio());
try {
long t0 = System.nanoTime();
String msg = player.open(path);
long t1 = System.nanoTime() - t0;
File file = new File(path);
long length = file.length();
int frames = player.getFrameCount();
System.out.println(msg);
System.out.printf(" length: %d bytes, %d frames\n", length, frames);
System.out.printf("elapsed time: %,dns (%.9fs, %.2f fps)\n", t1, t1/1e9, frames/(t1/1e9));
player.run();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4 使用第三方解决方案 (mp3spi.jar)
5 使用 Google 的 mp3spi 播放MP3。添加 mp3spi 的 maven 依赖。
音频格式 | 添加依赖 |
---|---|
*.mp3 | mp3spi.jar |
4.1 依赖引用
<dependency>
<groupId>com.googlecode.soundlibs</groupId>
<artifactId>mp3spi</artifactId>
<version>1.9.5.4</version>
</dependency>
4.2 测试代码
/**
*
* @Author: hyacinth
* @Title: MusicPlayer.java
* @Package com.xu.test
* @Description: TODO:
* @Date: 2019年8月25日 下午10:40:47
* @Version V-1.0
* @Copyright: 2019 hyacinth
*
*/
package com.xu.test;
import java.io.File;
import java.io.FileInputStream;
import javazoom.jl.player.Player;
/**
* @Author: hyacinth
* @ClassName: MusicPlayer
* @Description: TODO
* @Date: 2019年8月25日 下午10:40:47
* @Copyright: hyacinth
*/
public class MusicPlayer {
public static void main(String[] args) throws Exception {
File file=new File("I:\\KuGou\\许丽静 - 昨天今天下雨天.mp3");
FileInputStream stream=new FileInputStream(file);
Player player=new Player(stream);
player.play();
}
}
5 使用第三方解决方案 (jaudiotagger.jar)
jaudiotagger.jar 本身不能播放 音频文件,但是能解码 音频文件 中的标签信息。
音频格式 | 添加依赖 |
---|---|
*.mp3 *.mp4 *.ogg *.flac *.wav *.aif *.dsf *.wma (获取音频标签) | jaudiotagger.jar |
5.1 添加依赖
<dependency>
<groupId>org</groupId>
<artifactId>jaudiotagger</artifactId>
<version>2.0.3</version>
</dependency>
5.2 测试代码
package com.xu.music.player;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.TagException;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
public class MusicPlayer {
public static void main(String[] args) throws Exception {
get_music_play_length("I:\\KuGou\\许丽静 - 昨天今天下雨天.mp3");
}
/**
* Java Music 获取歌曲播放时长
* @Title: get_music_play_length
* @Description: 获取歌曲播放时长
* @param path mp3路径
* @throws InvalidAudioFrameException
* @throws ReadOnlyFileException
* @throws TagException
* @throws IOException
* @throws CannotReadException
* @date 2019年10月25日 下午12:28:41
*/
public int get_music_play_length(String path) throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException {
File file=new File("C:\\Users\\Administrator\\Desktop\\梦涵 - 加减乘除.mp3");
AudioFile mp3=AudioFileIO.read(file);
return mp3.getAudioHeader().getTrackLength();
}
}
6 使用自定义解决方案(推荐)
6.1 SourceDataLine和Clip
方式 | 优点 | 缺点 |
---|---|---|
SourceDataLine | 1、适合需要实时处理音频数据的应用,如音频流媒体、音频处理和效果应用等。 2、可以逐块地写入音频数据,因此可以动态生成或修改音频流。 3、提供更高的控制力,可以控制播放速度、音量、音调等参数。 4、可以处理各种格式的音频数据,只要通过适当的编码解码器进行转换。 5、适合处理大文件,因为音频数据是逐块处理的,不需要一次性加载到内存中。 | 1、代码实现相对复杂,需要处理缓冲区管理、同步和错误处理等。 2、需要更详细的了解音频数据格式和音频系统。 3、由于需要初始化音频流,可能会有一定的启动延迟。 |
Clip | 1、适合播放简单的音频片段,如短音乐、音效等。 2、API 简单,使用方便,只需加载音频文件后调用 start() 方法即可播放。 3、启动延迟小,适合快速播放音频的场景,如游戏音效、用户界面提示音等。 4、将音频文件一次性加载到内存中,减少了对磁盘 I/O 的依赖,播放时性能较高。 | 1、对于较大的音频文件,需要一次性加载到内存中,内存消耗较大,不适合播放大文件或长时间音频。 2、不适合需要动态生成或实时处理音频数据的场景。 3、控制能力有限,难以实现复杂的音频处理和效果。 |
如果你的应用需要实时处理音频数据、播放长时间音频或大文件、或者需要高度自定义的音频控制,SourceDataLine 是更好的选择。 | ||
如果你的应用主要是播放短音频片段,要求启动延迟小,且对音频处理和控制要求不高,Clip 是更为简便和高效的选择。 |
自定义通过获取MP3的PCM播放MP3,需要导入Google的一个jar包,可以获取音频的播放时长。
音频格式 | 添加依赖 |
---|---|
*.wav | 无 (JDK 原生支持) |
*.pcm | 无 (JDK 原生支持) |
*.au | 无 (JDK 原生支持) |
*.aiff | 无 (JDK 原生支持) |
*.mp3 | mp3spi.jar |
*.flac | jflac-codec.jar |
6.2 依赖引用
<!-- 如果需要解码播放mp3文件则引入这个jar包 -->
<dependency>
<groupId>com.googlecode.soundlibs</groupId>
<artifactId>mp3spi</artifactId>
<version>1.9.5.4</version>
</dependency>
<!-- 如果需要解码播放flac文件则引入这个jar包 -->
<dependency>
<groupId>org.jflac</groupId>
<artifactId>jflac-codec</artifactId>
<version>1.5.2</version>
</dependency>
7.3 播放时长
// float 类型 秒
AudioSystem.getAudioInputStream(new File("")).getFrameLength()/AudioSystem.getAudioInputStream(new File("")).getFormat().getSampleRate()
/**
* Java Music 获取音频文件信息
* @Title: get_info
* @Description: 获取音频文件信息
* @param path 音频文件路径
* @return 音频文件信息
* @date 2019年10月25日 下午12:28:41
*/
public String get_info(String path) {
File file=new File(path);
AudioInputStream ais;
String result="";
try {
ais = AudioSystem.getAudioInputStream(file);
AudioFormat af = ais.getFormat();
result = af.toString();
System.out.println(result);
System.out.println("音频总帧数:"+ais.getFrameLength());
System.out.println("每秒播放帧数:"+af.getSampleRate());
float len = ais.getFrameLength()/af.getSampleRate();
System.out.println("音频时长(秒):"+len);
System.out.println("音频时长:"+(int)len/60+"分"+(int)len%60+"秒");
} catch(UnsupportedAudioFileException e) {
throw new RuntimeException(e.getMessage());
} catch(IOException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
6.4 全部代码
package com.xu.player;
import org.apache.commons.lang3.StringUtils;
/**
* @author Administrator
*/
public enum Audio {
/**
* Specifies a WAVE file.
*/
WAVE(1, "WAVE", "wav"),
/**
* Specifies an AU file.
*/
AU(2, "AU", "au"),
/**
* Specifies an AIFF file.
*/
AIFF(3, "AIFF", "aif"),
/**
* Specifies an AIFF-C file.
*/
AIFF_C(4, "AIFF-C", "aifc"),
/**
* Specifies an SND file.
*/
SND(5, "SND", "snd"),
/**
* Specifies an MP3 file.
*/
MP3(6, "MP3", "mp3"),
/**
* Specifies an FLAC file.
*/
FLAC(7, "FLAC", "flac");
private int index;
private String type;
private String suffix;
Audio(int index, String type, String suffix) {
this.index = index;
this.type = type;
this.suffix = suffix;
}
public int index() {
return index;
}
public static int getIndex(String name) {
if (StringUtils.isBlank(name)) {
throw new RuntimeException("文件名称为空!");
}
name = StringUtils.substring(name, StringUtils.lastIndexOf(name, ".") + 1);
for (Audio audio : values()) {
if (StringUtils.equalsIgnoreCase(audio.suffix, name)) {
return audio.index;
}
}
return -1;
}
public static boolean isSupport(String name) {
if (StringUtils.isBlank(name)) {
throw new RuntimeException("文件名称为空!");
}
name = StringUtils.substring(name, StringUtils.lastIndexOf(name, ".") + 1);
for (Audio audio : values()) {
if (StringUtils.equalsIgnoreCase(audio.suffix, name)) {
return true;
}
}
return false;
}
}
package com.xu.player;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.ImageIcon;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.id3.AbstractID3v2Frame;
import org.jaudiotagger.tag.id3.AbstractID3v2Tag;
import org.jaudiotagger.tag.id3.framebody.FrameBodyAPIC;
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;
/**
* Java 播放音频
*
* @ClassName: MusicPlayer
* @Description: TODO
* @author: hyacinth
* @date: 2019年10月25日 下午12:28:41
* @Copyright: hyacinth
*/
public class MusicPlayer {
private static DataLine.Info info = null;
private static AudioFormat format = null;
private static SourceDataLine line = null;
private static AudioInputStream audio = null;
public static void main(String[] args) throws Exception {
MusicPlayer player = new MusicPlayer();
//player.audio_to_pcm("E:\\KuGou\\左宏元 - 功德圆满 (情与法笛子版).mp3", "E:\\KuGou\\左宏元 - 功德圆满 (情与法笛子版).pcm");
//player.get_info("C:\\Users\\Administrator\\Desktop\\梦涵 - 加减乘除.wav");
//player.play("C:\\Users\\Administrator\\Desktop\\梦涵 - 加减乘除.pcm");
//player.play("C:\\Users\\Administrator\\Desktop\\梦涵 - 加减乘除.wav");
player.play("E:\\KuGou\\左宏元 - 功德圆满 (情与法笛子版).mp3");
//player.play("C:\\Users\\Administrator\\Desktop\\梦涵 - 加减乘除.flac");
}
/**
* Java Music 播放
*
* @param path 文件路径
* @throws Exception
* @Title: play_pcm
* @Description: 播放 pcm
* @date 2019年10月25日 下午12:28:41
*/
public void play(String path) throws Exception {
load(path);
try {
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = audio.read(buffer)) > 0) {
line.write(buffer, 0, len);
}
line.drain();
line.stop();
line.close();
audio.close();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 加载音频
*
* @param url
* @throws Exception
* @date 2022年1月7日14点15分
*/
public void load(URL url) throws Exception {
load(AudioSystem.getAudioInputStream(url));
}
/**
* 加载音频
*
* @param file
* @throws Exception
* @date 2022年1月7日14点15分
*/
public void load(File file) throws Exception {
String name = file.getName();
if (Audio.isSupport(name)) {
if (Audio.getIndex(name) == Audio.MP3.index()) {
MpegAudioFileReader reader = new MpegAudioFileReader();
load(reader.getAudioInputStream(file));
} else {
load(AudioSystem.getAudioInputStream(file));
}
}
}
/**
* 加载音频
*
* @param path
* @throws Exception
* @date 2022年1月7日14点15分
*/
public void load(String path) throws Exception {
load(new File(path));
}
/**
* 加载音频
*
* @param stream
* @throws Exception
* @date 2022年1月7日14点15分
*/
public void load(InputStream stream) throws Exception {
load_audio(AudioSystem.getAudioInputStream(stream));
}
/**
* 加载音频
*
* @param encoding
* @param stream
* @date 2022年1月7日14点15分
*/
public void load(AudioFormat.Encoding encoding, AudioInputStream stream) {
load_audio(AudioSystem.getAudioInputStream(encoding, stream));
}
/**
* 加载音频
*
* @param format
* @param stream
* @date 2022年1月7日14点15分
*/
public void load(AudioFormat format, AudioInputStream stream) {
load_audio(AudioSystem.getAudioInputStream(format, stream));
}
/**
* 加载音频
*
* @param stream 音频流
* @date 2022年1月7日14点15分
*/
public void load_audio(AudioInputStream stream) {
try {
format = stream.getFormat();
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),
format.getChannels() * 2, format.getSampleRate(), false);
audio = AudioSystem.getAudioInputStream(format, stream);
info = new DataLine.Info(SourceDataLine.class, format, AudioSystem.NOT_SPECIFIED);
line = (SourceDataLine) AudioSystem.getLine(info);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 导出文件为PCM
*
* @param src 音频文件路径
* @param dst PCM文件导出路径
* @throws Exception
* @date 2022年1月7日14点15分
*/
private void audio_to_pcm(String src, String dst) throws Exception {
load(src);
AudioSystem.write(audio, AudioFileFormat.Type.WAVE, new File(dst));
line.close();
audio.close();
}
/**
* Java Music 获取wav或者pcm文件的编码信息
*
* @param path wav或者pcm文件路径
* @return wav或者pcm文件的编码信息
* @Title: get_info
* @Description: 获取wav或者pcm文件的编码信息
* @date 2019年10月25日 下午12:28:41
*/
public String get_info(String path) {
File file = new File(path);
AudioInputStream ais;
String result = "";
try {
ais = AudioSystem.getAudioInputStream(file);
AudioFormat af = ais.getFormat();
result = af.toString();
System.out.println(result);
System.out.println("音频总帧数:" + ais.getFrameLength());
System.out.println("每秒播放帧数:" + af.getSampleRate());
float len = ais.getFrameLength() / af.getSampleRate();
System.out.println("音频时长(秒):" + len);
System.out.println("音频时长:" + (int) len / 60 + "分" + len % 60 + "秒");
} catch (UnsupportedAudioFileException e) {
throw new RuntimeException(e.getMessage());
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
/**
* Java Music 获取mp3文件的图片
*
* @param mpath mp3flac文件路径
* @Title: get_image_from_mp3
* @Description: 获取mp3文件的图片
* @date 2019年10月25日 下午12:28:41
*/
public void get_image_from_mp3(String mpath) throws Exception {
File sourceFile = new File(mpath);
MP3File mp3file = new MP3File(sourceFile);
AbstractID3v2Tag tag = mp3file.getID3v2Tag();
AbstractID3v2Frame frame = (AbstractID3v2Frame) tag.getFrame("APIC");
FrameBodyAPIC body = (FrameBodyAPIC) frame.getBody();
byte[] image = body.getImageData();
Image img = Toolkit.getDefaultToolkit().createImage(image, 0, image.length);
ImageIcon icon = new ImageIcon(img);
FileOutputStream fos = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\梦涵 - 加减乘除.jpg");
fos.write(image);
fos.close();
System.out.println("width:" + icon.getIconWidth());
System.out.println("height:" + icon.getIconHeight());
}
}
7 使用JavaFX解决方案
7.1 添加依赖
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17.0.10</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>17.0.10</version>
</dependency>
7.2 下载JavaFX SDK
7.3 测试代码
--module-path D:\Environment\JavaFX\lib --add-modules=javafx.controls,javafx.media
java --module-path D:\Environment\JavaFX\lib --add-modules=javafx.controls,javafx.media -cp target/test.jar com.xu.test.Test
package com.xu.test;
import java.nio.file.Paths;
import javafx.application.Application;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;
public class Test extends Application {
@Override
public void start(Stage primaryStage) {
Media media = new Media(Paths.get("D:\\Kugou\\梦涵 - 加减乘除.mp3").toUri().toString());
MediaPlayer player = new MediaPlayer(media);
player.play();
}
public static void main(String[] args) {
launch(args);
}
}
8 制作一个 Java 音乐播放器
博主用 Java SWT 编写的 Java MusicPlayer
支持FFT频谱显示,默认不开启FFT频谱,喜欢的帮助点颗心。
Java MusicPlayer GitHub 地址 (旧版本)
Java MusicPlayer GitHub 地址 (新版本)