From 42fc050f47dd7e1bdb85655d7bb2f1439c3bdc6b Mon Sep 17 00:00:00 2001 From: fanyufeng Date: Fri, 23 Feb 2024 15:00:20 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E5=BD=95=E5=B1=8F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 10 +- .../recode/Controller/RecorderController.java | 2 +- .../com/ht/recode/fxbase/RecorderUtil.java | 4 +- .../com/ht/recode/fxbase/VideoRecorder.java | 287 +++++++++--------- src/main/resources/application.properties | 4 +- 5 files changed, 155 insertions(+), 152 deletions(-) diff --git a/pom.xml b/pom.xml index 8183dd0..224d7a4 100644 --- a/pom.xml +++ b/pom.xml @@ -31,10 +31,16 @@ + + + + + + org.bytedeco - javacv - 1.4.4 + javacv-platform + 1.5.10 diff --git a/src/main/java/com/ht/recode/Controller/RecorderController.java b/src/main/java/com/ht/recode/Controller/RecorderController.java index 1ceb4d3..7f07649 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 c6edcd0..6434878 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 9e7f67f..e088e66 100644 --- a/src/main/java/com/ht/recode/fxbase/VideoRecorder.java +++ b/src/main/java/com/ht/recode/fxbase/VideoRecorder.java @@ -6,18 +6,23 @@ 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 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 +31,25 @@ 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 +57,73 @@ 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", (int)rectangle1.getWidth(), (int)rectangle1.getHeight(),2); + recorder = new FFmpegFrameRecorder(fileName + ".mp4", + this.rectangle.width, this.rectangle.height,0); + //recorder.setVideoCodec(avcodec.AV_CODEC_ID_H265); // 28 + // recorder.setVideoCodec(avcodec.AV_CODEC_ID_FLV1); // 28 + 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.setVideoBitrate(400000); + /** + * 权衡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.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; + + this.isHaveDevice = isHaveDevice; + } + + /** * 开始录制 */ - public void start() { - + public void start() throws FrameGrabber.Exception { + isStop = false; if (startTime == 0) { startTime = System.currentTimeMillis(); } @@ -117,68 +139,67 @@ public class VideoRecorder { } }).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 videoImg = new BufferedImage(rectangle.width, rectangle.height, + 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("开始录制屏幕"); + // Frame frame = grabber.grabFrame(); + recorder.record(frame); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + log.error("出现异常:",e); + } + // 释放资源 + 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) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + }, 0, 1000 / frameRate, TimeUnit.MILLISECONDS); } /** @@ -224,7 +245,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 +257,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; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ac35991..5a64eba 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/ -- Gitee From 03cba5fde14c84b63a5d13792c827ffa4d31349b Mon Sep 17 00:00:00 2001 From: fanyufeng Date: Fri, 23 Feb 2024 19:55:15 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E6=89=A9=E5=B1=95=E5=B1=8F?= =?UTF-8?q?=E5=BD=95=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 + .../java/com/example/demo/VideoRecorder.java | 174 ++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/test/java/com/example/demo/VideoRecorder.java diff --git a/pom.xml b/pom.xml index 224d7a4..1c95451 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,10 @@ spring-boot-starter-test test + + junit + junit + diff --git a/src/test/java/com/example/demo/VideoRecorder.java b/src/test/java/com/example/demo/VideoRecorder.java new file mode 100644 index 0000000..efc9bc1 --- /dev/null +++ b/src/test/java/com/example/demo/VideoRecorder.java @@ -0,0 +1,174 @@ +package com.example.demo; + +/** + * @author 王瑞 + * @description: TODO + * @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.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.*; + +/** + * 使用javacv进行录屏 + */ + +@Data +@Slf4j +public class VideoRecorder { + //线程池 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 VideoRecorder() { + } + + + /** + * 停止 + */ + public void stop() { + + isStop = true; + + } + + /** + * 暂停 + * + * @throws Exception + */ + public void pause() throws Exception { + screenTimer.shutdownNow(); + screenTimer = null; + if (isHaveDevice) { + exec.shutdownNow(); + exec = null; + line.stop(); + line.close(); + dataLineInfo = null; + audioFormat = null; + line = null; + } + pauseTime = System.currentTimeMillis(); + } + + + @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 screen : screens) { + Rectangle screenRect = screen.getDefaultConfiguration().getBounds(); + FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(fileName + i++ + ".mp4", + screenRect.width, screenRect.height, 0); + buildRecord(recorder); + screenTimer.scheduleAtFixedRate(() -> { + BufferedImage videoImg = robot.createScreenCapture(screenRect); + 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) { + try { + log.info("录制线程池结束运行"); + recorder.stop(); + recorder.release(); + recorder.close(); + screenTimer.shutdown(); + } catch (Exception e) { + log.error("停止录屏功能出现异常:", e); + } + } + }, 0, 1000 / frameRate, TimeUnit.MILLISECONDS); + + } + + // 线程睡眠5S 录制5S + Thread.sleep(1000 * 50); + log.info("执行完任务"); + isStop = true; + Thread.sleep(1000 * 100); + // 等待任务执行完毕 + + } + + private FFmpegFrameRecorder buildRecord(FFmpegFrameRecorder recorder) throws FFmpegFrameRecorder.Exception { + + // recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 13 + 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(); + return recorder; + } + + +} -- Gitee From 9e864ea8d2adff666e21c33325cb4e8ecceddf5a Mon Sep 17 00:00:00 2001 From: fanyufeng Date: Mon, 26 Feb 2024 14:32:01 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=E5=B1=8F?= =?UTF-8?q?=E5=B9=95=E7=BA=A2=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ht/recode/fxbase/VideoRecorder.java | 190 ++++++++++++------ .../java/com/example/demo/VideoRecorder.java | 105 +++++++++- 2 files changed, 229 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/ht/recode/fxbase/VideoRecorder.java b/src/main/java/com/ht/recode/fxbase/VideoRecorder.java index e088e66..976d229 100644 --- a/src/main/java/com/ht/recode/fxbase/VideoRecorder.java +++ b/src/main/java/com/ht/recode/fxbase/VideoRecorder.java @@ -12,6 +12,7 @@ import org.bytedeco.javacpp.avcodec; import org.bytedeco.javacv.*; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameRecorder.Exception; +import org.junit.Test; import javax.imageio.ImageIO; import javax.sound.sampled.*; @@ -35,8 +36,6 @@ import java.util.concurrent.TimeUnit; public class VideoRecorder { //线程池 screenTimer private ScheduledThreadPoolExecutor screenTimer; - - private static boolean isStop = false; //获取屏幕尺寸 private static final int WIDTH = 2560; @@ -65,14 +64,10 @@ public class VideoRecorder { } private void init(String fileName, boolean isHaveDevice, Rectangle rectangle) { - this.rectangle = rectangle; System.out.println(this.rectangle); - //recorder = new FFmpegFrameRecorder(fileName + ".mp4", (int)rectangle1.getWidth(), (int)rectangle1.getHeight(),2); recorder = new FFmpegFrameRecorder(fileName + ".mp4", this.rectangle.width, this.rectangle.height,0); - //recorder.setVideoCodec(avcodec.AV_CODEC_ID_H265); // 28 - // recorder.setVideoCodec(avcodec.AV_CODEC_ID_FLV1); // 28 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 13 recorder.setFormat("mp4"); // recorder.setFormat("mov,mp4,m4a,3gp,3g2,mj2,h264,ogg,MPEG4"); @@ -85,44 +80,25 @@ public class VideoRecorder { recorder.setVideoOption("crf", "23"); // 2000 kb/s, 720P视频的合理比特率范围 recorder.setVideoBitrate(1000000); - // recorder.setVideoBitrate(400000); - /** - * 权衡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.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(); + log.error("录屏功能出现异常:",e); } try { recorder.start(); } catch (Exception e) { - // TODO Auto-generated catch block - System.out.print("*******************************"); + log.error("录屏功能出现异常:",e); } this.isHaveDevice = isHaveDevice; - - this.isHaveDevice = isHaveDevice; } /** * 开始录制 */ - public void start() throws FrameGrabber.Exception { + public void start() { + isStop = false; if (startTime == 0) { startTime = System.currentTimeMillis(); @@ -131,28 +107,23 @@ public class VideoRecorder { pauseTime = System.currentTimeMillis(); } // 如果有录音设备则启动录音线程 - /* if (isHaveDevice) { - new Thread(new Runnable() { - @Override - public void run() { - caputre(); - } - }).start(); - }*/ screenTimer = new ScheduledThreadPoolExecutor(5); screenTimer.scheduleAtFixedRate(() -> { - screenCapture = robot.createScreenCapture(rectangle); // 截屏 + // 截屏 + screenCapture = robot.createScreenCapture(rectangle); + // 声明一个BufferedImage用重绘截图 BufferedImage videoImg = new BufferedImage(rectangle.width, rectangle.height, - BufferedImage.TYPE_3BYTE_BGR); // 声明一个BufferedImage用重绘截图 - Graphics2D videoGraphics = videoImg.createGraphics();// 创建videoImg的Graphics2D + 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); // 重绘截图 + // 重绘截图 + videoGraphics.drawImage(screenCapture, 0, 0, null); Java2DFrameConverter java2dConverter = new Java2DFrameConverter(); - Frame frame = java2dConverter.convert(videoImg); try { // 检查偏移量 @@ -160,18 +131,18 @@ public class VideoRecorder { // Frame frame = grabber.grabFrame(); recorder.record(frame); } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - log.error("出现异常:",e); + log.error("录屏功能出现异常:",e); + }finally { + // 释放资源 + videoGraphics.dispose(); + videoGraphics = null; + videoImg.flush(); + videoImg = null; + java2dConverter = null; + screenCapture.flush(); + screenCapture = null; } - // 释放资源 - videoGraphics.dispose(); - videoGraphics = null; - videoImg.flush(); - videoImg = null; - // java2dConverter = null; - screenCapture.flush(); - screenCapture = null; + if (isStop) { if (null != screenTimer) { screenTimer.shutdownNow(); @@ -195,8 +166,7 @@ public class VideoRecorder { audioFormat = null; } } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + log.error("停止录屏功能出现异常:",e); } } }, 0, 1000 / frameRate, TimeUnit.MILLISECONDS); @@ -281,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/test/java/com/example/demo/VideoRecorder.java b/src/test/java/com/example/demo/VideoRecorder.java index efc9bc1..db7be27 100644 --- a/src/test/java/com/example/demo/VideoRecorder.java +++ b/src/test/java/com/example/demo/VideoRecorder.java @@ -90,6 +90,84 @@ public class VideoRecorder { @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(); + 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 * 30); + // 等待任务执行完毕 + + } + public void recordSingleTest() throws AWTException, InterruptedException, FFmpegFrameRecorder.Exception { // screenTimer = new ScheduledThreadPoolExecutor(5); // 创建一个线程池 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); @@ -106,6 +184,13 @@ public class VideoRecorder { buildRecord(recorder); screenTimer.scheduleAtFixedRate(() -> { BufferedImage videoImg = robot.createScreenCapture(screenRect); + 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 { @@ -142,30 +227,34 @@ public class VideoRecorder { } // 线程睡眠5S 录制5S - Thread.sleep(1000 * 50); + Thread.sleep(1000 * 30); log.info("执行完任务"); isStop = true; - Thread.sleep(1000 * 100); + Thread.sleep(1000 * 30); // 等待任务执行完毕 } + + + + private FFmpegFrameRecorder buildRecord(FFmpegFrameRecorder recorder) throws FFmpegFrameRecorder.Exception { - // recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 13 - recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // 13 + 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.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); - recorder.setVideoOption("crf", "23"); // 2000 kb/s, 720P视频的合理比特率范围 recorder.setVideoBitrate(1000000); - recorder.setVideoOption("preset", "slow"); + recorder.setPixelFormat(0); // yuv420p = 0 recorder.start(); return recorder; } -- Gitee From 72493b95df2acdd19b9218d5ea1df85afe094d64 Mon Sep 17 00:00:00 2001 From: fanyufeng Date: Mon, 26 Feb 2024 14:52:13 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=E5=A4=84=E7=90=86=E5=B1=8F?= =?UTF-8?q?=E5=B9=95=E5=88=86=E8=BE=A8=E7=8E=87=E5=A4=A7=E5=B0=8F=E5=9B=A0?= =?UTF-8?q?=E7=BC=A9=E6=94=BE=E8=80=8C=E5=BD=B1=E5=93=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/demo/VideoRecorder.java | 86 +++---------------- 1 file changed, 11 insertions(+), 75 deletions(-) diff --git a/src/test/java/com/example/demo/VideoRecorder.java b/src/test/java/com/example/demo/VideoRecorder.java index db7be27..c4b0564 100644 --- a/src/test/java/com/example/demo/VideoRecorder.java +++ b/src/test/java/com/example/demo/VideoRecorder.java @@ -42,7 +42,7 @@ public class VideoRecorder { private ScheduledThreadPoolExecutor exec; private String fileName; private OpenCVFrameConverter.ToIplImage conveter; - private BufferedImage screenCapture; + // private BufferedImage screenCapture; private TargetDataLine line; private AudioFormat audioFormat; private DataLine.Info dataLineInfo; @@ -99,13 +99,16 @@ public class VideoRecorder { 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 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); @@ -160,81 +163,14 @@ public class VideoRecorder { } // 线程睡眠5S 录制5S - Thread.sleep(1000 * 30); + Thread.sleep(1000 * 10); log.info("执行完任务"); isStop = true; - Thread.sleep(1000 * 30); + Thread.sleep(1000 * 10); // 等待任务执行完毕 } - public void recordSingleTest() 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 screen : screens) { - Rectangle screenRect = screen.getDefaultConfiguration().getBounds(); - FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(fileName + i++ + ".mp4", - screenRect.width, screenRect.height, 0); - buildRecord(recorder); - screenTimer.scheduleAtFixedRate(() -> { - BufferedImage videoImg = robot.createScreenCapture(screenRect); - 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("开始录制屏幕"); - // 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) { - try { - log.info("录制线程池结束运行"); - recorder.stop(); - recorder.release(); - recorder.close(); - screenTimer.shutdown(); - } catch (Exception e) { - log.error("停止录屏功能出现异常:", e); - } - } - }, 0, 1000 / frameRate, TimeUnit.MILLISECONDS); - - } - - // 线程睡眠5S 录制5S - Thread.sleep(1000 * 30); - log.info("执行完任务"); - isStop = true; - Thread.sleep(1000 * 30); - // 等待任务执行完毕 - - } - + -- Gitee From dff9cdd21f5f8685d80064c195ec6f86ca150886 Mon Sep 17 00:00:00 2001 From: fanyufeng Date: Mon, 26 Feb 2024 15:06:24 +0800 Subject: [PATCH 5/5] =?UTF-8?q?style=20:=20=E5=88=A0=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E5=BF=85=E8=A6=81=E7=9A=84=E4=BB=A3=E7=A0=81=20&&=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- ...eoRecorder.java => VideoRecorderTest.java} | 48 ++----------------- 2 files changed, 8 insertions(+), 44 deletions(-) rename src/test/java/com/example/demo/{VideoRecorder.java => VideoRecorderTest.java} (89%) diff --git a/README.md b/README.md index f8d0eb6..9e25cec 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/src/test/java/com/example/demo/VideoRecorder.java b/src/test/java/com/example/demo/VideoRecorderTest.java similarity index 89% rename from src/test/java/com/example/demo/VideoRecorder.java rename to src/test/java/com/example/demo/VideoRecorderTest.java index c4b0564..1fafc72 100644 --- a/src/test/java/com/example/demo/VideoRecorder.java +++ b/src/test/java/com/example/demo/VideoRecorderTest.java @@ -1,14 +1,7 @@ package com.example.demo; -/** - * @author 王瑞 - * @description: TODO - * @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.Frame; @@ -23,12 +16,13 @@ import java.awt.image.BufferedImage; import java.util.concurrent.*; /** + * @author fanyufeng + * * 使用javacv进行录屏 */ - @Data @Slf4j -public class VideoRecorder { +public class VideoRecorderTest { //线程池 screenTimer private ScheduledThreadPoolExecutor screenTimer; private static boolean isStop = false; @@ -53,41 +47,13 @@ public class VideoRecorder { /*录制的频率*/ private int frameRate = 10; - - public VideoRecorder() { + public VideoRecorderTest() { } /** - * 停止 + * windows 多屏录制demo */ - public void stop() { - - isStop = true; - - } - - /** - * 暂停 - * - * @throws Exception - */ - public void pause() throws Exception { - screenTimer.shutdownNow(); - screenTimer = null; - if (isHaveDevice) { - exec.shutdownNow(); - exec = null; - line.stop(); - line.close(); - dataLineInfo = null; - audioFormat = null; - line = null; - } - pauseTime = System.currentTimeMillis(); - } - - @Test public void recordTest() throws AWTException, InterruptedException, FFmpegFrameRecorder.Exception { // screenTimer = new ScheduledThreadPoolExecutor(5); @@ -143,7 +109,6 @@ public class VideoRecorder { // screenCapture.flush(); // screenCapture = null; } - if (isStop) { try { log.info("录制线程池结束运行"); @@ -170,9 +135,6 @@ public class VideoRecorder { // 等待任务执行完毕 } - - - private FFmpegFrameRecorder buildRecord(FFmpegFrameRecorder recorder) throws FFmpegFrameRecorder.Exception { -- Gitee