VLC + Swing制作简易视频播放器

利用VLC制作简易的视频播放器


写在前面

本次视频播放器的制作需要准备四样东西:1、VLC播放器;2、VLC扩展库,3、Apache log4j,4、WindowBuilder插件。前两个是必须的,WindowBuilder插件是为方便开发而使用的,如果有大佬喜欢手写图形界面也是没有问题的。关于插件的安装这里不说了,比较简单,下面直接进入主题。


安装VLC播放器

  链接上面已经给出,根据自己的电脑直接下载相应的版本即可,例如我的电脑是windows 64位的,则选择windows 64bit

vlc播放器下载

下载完成直接安装即可,注意记住安装路径,后面会用到。


安装VLC扩展库

  点击打开上面的VLC扩展库链接地址,或者直接点击这里传送门,找到vlcj-3.10.1 distribution (zip)点击下载,下载完成后解压缩。

vlc库

vlc库


下载日志库log4j

  由于在下面写代码的过程中会出现一个错误,这个错误需要通过导入log4j-1.2.17.jar包解决,所以在此先将其下载好,当然这里使用的是1.2X版本,你可以下载最新的2.X版本,这应该是没有影响的。下载链接

log4j


创建工程以及加载VLC库

创建工程很简单,关键是加载VLC库,要在代码中加载VLC库,需要先在工程目录中导入所需要的jar包,包括


jna-4.1.0.jar
vlcj-3.10.1.jar
log4j-1.2.17.jar
slf4j-log4j12-1.7.25.jar
slf4j-api-1.7.10.jar

之前由于没有导入log4j-1.2.17.jar或者slf4j-log4j12-1.7.25.jar,因此在加载VLC库文件的时候会出现各种谜一样的错误,类似于:

1
2
3
4
错误:
log4j:WARN No appenders could be found for logger (com.mackvord.videoplayer.main.Main).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

网上的解决办法也是五花八门,自己也摸索着找到了解决的方法:

先在在项目中导入log4j-1.2.17.jar和slf4j-log4j12-1.7.25.jar两个包,添加完后需要在src目录下添加一个log.properties文件指定日志信息的存放地址,log.properties里的内容可以自定义,下面是我的log.properties文件中的内容:

1
2
3
4
5
6
7
8
9
10
11
12
# Root logger option
log4j.rootLogger=INFO, logg

# Redirect log messages to a log file, support file rolling.
log4j.appender.logg=org.apache.log4j.RollingFileAppender
log4j.appender.logg.File=F://MyPlayer//logs//log.log
log4j.appender.logg.Append = true
log4j.appender.logg.Threshold = DEBUG
log4j.appender.logg.MaxFileSize=5MB
log4j.appender.logg.MaxBackupIndex=3
log4j.appender.logg.layout=org.apache.log4j.PatternLayout
log4j.appender.logg.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

还有一个迷之错误就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java.lang.RuntimeException: Failed to initialise libvlc.

This is most often caused either by an invalid vlc option being passed when creating a MediaPlayerFactory or by libvlc being unable to locate the required plugins.

If libvlc is unable to locate the required plugins the instructions below may help:

In the text below <libvlc-path> represents the name of the directory containing "libvlc.dylib" and "libvlccore.dylib" and <plugins-path> represents the name of the directory containing the vlc plugins...

For libvlc to function correctly the vlc plugins must be available, there are a number of different ways to achieve this:

1. Make sure the plugins are installed in the "<libvlc-path>/vlc/plugins" directory, this should be the case with a normal vlc installation.

2. Set the VLC_PLUGIN_PATH operating system environment variable to point to "<plugins-path>".

More information may be available in the log, specify -Dvlcj.log=DEBUG on the command-line when starting your application.

这个问题网上有不少人遇到过,但给出解决办法的却没几个,下面是我的解决办法:

windows下解决的办法:在系统的环境变量中添加一条记录VLC_PLUGIN_PATH指定路径:VLC安装目录下的plugins目录,例如:F:\MyPlayer\VLC\plugins,添加完环境属性后重启电脑,再次执行程序便可正常运行。

