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,并在原有基础上做了优化

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenCV是一个流行的计算机视觉库,它提供了许多有用的功能,其中包括处理视频和图像。Java OpenCV是OpenCV的Java绑定,它使Java开发人员可以直接使用OpenCV提供的功能。 视频帧是指从视频源中取一系列图像帧的过程。在Java OpenCV中,要实现视频帧需要使用VideoCapture类来读取视频源,并使用Imgcodecs类来保存每一帧样生成的图像。具体步骤如下: 1. 初始化VideoCapture对象并将其绑定到视频源: VideoCapture cap = new VideoCapture("input_video.mp4"); 2. 检查VideoCapture对象是否已成功打开视频源: if (!cap.isOpened()) { System.out.println("Error opening video file."); return; } 3. 循环遍历每一帧,使用read()方法读取并检查是否成功读取: Mat frame = new Mat(); while (cap.read(frame)) { if (frame.empty()) { System.out.println("Error reading frame."); break; } 4. 为每一帧样生成一个输出文件名: String outputFilename = "frame_" + cap.get(CAP_PROP_POS_FRAMES) + ".jpg"; 5. 使用Imgcodecs类的imwrite()方法保存每一帧的图像: Imgcodecs.imwrite(outputFilename, frame); 6. 释放VideoCapture对象及其关联的内存: cap.release(); 这样就可以实现视频源中取一系列图像帧的操作。Java OpenCV支持大多数视频格式,包括MP4,AVI和MOV。根据需求,还可以调整帧的频率(例如每秒1帧),并使用其他OpenCV函数对样生成的图像进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值