截图录屏工具——图片组转视频流

本文介绍使用Java实现屏幕录制的方法,包括通过Robot组件抓取屏幕图像,并利用Jim2Mov库将一系列JPG图片转换为AVI视频的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们将我们的项目拆分成两个部分,一是屏幕截图部分,二是jpg图片转AVI部分,在之后我会发出通过javaCV进行操作
不过在这个之前,我们要先安装JMF,很多博客中,总是不要求按照JMF导致不能运行,JMF是Java媒体框架,地址
还需要Jim2mov.jar
Windows直接安装即可,具体可以参考博客:JMF下载和安装
这里我测试,需要将JMF下的.jar导入到项目中
所用到的资源:http://download.youkuaiyun.com/download/whb3299065/10202791

屏幕抓取

我们通过Robot组件,来进行屏幕抓取
首先我们先看看如何捕捉一张图像:为了可以让该方法直接运行我添加一些参数

    Robot robot = new Robot();
    //尺寸指定为全屏
    Rectangle rectangle=new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    public void capturOneImg(/**Rectangle rectangle*/) {
        try {
            BufferedImage image = robot.createScreenCapture(rectangle);//捕获制定屏幕矩形区域
            //这个功能是对图片进行压缩并保持,调用thumbnailator工具对图片进行处理
            Thumbnails.of(image).scale(0.8f).outputQuality(0.5f)
                .toFile("D:\\imgs\\图片名称.jpg");
        }  catch (IOException e) {
            e.printStackTrace();
        }
    }

这样就可以将屏幕截取下来,保存为一张图片了

视频转换

首先要注意的一点就是tip组一定是有序的,不然合成的视频一定会很混乱,排序过程我会在代码中展示,这里我先假设File[] jpgs是有序的。
File[] jpgs=……;
然后我们要设置视频的各种信息

// 生成视频的名称
DefaultMovieInfoProvider dmip = new DefaultMovieInfoProvider(aviFileName);
// 设置每秒帧数
dmip.setFPS(fps>0?fps:3); // 如果未设置,默认为3
// 设置总帧数
dmip.setNumberOfFrames(jpgs.length);
// 设置视频宽和高(最好与图片宽高保持一直)
dmip.setMWidth(mWidth>0?mWidth:1440); // 如果未设置,默认为1440
dmip.setMHeight(mHeight>0?mHeight:860); // 如果未设置,默认为860

然后就是直接创建一个转换对象,传入一个入伙获取图片的匿名对象,最后调用saveMovie方法,视频就保存成功了,注意的是,这个位置非常耗时,而且转成AVI后比图片组占用的空间都大

new Jim2Mov(new ImageProvider() {
    public byte[] getImage(int frame) {
        try {
            // 设置压缩比
            return MovieUtils.convertImageToJPEG((jpgs[frame]), 1.0f);
        } catch (IOException e) {
            System.err.println(e);
        }
        return null;
    }   
}, dmip, null).saveMovie(MovieInfoProvider.TYPE_AVI_MJPEG);

看懂了这个方法,那么我们就可以将这个类全部展示出来了,这里需要注意的是,Config是我自己定义的一个不完善的配置对象,这里建议重写一下,我会把我的config放到最后

import com.sun.image.codec.jpeg.JPEGCodec;
import net.coobird.thumbnailator.Thumbnails;
import top.whbweb.screen.recording.config.Config;
import top.whbweb.screen.recording.img2void.PicToAviUtil;
import top.whbweb.screen.recording.util.UUID;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
//录屏工具类
public class ScreenRecording {

    Config config;
    Robot robot;
    public Thread thread;
    private long sleepTime;
    private boolean recordSwitch = true;
    private String recordName;
    public ScreenRecording() throws AWTException {
        robot = new Robot();
        init();
    }

    public void start() {
        recordSwitch=true;
        recordName= UUID.getUUID()+"\\";
        new File(config.basePath+recordName).mkdirs();
        thread.start();
    }