加载VLC库文件的核心代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class PlayMain {
// 定义一个常量来保存本地库的搜索路径
// 不同的系统,库文件的名称不一样,在windows系统中,用于搜索路径的目录必须是包含libvic和libviccore共享对象的目录
// 共享对象是指: Linux上以.so结束的文件或者Windows上以.dll结束的文件
private static final String NATIVE_LIBRARY_SEARCH_PATH = "F:\\MyPlayer\\VLC";
static MainWindow frame ;

public static void main(String[] args) {
// 判断当前主机是否是windows
if (RuntimeUtil.isWindows()) {
// 显式设置库路径
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), NATIVE_LIBRARY_SEARCH_PATH) ;
} else if (RuntimeUtil.isMac()) { // 判断当前主机是否是MacOS
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName()
, "/Application/VLC.app/Contens/MacOS/lib") ;
}
// 加载VLC播放器的系统库
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class) ;
}
}

创建界面

整个界面都是在windowbuilder中进行创建,所以这一部分比较简单,界面的代码如下:

图形界面代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package com.mackvord.videoplayer.views;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import com.mackvord.videoplayer.main.PlayMain;

import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JProgressBar;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSlider;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.Toolkit;

public class MainWindow extends JFrame {

/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane ;
EmbeddedMediaPlayerComponent playerComponent ; // 定义一个播放器界面
private JPanel panel;
private JButton btnNewButton;
private JButton btnNewButton_1;
private JButton btnStop;
private JPanel controlPanel;
private JProgressBar progress;
private JMenuBar menuBar;
private JMenu mnFile;
private JMenuItem mntmOpen;
private JMenuItem mntmOpenSubtitle;
private JMenuItem mntmExit;
private JSlider slider;
/**
* Launch the application.
*/
public static void main(String[] args) {

}

/**
* Create the frame.
*/
public MainWindow() {
setIconImage(Toolkit.getDefaultToolkit().getImage(MainWindow.class.getResource("/imageIcon/wallls.com_120503.jpg")));
setTitle("MyPlayer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 614, 456);
menuBar = new JMenuBar();
setJMenuBar(menuBar);
mnFile = new JMenu("File");
menuBar.add(mnFile);
mntmOpen = new JMenuItem("Open Video...");
mnFile.add(mntmOpen);
mntmOpenSubtitle = new JMenuItem("Open Subtitle...");
mnFile.add(mntmOpenSubtitle);
mntmExit = new JMenuItem("Exit");
mnFile.add(mntmExit);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel videopanel = new JPanel();
contentPane.add(videopanel, BorderLayout.CENTER);
videopanel.setLayout(new BorderLayout(0, 0));
playerComponent = new EmbeddedMediaPlayerComponent() ;
videopanel.add(playerComponent) ;
panel = new JPanel();
videopanel.add(panel, BorderLayout.SOUTH);
panel.setLayout(new BorderLayout(0, 0));
controlPanel = new JPanel();
panel.add(controlPanel, BorderLayout.CENTER);
btnStop = new JButton("Stop");
controlPanel.add(btnStop);
btnNewButton = new JButton("Play");
controlPanel.add(btnNewButton);
btnNewButton_1 = new JButton("Pause");
controlPanel.add(btnNewButton_1);
slider = new JSlider();
slider.setValue(100);
slider.setMaximum(120);
controlPanel.add(slider);
progress = new JProgressBar();
progress.setStringPainted(true);
panel.add(progress, BorderLayout.NORTH);

}

public EmbeddedMediaPlayer getMediaPlayer() {
return playerComponent.getMediaPlayer() ;
}

public JProgressBar getProgressBar() {
return progress ;
}

}

添加监听器

事件监听代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
mntmOpen.addActionListener(new ActionListener() { 

@Override
public void actionPerformed(ActionEvent e) {
PlayMain.openVideo() ;
}
});

mntmOpenSubtitle.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
PlayMain.openSubtitle() ;
}
});

mntmExit.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
PlayMain.exit() ;
}
});

slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
PlayMain.setVol(slider.getValue()) ;
}
});

progress.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int x = e.getX() ;
PlayMain.jumpTo((float)x/progress.getWidth());
}
});

btnNewButton_1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
PlayMain.pause() ;
}
});

btnNewButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
PlayMain.play() ; // 调用PlayMain类中的play()方法
}
});

btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});

btnStop.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
PlayMain.stop() ;
}
});

事件处理方法

