Java使用Vlcj进行屏幕录制

目录
  1. 需求
  2. 解决
    1. 添加主要依赖
    2. 关键代码
      1. 注意
    3. 界面效果

需求

使用Java编写GUI程序完成简单的屏幕录制操作,支持开始录屏、结束录屏、销毁本次录制等操作。

解决

添加主要依赖

1
2
3
4
5
<dependency>
<groupId>uk.co.caprica</groupId>
<artifactId>vlcj</artifactId>
<version>4.2.0</version>
</dependency>

关键代码

1、Application.java(项目的入口)

1
2
3
4
5
6
public class Application {
public static void main(String[] args) {
// 其中 destination 为 录制完成后视频文件存放的目录
SwingUtilities.invokeLater(() -> new ScreenRecorder(destination));
}
}

2、ScreenRecorder.java(GUI 及 录屏 主要逻辑)

程序 包含3个按钮,开始、停止、销毁;2个操作目录,录制完成后视频文件存放的目录A(vlcj使用) 及 待处理业务目录B(自身业务使用)。

一般流程是 先点击 开始,此时 目录A下会 多一个视频文件,录制一段视频,点击停止,程序会将目录A下的视频移至 目录B下,此时可进行后续业务处理。因为 开始录制时目录A就会创建文件,导致目录A下文件可能不是最终文件(录制未完成),所以目录B就有存在的意义,程序关闭再启动后也可遍历 目录B下的文件 处理未完成的业务。

销毁按钮用于 开始录制但未停止时想放弃本次录制,注意停止后再销毁无效。

录制中关闭程序,则保存本次录制。

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
public class ScreenRecorder {

private static final String[] OPTIONS = {
"--quiet",
"--quiet-synchro",
"--intf",
"dummy"
};

private static String filePath = "";

private static final String MRL = "screen://";
private static final String SOUT = ":sout=#transcode{vcodec=mp4v,acodec=mpga,vb=4096,ab=512}:duplicate{dst=file{dst=%s}}";
private static final String FPS = ":screen-fps=20";
private static final String CACHING = ":screen-caching=500";

private final MediaPlayerFactory mediaPlayerFactory;
private final MediaPlayer mediaPlayer;

private JFrame frame;
private static JLabel countLabel;
private static JTextField nameField;

public ScreenRecorder(final String destination) {
mediaPlayerFactory = new MediaPlayerFactory(OPTIONS);
mediaPlayer = mediaPlayerFactory.mediaPlayers().newMediaPlayer();
JPanel cp = new JPanel();
nameField = new JTextField(5);
JButton recordButton = new JButton("开始");
JButton stopButton = new JButton("停止");
JButton delButton = new JButton("销毁");
cp.add(recordButton);
cp.add(stopButton);
cp.add(delButton);
frame = new JFrame("录屏程序");
// 图标化
// frame.setExtendedState(JFrame.ICONIFIED);
frame.setContentPane(cp);
frame.setLocation(10, 10);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
release();
}
});
recordButton.addActionListener(e -> go(destination));
stopButton.addActionListener(e -> stop());
delButton.addActionListener(e -> delete());
frame.setVisible(true);
}

private void go(String destination) {
State state = mediaPlayer.status().state();
filePath = destination + getUUID() + ".mp4";
mediaPlayer.media().play(MRL, getMediaOptions(filePath));
updateTitle("录屏中");
}

private void stop() {
State state = mediaPlayer.status().state();
mediaPlayer.controls().stop();
if (!state.equals(State.STOPPED) && !state.equals(State.NOTHING_SPECIAL)) {
// 将 目录A下的文件 移动到 目录B
FileUtil.moveFile(filePath, waitSendPath);
filePath = "";
}
updateTitle("停止");
}

private void delete() {
mediaPlayer.controls().stop();
if (!"".equals(filePath)) {
FileUtil.delFile(filePath);
}
updateTitle("停止");
}

private void release() {
State state = mediaPlayer.status().state();
if (state.equals(State.PLAYING)) {
// 如果关闭时程序录制中,则保存本次录制
stop();
}
log.info("status:" + state);

mediaPlayer.release();
mediaPlayerFactory.release();
}

private void updateTitle(String title) {
frame.setTitle("录屏程序:" + title);
}

private String[] getMediaOptions(String destination) {
String result = String.format(SOUT, destination);
return new String[] {
result,
FPS,
CACHING
};
}
}
注意
  1. vlcj好像不能处理好windows下的中文文件名乱码的问题(创建的中文文件名乱码),mac下没问题,可以定义map存放 目录A下的随机非中文文件名 及 想要的中文文件名,在将文件从目录A移动到目录B后使用中文文件名。
  2. 虽然视频文件是以.mp4结尾,且视频文件能用一般的播放器打开,但文件应该不是标准的mp4,使用浏览器无法直接播放。我对视频编码这里不了解,因此也没有进行后续研究(有更好的解决办法欢迎留言交流),后续业务采用阿里云进行视频转码,转换后的mp4可在浏览器中直接打开。
  3. 暂不支持声音录制。
  4. 可使用Java监听 目录B 文件变化来实现后续业务 Java监听文件变化

界面效果

Java Vlcj录屏程序最终效果