    public void pause() {
        try {
            thread.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void stop() {
        int width= (int) config.getRectangle().getWidth();
        int height= (int) config.getRectangle().getHeight();
        recordSwitch=false;
        PicToAviUtil.convertPicToAvi(config.basePath+recordName+"\\",
                config.basePath+recordName+".avi",
                config.frame,width,height
                );
    }

    public void capturOneImg(Rectangle rectangle) {
        try {
            BufferedImage image = robot.createScreenCapture(rectangle);//捕获制定屏幕矩形区域
            Thumbnails.of(image).scale(0.8f).outputQuality(0.5f).toFile(config.basePath+recordName + UUID.getUUID() + ".jpg");
        }  catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Config getConfig() {
        return config;
    }

    public void setConfig(Config config) {
        this.config = config;
        sleepTime = 1000 / config.getFrame();
    }

    public void init() {
        thread = new Thread() {
            @Override public void run() {
                while (recordSwitch) {
                    try {
                        capturOneImg(config.getRectangle());
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
    }
}
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;

import org.jim2mov.core.DefaultMovieInfoProvider;
import org.jim2mov.core.ImageProvider;
import org.jim2mov.core.Jim2Mov;
import org.jim2mov.core.MovieInfoProvider;
import org.jim2mov.core.MovieSaveException;
import org.jim2mov.utils.MovieUtils;

/**
 * 图片与视频转换工具类
 *
 * @author Administrator
 */
public class PicToAviUtil {

    /**
     * 将图片转换成视频
     * @param jpgDirPath jpg图片文件夹绝对路径
     * @param aviFileName 生成的avi视频文件名
     * @param fps 每秒帧数
     * @param mWidth 视频的宽度
     * @param mHeight 视频的高度
     * @throws Exception
     */
    public static void convertPicToAvi(String jpgDirPath, String aviFileName, int fps, int mWidth, int mHeight) {
        // jpgs目录放置jpg图片,图片文件名为(1.jpg,2.jpg...)
        final File[] jpgs = new File(jpgDirPath).listFiles();
        if(jpgs==null || jpgs.length==0){
            return;
        }

        // 对文件名进行排序(本示例假定文件名中的数字越小,生成视频的帧数越靠前)
        Arrays.sort(jpgs, new Comparator<File>() {
            public int compare(File file1, File file2) {
                String numberName1 = file1.getName().replace(".jpg", "");
                String numberName2 = file2.getName().replace(".jpg", "");
                return numberName1.compareTo(numberName2);
            }
        });

        // 生成视频的名称
        DefaultMovieInfoProvider dmip = new DefaultMovieInfoProvider(aviFileName);
        // 设置每秒帧数
        dmip.setFPS(fps>0?fps:3); // 如果未设置,默认为3
        // 设置总帧数
        dmip.setNumberOfFrames(jpgs.length);
        // 设置视频宽和高(最好与图片宽高保持一直)
        dmip.setMWidth(mWidth>0?mWidth:1440); // 如果未设置,默认为1440
        dmip.setMHeight(mHeight>0?mHeight:860); // 如果未设置,默认为860

        try {
            new Jim2Mov(new ImageProvider() {
                public byte[] getImage(int frame) {
                    try {
                        // 设置压缩比
                        return MovieUtils.convertImageToJPEG((jpgs[frame]), 1.0f);
                    } catch (IOException e) {
                        System.err.println(e);
                    }
                    return null;
                }
            }, dmip, null).saveMovie(MovieInfoProvider.TYPE_AVI_MJPEG);
        } catch (MovieSaveException e) {
            e.printStackTrace();
        }

        System.out.println("create avi success.");
    }

    /**
     * main
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        String jpgDirPath = "D:\\date\\file\\playScreen\\capture\\20180111150516449285223899794475\\"; // jpg文件夹路径
        String aviFileName = "file:///D:/date/file/playScreen/capture/test.avi"; // 生成的avi视频文件名(生成路径为本工程)
        int fps = 5; // 每秒播放的帧数
        int mWidth = 1440; // 视频的宽度
        int mHeight = 860; // 视频的高度
        PicToAviUtil.convertPicToAvi(jpgDirPath, aviFileName, fps, mWidth, mHeight);
    }

}

测试类:


import top.whbweb.screen.recording.config.Config;

import java.awt.*;

public class ScreenRecordTest {

    public static void main(String[] args) throws AWTException, InterruptedException {
        new ScreenRecordTest().test();

    }
    public void test() throws AWTException, InterruptedException {
        ScreenRecording screenRecordTest = new ScreenRecording();
        Config config=new Config();
        config.setRectangle(config.getScreenFull());
        screenRecordTest.setConfig(config);
        screenRecordTest.start();
        //wait(1000*20);
        screenRecordTest.stop();
    }
}

配置文件


import java.awt.*;

public class Config {
    public static String SCREEN_FULL="FULL_SCREEN";
    public String basePath="D:\\date\\file\\playScreen\\capture\\";
    public int frame=45;
    public Rectangle rectangle;

    public Rectangle getScreenFull() {
        return new  Rectangle(Toolkit.getDefaultToolkit().getScreenSize());//可以指定捕获屏幕区域
    }


    public String getBasePath() {
        return basePath;
    }

    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }

    public int getFrame() {
        return frame;
    }

    public void setFrame(int frame) {
        this.frame = frame;
    }

    public Rectangle getRectangle() {
        if (rectangle==null)
            return getScreenFull();
        return rectangle;
    }

    public void setRectangle(Rectangle rectangle) {
        this.rectangle = rectangle;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值