Java 屏幕录制及多屏录制的简单实现

本文介绍了如何使用JavaCV库结合FFmpeg在Java项目中实现屏幕录制功能,包括添加必要的Maven依赖,以及提供了一个Windows多屏录制的示例代码,展示了如何配置视频质量、编码格式等参数。
摘要由CSDN通过智能技术生成

前言

近期接的一个公司内部安全终端需求,需要一个录屏功能,在调研了之后,使用 JavaCV 来实现录屏的功能。鉴于网上没有查找到扩展屏录制的相关代码,因此自己参考了官方文档后实现了录屏以及扩展屏录制的功能

基本原理看了下程序就是基于截屏,然后使用 ffmpeg 来合成视频。

JavaCV 就是一款开源的视觉处理库,封装了 FFmpeg、OpenCV、videoInput 和 ARToolKitPlus 等等计算机视觉的接口。

代码可在 github 查看:Fan-Yu-Feng/SpringBoot-demo: A SpringBoot Demo (github.com)

程序依赖

在 maven 的服务中添加以下的依赖。

        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.10</version>
        </dependency>
        <!-- 录屏需要的核心依赖 -->
        <!-- https://mvnrepository.com/artifact/org.bytedeco.javacpp-presets/ffmpeg-platform -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg-platform</artifactId>
            <version>6.1.1-1.5.10</version>
        </dependency>

录屏代码实现


/**
 * @author fanyufeng
 *
 * 使用 javacv 进行录屏
 */
@Data
@Slf4j
public class VideoRecorderTest {
	// 线程池 screenTimer
	private ScheduledThreadPoolExecutor screenTimer;
	private static boolean isStop = false;
	// 获取屏幕尺寸
	private static final int WIDTH = 2560;
	private static final int HEIGHT = 1600;
	private Rectangle rectangle;
	// 视频类 FFmpegFrameRecorder
	private Robot robot;
	// 线程池 exec
	private ScheduledThreadPoolExecutor exec;
	private OpenCVFrameConverter.ToIplImage conveter;
	// private BufferedImage screenCapture;
	private TargetDataLine line;
	private AudioFormat audioFormat;
	private DataLine.Info dataLineInfo;
	private boolean isHaveDevice = true;
	private long startTime = 0;
	private long videoTS = 0;
	private long pauseTime = 0;
	/* 录制的频率 */
	private int frameRate = 1;

	public VideoRecorderTest() {
	}

	// 定义时间格式,使用 "-" 拼接日期和时间
	DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss");
	public static final String screenFilePath = "D:\\screenRecoding\\";
	// String fileName = screenFilePath + DateUtil.formatAsDatetimeWithMs(new Date());

	/**
	 *  windows 多屏录制 demo
	 */
	@Test
	public void recordTest() throws AWTException, InterruptedException, FFmpegFrameRecorder.Exception {
		// 获取当前时间
		LocalDateTime currentTime = LocalDateTime.now();
		// 格式化当前时间为字符串
		String fileName = screenFilePath + currentTime.format(formatter);

		// 创建一个线程池
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		GraphicsDevice[] screens = ge.getScreenDevices();
		Robot robot = new Robot();
		screenTimer = new ScheduledThreadPoolExecutor(5);
		isStop = false;
		int i = 0;
		for (GraphicsDevice screen : screens) {
			DisplayMode displayMode = screen.getDisplayMode();
			Rectangle screenRect = screen.getDefaultConfiguration().getBounds();
			screenRect.height = displayMode.getHeight();
			screenRect.width = displayMode.getWidth();


			FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(fileName + i++ + ".mp4",
					displayMode.getWidth(), displayMode.getHeight(), 0);
			buildRecord(recorder);
			screenTimer.scheduleAtFixedRate(() -> {
				// 主动截屏屏幕偏红,需要重绘截图
				BufferedImage screenCapture = robot.createScreenCapture(screenRect);
				BufferedImage videoImg = new BufferedImage(displayMode.getWidth(), displayMode.getHeight(),
						BufferedImage.TYPE_3BYTE_BGR);
				// 声明一个 BufferedImage 用重绘截图
				Graphics2D videoGraphics = videoImg.createGraphics();// 创建 videoImg 的 Graphics2D
				videoGraphics.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
				videoGraphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
						RenderingHints.VALUE_COLOR_RENDER_SPEED);
				videoGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
				videoGraphics.drawImage(screenCapture, 0, 0, null); // 重绘截图

				Java2DFrameConverter java2dConverter = new Java2DFrameConverter();
				Frame frame = java2dConverter.convert(videoImg);
				try {
					// 检查偏移量
					log.info("开始录制屏幕");
					recorder.record(frame);
				} catch (Exception e) {
					log.error("录屏功能出现异常:", e);
				} finally {
					// 释放资源
					// videoGraphics.dispose();
					// videoGraphics = null;
					videoImg.flush();
					videoImg = null;
					java2dConverter = null;
					// screenCapture.flush();
					// screenCapture = null;
				}
				if (isStop) {
					try {
						log.info("录制线程池结束运行");
						recorder.stop();
						recorder.release();
						recorder.close();
						Thread.sleep(1000);
						screenTimer.shutdown();
					} catch (Exception e) {
						log.error("停止录屏功能出现异常:", e);
					} catch (InterruptedException e) {
						throw new RuntimeException(e);
					}
				}
			}, 0, 1000 / frameRate, TimeUnit.MILLISECONDS);

		}

		// 线程睡眠 5S 录制 5S
		Thread.sleep(1000 * 30);
		log.info("执行完任务");
		isStop = true;
		Thread.sleep(1000 * 10);
		// 等待任务执行完毕

	}

	private FFmpegFrameRecorder buildRecord(FFmpegFrameRecorder recorder) throws FFmpegFrameRecorder.Exception {

		recorder.setVideoQuality(0);
		recorder.setVideoOption("preset", "slow");
		recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); // 13
		recorder.setFormat("mp4");
		// recorder.setFormat("mov,mp4,m4a,3gp,3g2,mj2,h264,ogg,MPEG4");
		recorder.setSampleRate(44100);
		recorder.setFrameRate(frameRate);
		recorder.setVideoOption("crf", "23");
		// 2000 kb/s, 720P 视频的合理比特率范围 调整低了就改变画质,降低文件的大小
		recorder.setVideoBitrate(50000); // 500 kbps
		recorder.setPixelFormat(0); // yuv420p = 0
		recorder.start();
		return recorder;
	}
}

录屏结果查看

image-20240305211022389

个人blog

yohong’s blog

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值