----------------siwuxie095
使用 Java Swing 框架制作一个简单的视频播放器:
首先到 VideoLAN 的官网下载 VLC media player,制作的视频播放器内核
需要调用
VLC media player
接着下载相关的在线开源库:vlcj
下载链接:
vlcj-3.8.0-dist.tar.gz 解压后一览:
必备的 4 个 jar 包:
(1)jna-3.5.2.jar
(2)platform-3.5.2.jar
(3)vlcj-3.8.0.jar
(4)slf4j-api-1.7.10.jar
虽然这 4 个
jar 包已经够了,但根据控制台的提示:
Failed to load class "org.slf4j.impl.StaticLoggerBinder"
可以导入页面中所提到的 5 个包中的任何一个且只能一个来解决问题
(1)slf4j-nop.jar
(2)slf4j-simple.jar
(3)slf4j-log4j12.jar
(4)slf4j-jdk14.jar
(5)logback-classic.jar
SLF4J 下载链接:
我选择导入
slf4j-nop-1.7.25.jar,即 5 个可选包中的第一个
工程名:MyVideoPlayer
包名:com.siwuxie095.main、com.siwuxie095.view
类名:VideoPlayer.java(主类)、MainWindow.java
打开资源管理器,在工程 MyVideoPlayer 文件夹下,创建一个
文件夹:lib,在其中放入:
(1)jna-3.5.2.jar
(2)platform-3.5.2.jar
(3)vlcj-3.8.0.jar
(4)slf4j-api-1.7.10.jar
(5)
slf4j-nop-1.7.25.jar
工程结构目录如下:
全选这 5 个
jar 文件,右键->Build Path->Add to Build Path
此时,工程结构目录一览:
VideoPlayer.java(主类):
packagecom.siwuxie095.main;
importjava.awt.EventQueue;
importjava.io.File;
importjavax.swing.JFileChooser;
importjavax.swing.SwingWorker;
importcom.siwuxie095.view.MainWindow;
importcom.sun.jna.Native;
importcom.sun.jna.NativeLibrary;
importuk.co.caprica.vlcj.binding.LibVlc;
importuk.co.caprica.vlcj.discovery.NativeDiscovery;
importuk.co.caprica.vlcj.runtime.RuntimeUtil;
public classVideoPlayer {
/**
* VLC播放器系统库的路径:D:\VLC media player\VLC
*注意需要将路径中的反斜杠改为斜杠,或使用双反斜杠(即通过转义符进行转义)
*系统库一般是在含有libvlc.dll、libvlccore.dll的路径
*/
private static finalString NATIVE_LIBRARY_SEARCH_PATH = "D:/VLC media player/VLC";
//将声明转移到类中,并设为static
staticMainWindow frame;
public staticvoidmain(String[] args) {
//(1)法一:首先要找到本机库(VLC播放器的系统库),这是自动搜索本机库的位置
booleanfound = newNativeDiscovery().discover();
System.out.println(found);
System.out.println(LibVlc.INSTANCE.libvlc_get_version());
//判断当前的系统是否是Windows
//还可以判断Mac和Linux,以传入不同的路径
if(RuntimeUtil.isWindows()) {
//(2)法二:手动设置本机库(VLC播放器的系统库)的路径
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(),
NATIVE_LIBRARY_SEARCH_PATH);
System.out.println(LibVlc.INSTANCE.libvlc_get_version());
}
//加载VLC播放器的系统库
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
//在主方法中创建窗体
EventQueue.invokeLater(newRunnable() {
publicvoidrun() {
try{
frame = newMainWindow();
frame.setVisible(true);
//字幕的编码
String options="--subsdec-encoding=GB18030";
/**
* prepareMedia()先准备而不是马上播放
*可传入视频文件的路径(和播放参数,如:字幕编码)
*这里使用双反斜杠(通过转义符进行转义)
*关于播放参数,可以参考VLC command-line
*链接:https://wiki.videolan.org/VLC_command-line_help/
*进入后搜索subsdec设定字幕编码
*还可以传入更多播放参数
*/
frame.getMediaPlayer().prepareMedia("C:\\Users\\siwux\\Desktop\\"
+ "testvideo\\test.mp4",options);
frame.getMediaPlayer().toggleFullScreen();
//创建一个SwingWorker线程,用于实时调节进度
//注意:创建完毕,最后要execute()将它运行起来
newSwingWorker() {
@Override
protectedString doInBackground() throwsException {
while(true) {
//视频总时长,以毫秒计
longtotal=frame.getMediaPlayer().getLength();
//当前所看时长,以毫秒计
longcurr=frame.getMediaPlayer().getTime();
//百分比,并强转为float
floatpercent=(float)curr/total;
//因为进度条不是按百分比进行计算,而是0-100的数值范围
//所以要乘100,并强转为int,publish()到process()
//(进度条范围可设置,如果改为0-120,就要乘120)
publish((int)(percent*100));
//每隔0.1秒(100毫秒)更新一次进度条,如果不加则刷新过快
Thread.sleep(100);
}
}
protectedvoidprocess(java.util.List chunks) {
//创建int型变量value接收chunks中的值
for(intvalue : chunks) {
frame.getProgressBar().setValue(value);
}
};
}.execute();
} catch(Exception e) {
e.printStackTrace();
}
}
});
}
//播放
public staticvoidplay() {
frame.getMediaPlayer().play();
}
//暂停
public staticvoidpause() {
frame.getMediaPlayer().pause();
}
//停止
public staticvoidstop() {
frame.getMediaPlayer().stop();
}
public staticvoidjumpTo(floatto) {
//为跳转设定时间:百分比乘以视频时间的总长
frame.getMediaPlayer().setTime((long)(to*frame.getMediaPlayer().getLength()));
}
public staticvoidopenVideo() {
//创建文件选择器:JFileChooser
JFileChooser chooser=newJFileChooser();
//将父级窗体设置成null
intv=chooser.showOpenDialog(null);
if(v==JFileChooser.APPROVE_OPTION) {
File file=chooser.getSelectedFile();
//获取到文件的绝对路径,开始播放
frame.getMediaPlayer().playMedia(file.getAbsolutePath());
}
}
public staticvoidopenSubtitle() {
JFileChooser chooser=newJFileChooser();
intv=chooser.showOpenDialog(null);
if(v==JFileChooser.APPROVE_OPTION) {
File file=chooser.getSelectedFile();
//设定字幕,直接传入file对象
frame.getMediaPlayer().setSubTitleFile(file);
}
}
public staticvoidexit() {
//在退出之前,先释放播放器的资源
frame.getMediaPlayer().release();
System.exit(0);
}
public staticvoidsetVol(intvol) {
//设定音量
frame.getMediaPlayer().setVolume(vol);
}
}
MainWindow.java:
packagecom.siwuxie095.view;
importjava.awt.BorderLayout;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjava.awt.event.MouseAdapter;
importjava.awt.event.MouseEvent;
importjavax.swing.JButton;
importjavax.swing.JFrame;
importjavax.swing.JMenu;
importjavax.swing.JMenuBar;
importjavax.swing.JMenuItem;
importjavax.swing.JPanel;
importjavax.swing.JProgressBar;
importjavax.swing.JSlider;
importjavax.swing.UIManager;
importjavax.swing.UnsupportedLookAndFeelException;
importjavax.swing.border.EmptyBorder;
importjavax.swing.event.ChangeEvent;
importjavax.swing.event.ChangeListener;
importcom.siwuxie095.main.VideoPlayer;
importcom.sun.java.swing.plaf.windows.WindowsLookAndFeel;
importuk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
importuk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
public classMainWindow extendsJFrame {
privateJPanel contentPane;
//创建播放器的界面需要使用EmbeddedMediaPlayerComponent
EmbeddedMediaPlayerComponent playerComponent;
privateJPanel bottomPane;
privateJButton btnPlay;
privateJButton btnPause;
privateJButton btnStop;
privateJPanel controlPane;
privateJProgressBar progress;
privateJMenuBar menuBar;
privateJMenu mnFile;
privateJMenuItem mntmOpenvideo;
privateJMenuItem mntmOpensubtitle;
privateJMenuItem mntmExit;
privateJSlider slider;
/**
* Create the frame.
*/
publicMainWindow() {
try{
UIManager.setLookAndFeel(newWindowsLookAndFeel());
} catch(UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
menuBar = newJMenuBar();
setJMenuBar(menuBar);
mnFile = newJMenu("File");
menuBar.add(mnFile);
mntmOpenvideo = newJMenuItem("OpenVideo");
mntmOpenvideo.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
VideoPlayer.openVideo();
}
});
mnFile.add(mntmOpenvideo);
mntmOpensubtitle = newJMenuItem("OpenSubtitle");
mntmOpensubtitle.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
VideoPlayer.openSubtitle();
}
});
mnFile.add(mntmOpensubtitle);
mntmExit = newJMenuItem("Exit");
mntmExit.addActionListener(newActionListener() {
publicvoidactionPerformed(ActionEvent e) {
VideoPlayer.exit();
}
});
mnFile.add(mntmExit);
contentPane = newJPanel();
contentPane.setBorder(newEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(newBorderLayout(0, 0));
setContentPane(contentPane);
JPanel videoPane = newJPanel();
contentPane.add(videoPane, BorderLayout.CENTER);
videoPane.setLayout(newBorderLayout(0, 0));
//在videoPane创建之后实例化playerComponent
playerComponent=newEmbeddedMediaPlayerComponent();
//将playerComponent添加到videoPane中,并指定布局
videoPane.add(playerComponent, BorderLayout.CENTER);
bottomPane = newJPanel();
videoPane.add(bottomPane, BorderLayout.SOUTH);
bottomPane.setLayout(newBorderLayout(0, 0));
controlPane = newJPanel();
bottomPane.add(controlPane);
btnStop = newJButton("Stop");
controlPane.add(btnStop);
btnStop.setFocusable(false);
btnPlay = newJButton("Play");
controlPane.add(btnPlay);
btnPlay.setFocusable(false);
btnPause = newJButton("Pause");
controlPane.add(btnPause);
btnPause.setFocusable(false);
slider = newJSlider();
slider.setFocusable(false);
//关于默认音量的设定要在stateChanged事件之前
//如果要设定最大音量和最小音量也是如此
slider.setValue(20);
//为音量调节slider添加stateChanged事件
slider.addChangeListener(newChangeListener() {
publicvoidstateChanged(ChangeEvent e) {
VideoPlayer.setVol(slider.getValue());
}
});
controlPane.add(slider);
progress = newJProgressBar();
progress.setFocusable(false);
//为进度条progress添加mouseClicked事件
progress.addMouseListener(newMouseAdapter() {
@Override
publicvoidmouseClicked(MouseEvent e) {
//获取鼠标点击在进度条上的位置
intx=e.getX();
//计算点击位置占进度条总长的百分比
floatper=(float)x/progress.getWidth();
VideoPlayer.jumpTo(per);
}
});
//让进度条progress显示数字百分比
progress.setStringPainted(true);
bottomPane.add(progress, BorderLayout.NORTH);
//为Stop按钮添加mouseClicked事件
btnStop.addMouseListener(newMouseAdapter() {
@Override
publicvoidmouseClicked(MouseEvent e) {
VideoPlayer.stop();
}
});
//为Play按钮添加mouseClicked事件
btnPlay.addMouseListener(newMouseAdapter() {
@Override
publicvoidmouseClicked(MouseEvent e) {
VideoPlayer.play();
}
});
//为Pause按钮添加mouseClicked事件
btnPause.addMouseListener(newMouseAdapter() {
@Override
publicvoidmouseClicked(MouseEvent e) {
VideoPlayer.pause();
}
});
}
//返回媒体播放器的实例
publicEmbeddedMediaPlayer getMediaPlayer() {
returnplayerComponent.getMediaPlayer();
}
//返回JProgressBar的实例
publicJProgressBar getProgressBar() {
returnprogress;
}
}
将窗体
JFrame 的 LookAndFeel 设定为 Windows
根面板
contentPane 使用默认布局 Border Layout
在 contentPane 的中间添加一个 JPanel,将其布局改为:
Border Layout,Rename 为 videoPane
在 videoPane 的下方添加一个 JPanel,将其布局改为:
Border Layout,Rename 为 bottomPane
在 bottomPane 的中间添加一个 JPanel,将其布局改为:
Flow Layout,Rename 为 controlPane
在 controlPane 中添加三个 JButton 和一个 JSlider
将三个
JButton 的 focusable 属性设为
false,并将其文本(text)分别改为:
Stop、Play 和 Pause,再分别 Rename 为:btnStop、btnPlay 和 btnPause
为三个 JButton 添加 mouseClicked 事件,实现对应 停止、播放 和 暂停 的功能
将
Slider 的 focusable 属性设为
false
为
JSlider 添加 stateChanged 事件,实现 调节音量 的功能
在
bottomPane 的上方添加一个 JProgressBar
将
JProgressBar 的 focusable 属性设为
false,stringPainted 属性设为 true,
并 Rename 为:progress
为 JProgressBar 添加 mouseClicked 事件,实现 调节进度 的功能
在
JFrame 的上方添加一个 JMenuBar,注意:JMenuBar 和 contentPane 同级
制作
菜单栏,为
菜单项
添加
actionPerformed 事件,实现
打开视频、打开字幕 和 退出 的功能
整体的
Components 视图:
运行程序:
最后导出为可执行的
Java 程序:
选择工程
MyVideoPlayer,右键->Export->Java->Runnable JAR file
然后选择当前主类:VideoPlayer - MyVideoPlayer,导出
路径指定为:E:\workspace\MyVideoPlayer\release,并
命名为:MyVideoPlayer.jar
【made by siwuxie095】