【JAVA】JavaCV实现简单录屏功能

最近接触的Java桌面程序需要一个录屏功能,然后就翻到了JavaCV,跟着教程大概写了一个,其中用上了之前用来截屏的Robot类

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

首先需要声明并初始化各种属性


    private ScheduledThreadPoolExecutor screenTimer;
    private Rectangle rectangle;
    private FFmpegFrameRecorder recorder;
    private Robot robot;
    private OpenCVFrameConverter.ToIplImage conveter;
    private BufferedImage screenCapture;
    private ScheduledThreadPoolExecutor exec;
    private TargetDataLine line;
    private AudioFormat audioFormat;
    private DataLine.Info dataLineInfo;
    private boolean isHaveDevice;
    private String fileName;
    private long startTime = 0;
    private long videoTS = 0;
    private long pauseTime = 0;
    private double frameRate = 5;
    
    //构造器
    public VideoRecorder(String fileName, boolean isHaveDevice) {
        init(fileName, isHaveDevice);
    }

void init(String fileName, boolean isHaveDevice) {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        rectangle = new Rectangle(screenSize.width, screenSize.height);
        recorder = new FFmpegFrameRecorder(fileName + ".mp4", screenSize.width, screenSize.height);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        logger.info("设置视频格式:h264");
        recorder.setFormat("mp4");
        recorder.setSampleRate(44100);
        recorder.setFrameRate(frameRate);

        recorder.setVideoQuality(0);
        recorder.setVideoOption("crf", "23");
        recorder.setVideoBitrate(1000000);
        recorder.setVideoOption("preset", "slow");
        recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
        recorder.setAudioChannels(2);
        recorder.setAudioOption("crf", "0");
        recorder.setAudioQuality(0);
//        recorder.setAudioCodec(avcodec.AV_CODEC_ID_IMC);
        try {
            robot = new Robot();
        } catch (AWTException e) {
            logger.error("AWTException : ", e);
        }
        try {
            recorder.start();
        } catch (Exception e) {
            logger.error(" 录制视频初始化异常 : ", e);
        } catch (Error error) {
            logger.error("录制视频初始化错误 : ", error);
        }
        conveter = new OpenCVFrameConverter.ToIplImage();
        this.isHaveDevice = isHaveDevice;
        this.fileName = fileName;
    }

开始录制

    public void start() {

        logger.info("录屏开始!start");
        if (startTime == 0) {
            startTime = System.currentTimeMillis();
        }
        if (pauseTime == 0) {
            pauseTime = System.currentTimeMillis();
        }

        if (isHaveDevice) {
            new Thread(() -> caputre()).start();
        }
        screenTimer = new ScheduledThreadPoolExecutor(1);
        screenTimer.scheduleAtFixedRate(() -> {
            try {
                screenCapture = robot.createScreenCapture(rectangle);
                String name = fileName + ".JPEG";
                File f = new File(name);
                try {
                    ImageIO.write(screenCapture, "JPEG", f);
                } catch (IOException e) {
                    logger.error("写文件时发生io异常 : ", e);
                }
                IplImage image = cvLoadImage(name);
                videoTS = 1000 * (System.currentTimeMillis() - startTime - (System.currentTimeMillis() - pauseTime));
                if (videoTS > recorder.getTimestamp()) {
                    recorder.setTimestamp(videoTS);
                }
                recorder.record(conveter.convert(image));
                f.delete();
                System.gc();
            } catch (Exception ex) {
                logger.error("录屏线程异常 : ", ex);
                MessageResponseHandler.uploadErrorInfo("录屏线程异常",ex);
            }
        }, (int) (1000 / frameRate), (int) (1000 / frameRate), TimeUnit.MILLISECONDS);
    }

音频录制新线程

    private void caputre() {
        audioFormat = new AudioFormat(44100.0F, 16, 2, true, false);
        dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
        try {
            line = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
            line.open(audioFormat);
        } catch (LineUnavailableException e1) {
            logger.error("准备录制音频时发生异常 : ", e1);
            MessageResponseHandler.uploadErrorInfo("准备录制音频时发生异常",e1);
        }
        line.start();

        int sampleRate = (int) audioFormat.getSampleRate();
        int numChannels = audioFormat.getChannels();

        int audioBufferSize = sampleRate * numChannels;
        byte[] audioBytes = new byte[audioBufferSize];

        exec = new ScheduledThreadPoolExecutor(1);
        exec.scheduleAtFixedRate(() -> {
            try {
                int nBytesRead = line.read(audioBytes, 0, line.available());
                int nSamplesRead = nBytesRead / 2;
                short[] samples = new short[nSamplesRead];

                ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);
                ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);

                recorder.recordSamples(sampleRate, numChannels, sBuff);
                System.gc();
            } catch (Exception e) {
                logger.error("录制音频时发生异常 : ", e);
                MessageResponseHandler.uploadErrorInfo("录制音频时发生异常",e);
            }
        }, (int) (1000 / frameRate), (int) (1000 / frameRate), TimeUnit.MILLISECONDS);
    }

释放资源

    public void stop() {
        if (null != screenTimer) {
            screenTimer.shutdownNow();
        }
        try {
            recorder.stop();
            recorder.release();
            recorder.close();
            System.out.println("录屏结束!");
            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) {
            logger.error("录屏结束时发生异常 : ", e);
            MessageResponseHandler.uploadErrorInfo("录屏结束时发生异常",e);
        }
    }

你可能感兴趣的:(Java)