java实现视频抽帧以及获取其他视频信息

java实现视频抽帧以及获取其他视频信息

1.在pom.xml文件中导入jar包

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.4.3</version>
</dependency>

<dependency>
    <groupId>org.bytedeco.javacpp-presets</groupId>
    <artifactId>ffmpeg-platform</artifactId>
    <version>4.0.2-1.4.3</version>
</dependency>

2.创建工具类FetchVideoFrameUtil,复制以下代码

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


/**
 * Created with IDEA
 * 视频取帧,可设置间隔秒数或获取所有帧数
 *
 * @Author shunzi
 * @Date 2023/08/16 14:38:12
 * @Description
 * @Version 1.0
 */
@Slf4j
public class FetchVideoFrameUtil {

    // 主函数
    public static void main(String[] args){
        try {
            //批量处理,视频所在文件夹
            String videoPath = "C:\\Users\\17386\\Desktop\\video\\normal video.mp4";
            //输出图片文件夹
            String picPath = "C:\\Users\\17386\\Desktop\\video-image3\\";
            // 获取视频FPS
            Double videoFrameRate = FetchVideoFrameUtil.getVideoFrameRate(new File(videoPath));
            log.info("视频频率:{}", videoFrameRate);
            // 根据FPS,动态计算抽帧速率。示例为:每秒取一帧
            BigDecimal frameNumber = BigDecimal.valueOf(videoFrameRate);
            BigDecimal frameDecimal = frameNumber.setScale(0, RoundingMode.HALF_UP);
            // TODO 这里来更改抽帧速率,通过乘法运算来控制。比如:控制抽帧频率为2秒一帧,int second = 2 * frameDecimal.intValue()。以此类推
            int second = frameDecimal.intValue();
            log.info("抽帧频率:{}", second);
            // 视频时长
            log.info("视频总时长:{}", FetchVideoFrameUtil.getVideoTime(new File(videoPath)));
            // 视频总帧数
            log.info("视频总共帧数:{}", FetchVideoFrameUtil.getVideoFrameTotalLength(new File(videoPath)));
            // 开始视频取帧流程
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("开始视频取帧流程=====开始时间" + sdf.format(new Date()));
            List<File> files = FetchVideoFrameUtil.fetchPic(new File(videoPath), picPath, second);
            System.out.println("结束视频取帧流程=====结束时间" + sdf.format(new Date()));
            log.info("抽取的图片集合:{}", JSONObject.toJSONString(files));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取指定视频的帧并保存为图片至指定目录
     * @param file  源视频文件
     * @param picPath  截取帧的图片存放路径
     * @throws Exception
     */
    public static java.util.List<File> fetchPic(File file, String picPath, int second) throws Exception{
        java.util.List<File> list = Lists.newArrayList();
        FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file); // 获取视频文件

        int length = FetchVideoFrameUtil.getVideoFrameTotalLength(file);
        ff.start(); // 调用视频文件播放
        int i = 0; // 图片帧数,如需跳过前几秒,则在下方过滤即可
        org.bytedeco.javacv.Frame frame = null;
        int count = 0;
        while (i < length) {
            frame = ff.grabImage(); // 获取该帧图片流
            System.out.print(i + ",");
            if(frame!=null && frame.image!=null) {
                System.out.println(i);
                writeToFile(frame, picPath, count,second,list); // 生成帧图片
                count++;
            }
            i++;
        }
        ff.stop();
        return list;
    }

    /**
     *
     * @param frame // 视频文件对象
     * @param picPath // 图片存放路径
     * @param count // 当前取到第几帧
     * @param second // 每隔多少帧取一张,一般高清视频每秒 20-24 帧,根据情况配置,如果全部提取,则将second设为 0 即可
     * @param list // 返回文件结果
     */
    public static void writeToFile(org.bytedeco.javacv.Frame frame, String picPath, int count, int second, java.util.List<File> list){
        if (second == 0) {
            // 跳过间隔取帧判断
        } else if (count % second != 0){ // 提取倍数,如每秒取一张,则: second = 20
            return;
        }
        File targetFile = new File(picPath + count + ".jpg");
        System.out.println("创建了文件:" + picPath + count + ".jpg");
        list.add(targetFile);
        String imgSuffix = "jpg";

        Java2DFrameConverter converter =new Java2DFrameConverter();
        BufferedImage srcBi =converter.getBufferedImage(frame);
        int owidth = srcBi.getWidth();
        int oheight = srcBi.getHeight();
        // 对截取的帧进行等比例缩放
        int width = 800;
        int height = (int) (((double) width / owidth) * oheight);
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        bi.getGraphics().drawImage(srcBi.getScaledInstance(width, height, Image.SCALE_SMOOTH),0, 0, null);
        try {
            ImageIO.write(bi, imgSuffix, targetFile);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取视频时长,单位为秒
     * @param file
     * @return 时长(s)
     */
    public static Long getVideoTime(File file){
        Long times = 0L;
        try {
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
            ff.start();
            times = ff.getLengthInTime()/(1000*1000);
            ff.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return times;
    }

    /**
     * 获取视频帧率,单位FPS
     * @return
     */
    public static Double getVideoFrameRate(File file) {
        double frameRate = 0.0;
        try {
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
            ff.start();
            frameRate = ff.getVideoFrameRate();
            ff.stop();
        } catch (FrameGrabber.Exception e) {
            throw new RuntimeException(e);
        }
        return frameRate;
    }

    /**
     * 获取视频真实格式
     * @param file
     * @return
     */
    public static String getVideoRealFormat(File file){
        String videoFormat = "";
        try {
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
            ff.start();
            videoFormat = ff.getFormat();
            ff.stop();
        } catch (FrameGrabber.Exception e) {
            throw new RuntimeException(e);
        }
        return videoFormat;
    }

    /**
     * 获取视频总帧数长度
     * @return
     */
    public static int getVideoFrameTotalLength(File file) {
        int frameCount = 0;
        try {
            FFmpegFrameGrabber ff = new FFmpegFrameGrabber(file);
            ff.start();
            org.bytedeco.javacv.Frame frame;
            while ((frame = ff.grabImage()) != null) {
                frameCount++;
            }
            ff.stop();
        } catch (FrameGrabber.Exception e) {
            throw new RuntimeException(e);
        }
        return frameCount;
    }
}

文章引用出处:https://cloud.tencent.com/developer/article/1655887,并在原有基础上做了优化

相关推荐
泰山小张只吃荷园5 分钟前
期末Python复习-输入输出
java·前端·spring boot·python·spring cloud·docker·容器
Mr_Xuhhh8 分钟前
程序地址空间
android·java·开发语言·数据库
YSRM13 分钟前
异或-java-leetcode
java·算法·leetcode
大明湖的狗凯.17 分钟前
MySQL 中的乐观锁与悲观锁
java·数据库·mysql
z2023050822 分钟前
linux之调度管理(13)- wake affine 唤醒特性
java·开发语言
AI人H哥会Java23 分钟前
【JAVA】Java高级:Java网络编程——TCP/IP与UDP协议基础
java·开发语言
robin_suli1 小时前
Java多线程八股(三)一>多线程环境使用哈希表和ArrayList
java·开发语言·多线程·哈希表
NiNg_1_2341 小时前
Java中的多线程
java·开发语言
丁总学Java1 小时前
nohup java -jar supporterSys.jar --spring.profiles.active=prod &
java·spring·jar
呆呆小雅1 小时前
C# 结构体
android·java·c#