由于时间的关系,只实现了一些基本的功能,包括播放、暂停、停止、音量调节、文件的选择以及字幕文件的选择等。界面的创建以及事件监听在MainWindow类中实现,而事件的处理交由PlayMain类处理。并且PlayMain类负责界面的初始化。

播放事件

1
2
3
4
// 播放的方法
public static void play() {
frame.getMediaPlayer().play() ;
}

暂停事件

1
2
3
4
// 暂停的方法
public static void pause() {
frame.getMediaPlayer().pause() ;
}

停止事件

1
2
3
4
// 停止的方法
public static void stop() {
frame.getMediaPlayer().stop() ;
}

音量调节

1
2
3
4
// 设置音量
public static void setVol(int v) {
frame.getMediaPlayer().setVolume(v) ;
}

进度条调节播放进度

1
2
3
4
// 进度条跳转的方法
public static void jumpTo(float to) {
frame.getMediaPlayer().setTime((long)(to*frame.getMediaPlayer().getLength()));
}

选择视频文件

1
2
3
4
5
6
7
8
9
// 打开文件
public static void openVideo() {
JFileChooser chooser = new JFileChooser() ;
int v = chooser.showOpenDialog(null) ;
if (v == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile() ;
frame.getMediaPlayer().playMedia(file.getAbsolutePath()) ;
}
}

选择字幕文件

1
2
3
4
5
6
7
8
9
// 选择字幕文件
public static void openSubtitle() {
JFileChooser chooser = new JFileChooser() ;
int v = chooser.showOpenDialog(null) ;
if (v == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile() ;
frame.getMediaPlayer().setSubTitleFile(file) ;
}
}

退出时的处理

1
2
3
4
5
// 退出
public static void exit() {
frame.getMediaPlayer().release() ; // 释放播放器资源
System.exit(0) ;
}

完整的代码

PlayMain.java:

PlayMain.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.mackvord.videoplayer.main;

import java.awt.EventQueue;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.SwingWorker;

import com.mackvord.videoplayer.views.MainWindow;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;

import uk.co.caprica.vlcj.binding.LibVlc;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;

public class PlayMain {
// 定义一个常量来保存本地库的搜索路径
// 不同的系统,库文件的名称不一样,在windows系统中,用于搜索路径的目录必须是包含libvic和libviccore共享对象的目录
// 共享对象是指: Linux上以.so结束的文件或者Windows上以.dll结束的文件
private static final String NATIVE_LIBRARY_SEARCH_PATH = "F:\\MyPlayer\\VLC";
static MainWindow frame ;

public static void main(String[] args) {
// 判断当前主机是否是windows
if (RuntimeUtil.isWindows()) {
// 显式设置库路径
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), NATIVE_LIBRARY_SEARCH_PATH) ;
} else if (RuntimeUtil.isMac()) { // 判断当前主机是否是MacOS
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName()
, "/Application/VLC.app/Contens/MacOS/lib") ;
}
// 加载VLC播放器的系统库
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class) ;

EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new MainWindow();
frame.setVisible(true);
String options[] = {"--subsdec-encoding=UTF-8"} ; // 指定字幕的解码方式
//frame.getMediaPlayer().playMedia("E:\\CloudMusic\\MV\\我是江小白.mp4", options) ;
frame.getMediaPlayer().prepareMedia("E:\\CloudMusic\\MV\\我是江小白.mp4", options) ;
new SwingWorker<String, Integer>() {

@Override
protected String doInBackground() throws Exception {
while (true) {
long total = frame.getMediaPlayer().getLength() ;
long curr = frame.getMediaPlayer().getTime() ;
float percent = (float)curr / total ; // 此处不要使用括号扩住curr/total
publish((int)(percent*100)) ;
Thread.sleep(100) ; // 每一百毫秒刷新一次
}
}
protected void process(java.util.List<Integer> chunks) {
for (int v : chunks) {
frame.getProgressBar().setValue(v) ;
}
};
}.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
// 播放的方法
public static void play() {
frame.getMediaPlayer().play() ;
}
// 暂停的方法
public static void pause() {
frame.getMediaPlayer().pause() ;
}

// 停止的方法
public static void stop() {
frame.getMediaPlayer().stop() ;
}

// 进度条跳转的方法
public static void jumpTo(float to) {
frame.getMediaPlayer().setTime((long)(to*frame.getMediaPlayer().getLength()));
}

