本文目录导读:

在Java中实现录屏功能,主要有几种不同的技术方案,下面我会详细介绍几种常见的实现方式,并提供完整的代码示例。
使用Robot类 + JavaCV(最常用)
这是最经典的方式,使用java.awt.Robot截取屏幕,配合JavaCV生成视频文件。
Maven依赖
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>
完整实现代码
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ScreenRecorder {
private FFmpegFrameRecorder recorder;
private volatile boolean recording = false;
private Rectangle screenBounds;
private Robot robot;
private Thread recordingThread;
private String outputPath;
public ScreenRecorder(String outputPath) {
this.outputPath = outputPath;
this.screenBounds = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
try {
this.robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
}
public void startRecording() {
if (recording) return;
recording = true;
recordingThread = new Thread(() -> {
try {
// 初始化录制器
recorder = new FFmpegFrameRecorder(outputPath,
screenBounds.width, screenBounds.height);
recorder.setVideoCodec(org.bytedeco.javacv.FrameRecorder.VideoCodec.H264);
recorder.setFormat("mp4");
recorder.setFrameRate(30);
recorder.setPixelFormat(org.bytedeco.javacv.FrameRecorder.PixelFormat.YUV420P);
recorder.start();
Java2DFrameConverter converter = new Java2DFrameConverter();
while (recording) {
// 截图
BufferedImage screenCapture = robot.createScreenCapture(screenBounds);
BufferedImage image = convertToType(screenCapture, BufferedImage.TYPE_3BYTE_BGR);
// 转换为Frame并录制
Frame frame = converter.convert(image);
recorder.record(frame);
// 控制帧率
Thread.sleep(33); // 约30fps
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (recorder != null) {
recorder.stop();
recorder.release();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
recordingThread.start();
System.out.println("录屏已开始,输出文件:" + outputPath);
}
public void stopRecording() {
recording = false;
if (recordingThread != null) {
try {
recordingThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("录屏已停止");
}
private BufferedImage convertToType(BufferedImage sourceImage, int targetType) {
BufferedImage image = new BufferedImage(
sourceImage.getWidth(),
sourceImage.getHeight(),
targetType
);
Graphics2D g = image.createGraphics();
g.drawImage(sourceImage, 0, 0, null);
g.dispose();
return image;
}
// 使用示例
public static void main(String[] args) {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String outputPath = "screen_recording_" + timestamp + ".mp4";
ScreenRecorder recorder = new ScreenRecorder(outputPath);
recorder.startRecording();
// 录制10秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
recorder.stopRecording();
}
}
使用JNativeHook实现热键控制
添加全局热键支持,方便开始/停止录制:
<dependency>
<groupId>com.github.kwhat</groupId>
<artifactId>jnativehook</artifactId>
<version>2.2.2</version>
</dependency>
import com.github.kwhat.jnativehook.GlobalScreen;
import com.github.kwhat.jnativehook.keyboard.NativeKeyEvent;
import com.github.kwhat.jnativehook.keyboard.NativeKeyListener;
public class HotkeyRecorder extends ScreenRecorder implements NativeKeyListener {
public HotkeyRecorder(String outputPath) {
super(outputPath);
}
@Override
public void nativeKeyPressed(NativeKeyEvent e) {
// F6 开始录制,F7 停止录制
if (e.getKeyCode() == NativeKeyEvent.VC_F6) {
startRecording();
} else if (e.getKeyCode() == NativeKeyEvent.VC_F7) {
stopRecording();
}
}
@Override
public void nativeKeyReleased(NativeKeyEvent e) {}
@Override
public void nativeKeyTyped(NativeKeyEvent e) {}
public void registerHotkeys() {
try {
GlobalScreen.registerNativeHook();
GlobalScreen.addNativeKeyListener(this);
} catch (Exception e) {
e.printStackTrace();
}
}
public void unregisterHotkeys() {
try {
GlobalScreen.unregisterNativeHook();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String outputPath = "screen_recording_hotkey.mp4";
HotkeyRecorder recorder = new HotkeyRecorder(outputPath);
recorder.registerHotkeys();
System.out.println("按 F6 开始录制,按 F7 停止录制");
// 防止程序退出
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
带GUI的控制界面
提供一个简单的Swing界面控制录制:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ScreenRecorderGUI extends JFrame {
private ScreenRecorder recorder;
private JButton startButton;
private JButton stopButton;
private JLabel statusLabel;
private JTextField fpsField;
public ScreenRecorderGUI() {
setTitle("屏幕录制器");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
// 控制面板
JPanel controlPanel = new JPanel();
startButton = new JButton("开始录制");
stopButton = new JButton("停止录制");
stopButton.setEnabled(false);
statusLabel = new JLabel("就绪");
// FPS设置
controlPanel.add(new JLabel("FPS:"));
fpsField = new JTextField("30", 5);
controlPanel.add(fpsField);
controlPanel.add(startButton);
controlPanel.add(stopButton);
add(controlPanel, BorderLayout.NORTH);
add(statusLabel, BorderLayout.CENTER);
// 事件监听
startButton.addActionListener(e -> startRecording());
stopButton.addActionListener(e -> stopRecording());
pack();
setLocationRelativeTo(null);
}
private void startRecording() {
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String outputPath = "recording_" + timestamp + ".mp4";
recorder = new ScreenRecorder(outputPath);
recorder.startRecording();
startButton.setEnabled(false);
stopButton.setEnabled(true);
statusLabel.setText("正在录制... " + outputPath);
}
private void stopRecording() {
if (recorder != null) {
recorder.stopRecording();
}
startButton.setEnabled(true);
stopButton.setEnabled(false);
statusLabel.setText("录制完成");
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new ScreenRecorderGUI().setVisible(true);
});
}
}
高性能录屏(使用grabber)
对于更高性能要求的场景,可以使用JavaCV的FrameGrabber:
import org.bytedeco.javacv.*;
import org.bytedeco.javacpp.*;
public class HighPerformanceRecorder {
public static void startRecording(String outputPath, int duration) {
Rectangle screenBounds = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
try {
// 创建截屏抓取器
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("desktop");
grabber.setFormat("gdigrab"); // Windows下使用gdigrab
grabber.setFrameRate(30);
grabber.setImageWidth(screenBounds.width);
grabber.setImageHeight(screenBounds.height);
grabber.start();
// 创建录制器
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath,
screenBounds.width, screenBounds.height);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setFormat("mp4");
recorder.setFrameRate(30);
recorder.start();
long startTime = System.currentTimeMillis();
Frame frame;
while ((frame = grabber.grab()) != null) {
recorder.record(frame);
// 检查是否达到指定时长
if (System.currentTimeMillis() - startTime > duration * 1000) {
break;
}
}
recorder.stop();
grabber.stop();
System.out.println("录制完成");
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意事项
-
性能优化:实际的屏幕录制对性能要求较高,特别是高分辨率下,建议:
- 适当降低帧率(15-30fps)
- 可以降低录制分辨率
- 使用硬件编码加速
-
跨平台问题:
- Windows:使用gdigrab或Robot
- macOS:使用AVFoundation
- Linux:使用X11或KMS
-
权限问题:某些系统可能需要屏幕录制权限
-
内存管理:长时间录屏要注意内存使用,及时清理
-
音频录制:如需同时录制音频,需要额外添加音频捕获功能
方案中,方案一(Robot + JavaCV)是最通用和稳定的选择,你可以根据实际需求选择合适的实现方式,并在此基础上进行功能扩展。