diff --git a/README.md b/README.md index f8d0eb6c2bad65357238a89eecb06dea0ea82e62..9e25cec6b7c177b7f4230df5e281c391388ee758 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#由于工作中的需求,需要用java来实现当前电脑的录屏功能以及屏幕的截图截屏功能 +# 由于工作中的需求,需要用java来实现当前电脑的录屏功能以及屏幕的截图截屏功能 * 由于习惯了springboot 所以就写在springboot上了,并暴露了一个接口来触发录屏功能 * 核心代码在fxbase包下的VideoRecorder类中 但是代码写的有点乱,使用者可以不必过度关注这个类 而是看看RecorderUtil,我将这个类注入到了ioc容器,这个类的getVideoRecorderInstance可以获取录屏对象 调用这个对象的start()和stop()方法来完成录制和结束,具体过程很简单,可以看RecorderController的调用过程 @@ -19,3 +19,5 @@ * ####注意:主函数的启动类不是SpringApplication.run(DemoApplication.class, args);不然触发录屏会报错。而是SpringApplicationBuilder builder = new SpringApplicationBuilder(VideoRecordeApplication.class); builder.headless(false).run(args); +## 多屏录制测试demo +- com.example.demo.VideoRecorderTest.recordTest \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8183dd04f681d79dbde004a46b7394a9381b3575..1c95451f15661c0f2c00c28ffad7a969a605a247 100644 --- a/pom.xml +++ b/pom.xml @@ -31,10 +31,16 @@ + + + + + + org.bytedeco - javacv - 1.4.4 + javacv-platform + 1.5.10 @@ -59,6 +65,10 @@ spring-boot-starter-test test + + junit + junit + diff --git a/src/main/java/com/ht/recode/Controller/RecorderController.java b/src/main/java/com/ht/recode/Controller/RecorderController.java index 1ceb4d30e8263f83c501919fe902cd5fe936024e..7f07649946751d9121f1b2918df9fdd8bb50b56e 100644 --- a/src/main/java/com/ht/recode/Controller/RecorderController.java +++ b/src/main/java/com/ht/recode/Controller/RecorderController.java @@ -72,7 +72,7 @@ public class RecorderController { Thread.sleep(reTime); //截图 需要图片的用这个方法取图 - CutPicUtil.cutPic(name,imgPath,"png",videoRecorder.getRectangle()); + // CutPicUtil.cutPic(name,imgPath,"png",videoRecorder.getRectangle()); log.info("截图保存在这个文件夹下====》:"+imgPath); //结束============================================================================================ diff --git a/src/main/java/com/ht/recode/fxbase/RecorderUtil.java b/src/main/java/com/ht/recode/fxbase/RecorderUtil.java index c6edcd0e2ac86da3070f2806818757cbf41b16e2..643487816f53f6ef9a080335899c3829ad7b602d 100644 --- a/src/main/java/com/ht/recode/fxbase/RecorderUtil.java +++ b/src/main/java/com/ht/recode/fxbase/RecorderUtil.java @@ -1,6 +1,5 @@ package com.ht.recode.fxbase; -import com.ht.recode.fxbase.VideoRecorder; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @@ -37,8 +36,7 @@ public class RecorderUtil { //文件夹+文件名 String fileHoldName = fileName + videoName; //调用录屏API的对象 这个对象就可以开启或者关闭录屏 - VideoRecorder videoRecord = new VideoRecorder(fileHoldName, true,rectangle); - return videoRecord; + return new VideoRecorder(fileHoldName, true, rectangle); } } diff --git a/src/main/java/com/ht/recode/fxbase/VideoRecorder.java b/src/main/java/com/ht/recode/fxbase/VideoRecorder.java index 9e7f67f67a28b7dfc6ec94c7c76e22ac9193455a..976d2292dc5642b9a282eea4bb9b835d62c5b05a 100644 --- a/src/main/java/com/ht/recode/fxbase/VideoRecorder.java +++ b/src/main/java/com/ht/recode/fxbase/VideoRecorder.java @@ -6,18 +6,24 @@ package com.ht.recode.fxbase; * @date 2021/1/13 9:43 */ import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.bytedeco.ffmpeg.global.avutil; import org.bytedeco.javacpp.avcodec; -import org.bytedeco.javacv.FFmpegFrameRecorder; +import org.bytedeco.javacv.*; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameRecorder.Exception; -import org.bytedeco.javacv.Java2DFrameConverter; +import org.junit.Test; +import javax.imageio.ImageIO; import javax.sound.sampled.*; import java.awt.*; import java.awt.image.BufferedImage; +import java.io.File; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -26,18 +32,23 @@ import java.util.concurrent.TimeUnit; */ @Data +@Slf4j public class VideoRecorder { //线程池 screenTimer private ScheduledThreadPoolExecutor screenTimer; + private static boolean isStop = false; //获取屏幕尺寸 - private static final int WIDTH = 900; - private static final int HEIGHT = 600; + private static final int WIDTH = 2560; + private static final int HEIGHT = 1600; private Rectangle rectangle; //视频类 FFmpegFrameRecorder private FFmpegFrameRecorder recorder; private Robot robot; //线程池 exec private ScheduledThreadPoolExecutor exec; + private String fileName; + private OpenCVFrameConverter.ToIplImage conveter; + private BufferedImage screenCapture; private TargetDataLine line; private AudioFormat audioFormat; private DataLine.Info dataLineInfo; @@ -45,63 +56,50 @@ public class VideoRecorder { private long startTime = 0; private long videoTS = 0; private long pauseTime = 0; - private double frameRate = 24; + /*录制的频率*/ + private int frameRate = 10; - public VideoRecorder(String fileName, boolean isHaveDevice, Rectangle rectangle1) { - rectangle = rectangle1; - // TODO Auto-generated constructor stub - System.out.println(rectangle1); - //recorder = new FFmpegFrameRecorder(fileName + ".mp4", (int)rectangle1.getWidth(), (int)rectangle1.getHeight(),2); - recorder = new FFmpegFrameRecorder(fileName + ".mp4", (int)rectangle1.getWidth(), (int)rectangle1.getHeight(),2); - //recorder.setVideoCodec(avcodec.AV_CODEC_ID_H265); // 28 - // recorder.setVideoCodec(avcodec.AV_CODEC_ID_FLV1); // 28 - 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.setVideoQuality(1); - recorder.setVideoOption("crf", "23"); - // 2000 kb/s, 720P视频的合理比特率范围 - recorder.setVideoBitrate(1000000); - /** - * 权衡quality(视频质量)和encode speed(编码速度) values(值): ultrafast(终极快),superfast(超级快), - * veryfast(非常快), faster(很快), fast(快), medium(中等), slow(慢), slower(很慢), - * veryslow(非常慢) - * ultrafast(终极快)提供最少的压缩(低编码器CPU)和最大的视频流大小;而veryslow(非常慢)提供最佳的压缩(高编码器CPU)的同时降低视频流的大小 - * 参考:https://trac.ffmpeg.org/wiki/Encode/H.264 官方原文参考:-preset ultrafast as the - * name implies provides for the fastest possible encoding. If some tradeoff - * between quality and encode speed, go for the speed. This might be needed if - * you are going to be transcoding multiple streams on one machine. - */ - recorder.setVideoOption("preset", "slow"); - recorder.setPixelFormat(0); // yuv420p = 0 - recorder.setAudioChannels(2); - recorder.setAudioOption("crf", "0"); - // Highest quality - recorder.setAudioQuality(0); - recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); - try { - robot = new Robot(); - } catch (AWTException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - try { - recorder.start(); - } catch (Exception e) { - // TODO Auto-generated catch block - System.out.print("*******************************"); - } - this.isHaveDevice = isHaveDevice; + public VideoRecorder(String fileName, boolean isHaveDevice, Rectangle rectangle) { + init(fileName, isHaveDevice, rectangle); } - - /** + + private void init(String fileName, boolean isHaveDevice, Rectangle rectangle) { + this.rectangle = rectangle; + System.out.println(this.rectangle); + recorder = new FFmpegFrameRecorder(fileName + ".mp4", + this.rectangle.width, this.rectangle.height,0); + recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 13 + recorder.setFormat("mp4"); + // recorder.setFormat("mov,mp4,m4a,3gp,3g2,mj2,h264,ogg,MPEG4"); + recorder.setSampleRate(44100); + recorder.setFrameRate(frameRate); + + recorder.setVideoQuality(1); + recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); + + recorder.setVideoOption("crf", "23"); + // 2000 kb/s, 720P视频的合理比特率范围 + recorder.setVideoBitrate(1000000); + recorder.setVideoOption("preset", "slow"); + try { + robot = new Robot(); + } catch (AWTException e) { + log.error("录屏功能出现异常:",e); + } + try { + recorder.start(); + } catch (Exception e) { + log.error("录屏功能出现异常:",e); + } + this.isHaveDevice = isHaveDevice; + } + + /** * 开始录制 */ public void start() { - + + isStop = false; if (startTime == 0) { startTime = System.currentTimeMillis(); } @@ -109,76 +107,69 @@ public class VideoRecorder { pauseTime = System.currentTimeMillis(); } // 如果有录音设备则启动录音线程 - /* if (isHaveDevice) { - new Thread(new Runnable() { - @Override - public void run() { - caputre(); - } - }).start(); - }*/ - - // 录屏 - screenTimer = new ScheduledThreadPoolExecutor(5); - screenTimer.scheduleAtFixedRate(new Runnable() { - - @Override - public void run() { - - // 将screenshot对象写入图像文件 - // try { - // ImageIO.write(screenCapture, "JPEG", f); - // videoGraphics.drawImage(screenCapture, 0, 0, null); - // IplImage image = cvLoadImage(name); // 非常吃内存!! - // // 创建一个 timestamp用来写入帧中 - // videoTS = 1000 - // * (System.currentTimeMillis() - startTime - (System.currentTimeMillis() - - // pauseTime)); - // // 检查偏移量 - // if (videoTS > recorder.getTimestamp()) { - // recorder.setTimestamp(videoTS); - // } - - BufferedImage screenCapture = robot.createScreenCapture(rectangle); // 截屏 - - BufferedImage videoImg = new BufferedImage((int)rectangle.getWidth(), (int)rectangle.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 { - videoTS = 1000L - * (System.currentTimeMillis() - startTime - (System.currentTimeMillis() - pauseTime)); - // 检查偏移量 - if (videoTS > recorder.getTimestamp()) { - recorder.setTimestamp(videoTS); - } - recorder.record(frame); // 录制视频 - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // 释放资源 - videoGraphics.dispose(); - videoGraphics = null; - videoImg.flush(); - videoImg = null; - java2dConverter = null; - screenCapture.flush(); - screenCapture = null; - - } - }, (int) (1000 / frameRate), (int) (1000 / frameRate), TimeUnit.MILLISECONDS); - + screenTimer = new ScheduledThreadPoolExecutor(5); + screenTimer.scheduleAtFixedRate(() -> { + // 截屏 + screenCapture = robot.createScreenCapture(rectangle); + // 声明一个BufferedImage用重绘截图 + BufferedImage videoImg = new BufferedImage(rectangle.width, rectangle.height, + BufferedImage.TYPE_3BYTE_BGR); + // 创建videoImg的Graphics2D + Graphics2D videoGraphics = videoImg.createGraphics(); + + 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("开始录制屏幕"); + // Frame frame = grabber.grabFrame(); + 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) { + if (null != screenTimer) { + screenTimer.shutdownNow(); + } + try { + recorder.stop(); + recorder.release(); + recorder.close(); + screenTimer = null; + screenCapture = null; + screenTimer.shutdown(); + if (isHaveDevice) { + if (null != exec) { + exec.shutdownNow(); + } + if (null != line) { + line.stop(); + line.close(); + } + dataLineInfo = null; + audioFormat = null; + } + } catch (Exception e) { + log.error("停止录屏功能出现异常:",e); + } + } + }, 0, 1000 / frameRate, TimeUnit.MILLISECONDS); } /** @@ -224,7 +215,7 @@ public class VideoRecorder { // recorder is instance of // org.bytedeco.javacv.FFmpegFrameRecorder recorder.recordSamples(sampleRate, numChannels, sBuff); - // System.gc(); + System.gc(); } catch (Exception e) { e.printStackTrace(); } @@ -236,30 +227,8 @@ public class VideoRecorder { * 停止 */ public void stop() { - if (null != screenTimer) { - screenTimer.shutdownNow(); - } - try { - recorder.stop(); - recorder.release(); - recorder.close(); - screenTimer = null; - // screenCapture = null; - if (isHaveDevice) { - if (null != exec) { - exec.shutdownNow(); - } - if (null != line) { - line.stop(); - line.close(); - } - dataLineInfo = null; - audioFormat = null; - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + + isStop = true; } @@ -282,7 +251,111 @@ public class VideoRecorder { } pauseTime = System.currentTimeMillis(); } - - - + + + public static void main(String[] args) throws AWTException { + + } + + @Test + public void record() throws AWTException, InterruptedException, FFmpegFrameRecorder.Exception { + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] screens = ge.getScreenDevices(); + + Robot robot = new Robot(); + screenTimer = new ScheduledThreadPoolExecutor(5); + int i = 0; + for (GraphicsDevice screen : screens) { + + Rectangle screenRect = screen.getDefaultConfiguration().getBounds(); + FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(fileName + i++ + ".mp4", + screenRect.width, screenRect.height,0); + recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 13 + recorder.setFormat("mp4"); + // recorder.setFormat("mov,mp4,m4a,3gp,3g2,mj2,h264,ogg,MPEG4"); + recorder.setSampleRate(44100); + recorder.setFrameRate(frameRate); + + recorder.setVideoQuality(1); + recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); + + recorder.setVideoOption("crf", "23"); + // 2000 kb/s, 720P视频的合理比特率范围 + recorder.setVideoBitrate(1000000); + recorder.setVideoOption("preset", "slow"); + recorder.start(); + + + screenTimer.scheduleAtFixedRate(() -> { + // 截屏 + // screenCapture = robot.createScreenCapture(rectangle); + BufferedImage videoImg = robot.createScreenCapture(screenRect); + + // 声明一个BufferedImage用重绘截图 + // BufferedImage videoImg = new BufferedImage(rectangle.width, rectangle.height, + // BufferedImage.TYPE_3BYTE_BGR); + // 创建videoImg的Graphics2D + // Graphics2D videoGraphics = videoImg.createGraphics(); + + // 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("开始录制屏幕"); + // Frame frame = grabber.grabFrame(); + 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) { + if (null != screenTimer) { + screenTimer.shutdownNow(); + } + try { + recorder.stop(); + recorder.release(); + recorder.close(); + screenTimer = null; + screenCapture = null; + screenTimer.shutdown(); + if (isHaveDevice) { + if (null != exec) { + exec.shutdownNow(); + } + if (null != line) { + line.stop(); + line.close(); + } + dataLineInfo = null; + audioFormat = null; + } + } catch (Exception e) { + log.error("停止录屏功能出现异常:",e); + } + } + }, 0, 1000 / frameRate, TimeUnit.MILLISECONDS); + } + Thread.sleep(10000); + isStop = true; + + } + + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ac3599153fa52a9493475de9c6d0a00412c4db6b..5a64ebaaae2dce501c14558e7f3dd94512716cfb 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,7 +1,7 @@ video.recorder.startx=0 video.recorder.starty=0 -video.recorder.width=1920 -video.recorder.height=1080 +video.recorder.width=2560 +video.recorder.height=1600 video.recorder.file-name=D://screenRecoding/ video.recorder.recorderTime=10000 video.recorder.img-path=D://img/ diff --git a/src/test/java/com/example/demo/VideoRecorderTest.java b/src/test/java/com/example/demo/VideoRecorderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1fafc72bcc1281d61fdd7fa67de98edc7e9abad1 --- /dev/null +++ b/src/test/java/com/example/demo/VideoRecorderTest.java @@ -0,0 +1,161 @@ +package com.example.demo; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.bytedeco.javacpp.avcodec; +import org.bytedeco.javacv.FFmpegFrameRecorder; +import org.bytedeco.javacv.Frame; +import org.bytedeco.javacv.FrameRecorder.Exception; +import org.bytedeco.javacv.Java2DFrameConverter; +import org.bytedeco.javacv.OpenCVFrameConverter; +import org.junit.jupiter.api.Test; + +import javax.sound.sampled.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.concurrent.*; + +/** + * @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 String fileName; + 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 = 10; + + public VideoRecorderTest() { + } + + + /** + * windows 多屏录制demo + */ + @Test + public void recordTest() throws AWTException, InterruptedException, FFmpegFrameRecorder.Exception { + // screenTimer = new ScheduledThreadPoolExecutor(5); + // 创建一个线程池 + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] screens = ge.getScreenDevices(); + fileName = "D:\\screenRecoding\\zxczxc"; + Robot robot = new Robot(); + screenTimer = new ScheduledThreadPoolExecutor(5); + isStop = false; + int i = 0; + // for (GraphicsDevice gd : screens) { + // DisplayMode displayMode = gd.getDisplayMode(); + // System.out.println("Screen Resolution: " + displayMode.getWidth() + "x" + displayMode.getHeight()); + // } + 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 * 10); + log.info("执行完任务"); + isStop = true; + Thread.sleep(1000 * 10); + // 等待任务执行完毕 + + } + + + private FFmpegFrameRecorder buildRecord(FFmpegFrameRecorder recorder) throws FFmpegFrameRecorder.Exception { + + recorder.setSampleRate(44100); + recorder.setFrameRate(frameRate); + recorder.setVideoQuality(1); + 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.setVideoQuality(1); + recorder.setVideoOption("crf", "23"); + // 2000 kb/s, 720P视频的合理比特率范围 + recorder.setVideoBitrate(1000000); + recorder.setPixelFormat(0); // yuv420p = 0 + recorder.start(); + return recorder; + } + + +}