// 设置音量
public static void setVol(int v) {
frame.getMediaPlayer().setVolume(v) ;
}

// 打开文件
public static void openVideo() {
JFileChooser chooser = new JFileChooser() ;
int v = chooser.showOpenDialog(null) ;
if (v == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile() ;
frame.getMediaPlayer().playMedia(file.getAbsolutePath()) ;
}
}

// 选择字幕文件
public static void openSubtitle() {
JFileChooser chooser = new JFileChooser() ;
int v = chooser.showOpenDialog(null) ;
if (v == JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile() ;
frame.getMediaPlayer().setSubTitleFile(file) ;
}
}

// 退出
public static void exit() {
frame.getMediaPlayer().release() ; // 释放播放器资源
System.exit(0) ;
}
}

MainWindow.java:

MianWindow.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package com.mackvord.videoplayer.views;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import com.mackvord.videoplayer.main.PlayMain;

import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JProgressBar;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSlider;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
import java.awt.Toolkit;

public class MainWindow extends JFrame {

/**
*
*/
private static final long serialVersionUID = 1L;
private JPanel contentPane ;
EmbeddedMediaPlayerComponent playerComponent ; // 定义一个播放器界面
private JPanel panel;
private JButton btnNewButton;
private JButton btnNewButton_1;
private JButton btnStop;
private JPanel controlPanel;
private JProgressBar progress;
private JMenuBar menuBar;
private JMenu mnFile;
private JMenuItem mntmOpen;
private JMenuItem mntmOpenSubtitle;
private JMenuItem mntmExit;
private JSlider slider;
/**
* Launch the application.
*/
public static void main(String[] args) {

}

/**
* Create the frame.
*/
public MainWindow() {
setIconImage(Toolkit.getDefaultToolkit().getImage(MainWindow.class.getResource("/imageIcon/wallls.com_120503.jpg")));
setTitle("MyPlayer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 614, 456);

menuBar = new JMenuBar();
setJMenuBar(menuBar);

mnFile = new JMenu("File");
menuBar.add(mnFile);

mntmOpen = new JMenuItem("Open Video...");
mnFile.add(mntmOpen);

mntmOpenSubtitle = new JMenuItem("Open Subtitle...");
mnFile.add(mntmOpenSubtitle);

mntmExit = new JMenuItem("Exit");
mnFile.add(mntmExit);

mntmOpen.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
PlayMain.openVideo() ;
}
});

mntmOpenSubtitle.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
PlayMain.openSubtitle() ;
}
});

mntmExit.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent e) {
PlayMain.exit() ;
}
});

contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);

JPanel videopanel = new JPanel();
contentPane.add(videopanel, BorderLayout.CENTER);
videopanel.setLayout(new BorderLayout(0, 0));

playerComponent = new EmbeddedMediaPlayerComponent() ;
videopanel.add(playerComponent) ;

panel = new JPanel();
videopanel.add(panel, BorderLayout.SOUTH);
panel.setLayout(new BorderLayout(0, 0));

controlPanel = new JPanel();
panel.add(controlPanel, BorderLayout.CENTER);

btnStop = new JButton("Stop");
controlPanel.add(btnStop);

btnNewButton = new JButton("Play");
controlPanel.add(btnNewButton);

btnNewButton_1 = new JButton("Pause");
controlPanel.add(btnNewButton_1);

slider = new JSlider();
slider.setValue(100);
slider.setMaximum(120);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
PlayMain.setVol(slider.getValue()) ;
}
});
controlPanel.add(slider);

progress = new JProgressBar();
progress.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int x = e.getX() ;
PlayMain.jumpTo((float)x/progress.getWidth());
}
});
progress.setStringPainted(true);
panel.add(progress, BorderLayout.NORTH);
btnNewButton_1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
PlayMain.pause() ;
}
});
btnNewButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
PlayMain.play() ; // 调用PlayMain类中的play()方法
}
});
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
btnStop.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
PlayMain.stop() ;
}
});
}

public EmbeddedMediaPlayer getMediaPlayer() {
return playerComponent.getMediaPlayer() ;
}

public JProgressBar getProgressBar() {
return progress ;
}

}

效果

myplayer


如果您觉得我的文章对您有帮助,请随意赞赏,您的支持将鼓励我继续创作!
0%