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\\";// 获取视频FPSDouble 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 = 20return;}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,并在原有基础上做了优化