Java截取视频资料中的某一帧作为缩略图

最近项目中有一个需求,就是要实现视频资料的收藏功能,当时想了想,收藏记录实现并不是很难,但是想展现出视频的缩略图,就要想想其他办法了,所以就想到了截取视频资料中的某一帧作为缩略图,我没有选择截取第一帧,选择的是第五帧,因为第一帧可能没有内容。

基础知识
JavaCV:功能很强大,封装了很多很视频、图片相关的内容。

JavaCV是一款基于JavaCPP

调用方式(JNI的一层封装),由多种开源计算机视觉库组成的包装库,封装了包含FFmpegOpenCVtensorflow、caffe、tesseract、libdc1394、OpenKinect、videoInput和ARToolKitPlus等在内的计算机视觉领域的常用库和实用程序类。

JavaCV基于Apache License Version 2.0协议和GPLv2两种协议,

JavaCV支持Windows、Linux、MacOS,Android、IOS在内的Java平台上调用这些接口。


FFmpegFrameGrabber

FFmpegFrameGrabber可以理解为解码器,也可以理解为帧收集器,可以获取视频资料的各种详细信息,时长,宽高,帧等,很强大。


BufferedImage,ImageIO

BufferedImage类是Image的一个子类,是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中。

ImageIO提供read()和write()静态方法,读写照片

将图片加载到内存中

//需要是一个本地文件
 String imgPath = "‪C:\Users\Administrator\Videos\999.jpg";  
 BufferedImage image = ImageIO.read(new FileInputStream(imgPath));

将内存中的图片写到本地

BufferedImage bi=~某个值
File outputfile  = new File("save.png");
//参数 
// bi:要写入的RenderedImage 
// png:格式类型
// outputfile:要写入的OutputStream 
ImageIO.write(bi,"png",outputfile);  

MultipartFile

MultipartFile在上一篇文章中介绍过了。Java实例讲解文件上传与跨域问题

具体实现
引入依赖

本功能使用的Jar包是javacv,javacv-platform。因为这个包有150多M,很多依赖项都用不到,所以,将不需要的移除取出。

<!--start:视频获取某一帧的图片-->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.4.4</version>
    <exclusions>
        <exclusion>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacpp</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>flycapture</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>libdc1394</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>libfreenect</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>libfreenect2</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>librealsense</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>videoinput</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>opencv</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>tesseract</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>leptonica</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>flandmark</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>artoolkitplus</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.4.4</version>
    <exclusions>
        <exclusion>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>flycapture-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>libdc1394-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>libfreenect-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>libfreenect2-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>librealsense-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>videoinput-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>opencv-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>tesseract-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>leptonica-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>flandmark-platform</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>artoolkitplus-platform</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--end:视频获取某一帧的图片-->
Java代码
/**
 * 将视频文件帧处理并以“jpg”格式进行存储。
 * 依赖FrameToBufferedImage方法:将frame转换为bufferedImage对象
 * 参数可串本地文件,或者网络文件
 * @param videoFileName http://d-godone.dmsd.tech/goDone/M00/00/0A/wKg8O2D2mnqEMg7wAAAAALbl5Ys275.mp4
 */
public  String videoFramer(String videoFileName){
    //最后获取到的视频的图片的路径
    String videPicture="";
    //Frame对象
    Frame frame = null;
    //标识
    int flag = 0;
    try {
         /*
        获取视频文件
        */
        FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber( videoFileName);
        log.info("开始截取视频:");
//            av_register_all();//解决报错 avformat_open_input() error -138: Could not open input
//            avcodec_register_all();
//          当视频打不开时,会报错
        fFmpegFrameGrabber.start();
        //获取视频总帧数
        int ftp = fFmpegFrameGrabber.getLengthInFrames();
        log.info("时长 " + ftp / fFmpegFrameGrabber.getFrameRate() / 60);

        while (flag <= ftp) {
            //获得每一帧
            frame = fFmpegFrameGrabber.grabImage();
            /*
            对视频的第五帧进行处理
             */
            if (frame != null && flag==5) {

               //将文件转换
                BufferedImage bufferedImage = FrameToBufferedImage(frame);
                //将bufferedImage转换成MultipartFile--方便文件上传
                MultipartFile multipartFile = fileCase(bufferedImage);
                log.info("开始文件上传:");
                //文件上传--上传到FastDFS中,并返回URL
                String fileLoad = fileLoad(multipartFile);

                videPicture=fileLoad;
                log.info("文件上传成功{}",fileLoad);
                break;
            }
            flag++;
        }
        fFmpegFrameGrabber.stop();
        fFmpegFrameGrabber.close();
    } catch (Exception E) {
        E.printStackTrace();
    }
    return videPicture;
}
两个文件类型转换的方法Frame->BufferedImage->MultipartFile
/**
 * 文件转换,将Frame转换成BufferedImage
 * @param frame Frame
 * @return
 */
public static BufferedImage FrameToBufferedImage(Frame frame) {
    //创建BufferedImage对象
    Java2DFrameConverter converter = new Java2DFrameConverter();
    BufferedImage bufferedImage = converter.getBufferedImage(frame);
    return bufferedImage;
}


/**
 * 文件转换将BufferedImage转换成MultipartFile:为了文件上传
 * @param image
 * @return
 */
public static MultipartFile fileCase(BufferedImage image){
    //得到BufferedImage对象
   // BufferedImage bufferedImage = JoinTwoImage.testEncode(200, 200, url);
    MultipartFile multipartFile= null;
    try {
        //创建一个ByteArrayOutputStream
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        //把BufferedImage写入ByteArrayOutputStream
        ImageIO.write(image, "jpg", os);
        //ByteArrayOutputStream转成InputStream
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        //InputStream转成MultipartFile
        multipartFile =new MockMultipartFile("file", "file.jpg", "text/plain", input);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return multipartFile;
}
 
收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据