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