用Python下载B站视频?1行命令搞定,悄悄用(python b站视频下载)
571
2022-07-26
目录概述javacv 介绍引入 javacv读取视频信息创建 VideoInfo 类使用 FFmpegFrameGrabber 读取视频信息截图
概述
最近在对之前写的一个 Spring Boot 的视频网站项目做功能完善,需要利用 FFmpeg 实现读取视频信息和自动截图的功能,查阅资料后发现网上这部分的内容非常少,于是就有了这篇文章。
视频网站项目地址
github
码云
本文将介绍如何利用Javacv实现在视频网站中常见的读取视频信息和自动获取封面图的功能。
javacv 介绍
javacv可以帮助我们在java中很方便的使用 OpenCV 以及 FFmpeg 相关的功能接口
项目地址
引入 javacv
读取视频信息
创建 VideoInfo 类
package com.buguagaoshu.porntube.vo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombqPjTbPFok.Setter;
/**
* @author Pu Zhiwei {@literal puzhiweipuzhiwei@foxmail.com}
* create 2022-06-06 19:15
*/
@Getter
@Setter
public class VideoInfo {
/**
* 总帧数
**/
private int lengthInFrames;
/**
* 帧率
**/
private double frameRate;
/**
* 时长
**/
private double duration;
/**
* 视频编码
*/
private String videoCode;
/**
* 音频编码
*/
private String audioCode;
private int width;
private int height;
private int audioChannel;
private String md5;
/**
* 音频采样率
*/
private Integer sampleRate;
public String tojson() {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(this);
} catch (Exception e) {
return "";
}
}
}
使用 FFmpegFrameGrabber 读取视频信息
public static VideoInfo getVideoInfo(File file) {
VideoInfo videoInfo = new VideoInfo();
FFmpegFrameGrabber grabber = null;
try {
grabber = new FFmpegFrameGrabber(file);
// 启动 FFmpeg
grabber.start();
// 读取视频帧数
videoInfo.setLengthInFrames(grabber.getLengthInVideoFrames());
// 读取视频帧率
videoInfo.setFrameRate(grabber.getVideoFrameRate());
// 读取视频秒数
videoInfo.setDuration(grabber.getLengthInTime() / 1000000.00);
// 读取视频宽度
videoInfo.setWidth(grabber.getImageWidth());
// 读取视频高度
videoInfo.setHeight(grabber.getImageHeight());
videoInfo.setAudioChannel(grabber.getAudioChannels());
videoInfo.setVideoCode(grabber.getVideoCodecName());
videoInfo.setAudioCode(grabber.getAudiqPjTbPFoCodecName());
// String md5 = MD5Util.getMD5ByInputStream(new FileInputStream(file));
videoInfo.setSampleRate(grabber.getSampleRate());
return videoInfo;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (grabber != null) {
// 此处代码非常重要,如果没有,可能造成 FFmpeg 无法关闭
grabber.stop();
grabber.release();
}
} catch (FFmpegFrameGrabber.Exception e) {
log.error("getVideoInfo grabber.release failed 获取文件信息失败:{}", e.getMessage());
}
}
}
截图
读取信息没有什么难度,但是在对视频截图的过程中,出现了一些问题,在我查找截图实现的代码时,大多数的代码都是这么写的
/**
* 获取视频缩略图
* @param filePath:视频路径
* @param mod:视频长度/mod获取第几帧
* @throws Exception
*/
public static String randomGrabberFFmpegImage(String filePath, int mod) {
String targetFilePath = "";
try{
FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
ff.start();
//图片位置是否正确
String rotate = ff.getVideoMetadata(ROTATE);
//获取帧数
int ffLength = ff.getLengthInFrames();
Frame f;
int i = 0;
//设置截取帧数
int index = ffLength / mod;
while (i < ffLength) {
f = ff.grabImage();
if(i == index){
if (null != rotate && rotate.length() > 1) {
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
IplImage src = converter.convert(f);
f = converter.convert(rotate(src, Integer.parseInt(rotate)));
}
targetFilePath = getImagePath(filePath, i);
doExecuteFrame(f, targetFilePath);
break;
}
i++;
}
ff.stop();
}catch (Exception e){
log.error("获取视频缩略图异常:" + e.getMessage());
}
return targetFilePath;
}
这样写本身没有什么问题,但是在获取需要截取帧数的部分,使用的是通过循环来一帧一帧的判断,这样在视频较短的时候没有什么问题,但是如果视频较长,就会出现严重的性能问题。
while (i < ffLength) {
f = ff.grabImage();
if(i == index){
......
break;
}
i++;
}
FFmpeg 的命令行参数有一个 -ss 的参数,使用 -ss 可以快速的帮助我们跳到视频的指定位置,完成操作,不用一帧一帧的判断。
所以现在的问题就是如何在 javacv 中实现 -ss 参数
我在 javacv 的 GitHub Issues 中发现了这个操作,即使用 setTimestamp() 方法,使用 setTimestamp() 方法可以使 FFmpeg 跳转到指定时间,完成截图,于是,最后的截图代码就变成了这样
/**
* 随机获取视频截图
* @param videFile 视频文件
* @param count 输出截图数量
* @return 截图列表
* */
public static List
FFmpegFrameGrabber grabber = null;
String path = FileTypeEnum.filePath();
try {
List
grabber = new FFmpegFrameGrabber(videFile);
grabber.start();
// 获取视频总帧数
// int lengthInVideoFrames = grabber.getLengthInVideoFrames();
// 获取视频时长, / 1000000 将单位转换为秒
long delayedTime = grabber.getLengthInTime() / 1000000;
Random random = new Random();
for (int i = 0; i < count; i++) {
// 跳转到响应时间
grabber.setTimestamp((random.nextInt((int)delayedTime - 1) + 1) * 1000000L);
Frame f = grabber.grabImage();
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bi = converter.getBufferedImage(f);
String imageName = FileTypeEnum.newFilename(SUFFIX);
File out = Paths.get(path, imageName).toFile();
ImageIO.write(bi, "jpg", out);
FileTableEntity fileTable = FileUtils.createFileTableEntity(imageName, SUFFIX, path, f.image.length, "系统生成截图", userId, FileTypeEnum.VIDEO_PHOTO.getCode());
images.add(fileTable);
}
return images;
} catch (Exception e) {
return null;
} finally {
try {
if (grabber != null) {
grabber.stop();
grabber.release();
}
} catch (FFmpegFrameGrabber.Exception e) {
log.error("getVideoInfo grabber.release failed 获取文件信息失败:{}", e.getMessage());
}
}
}
这样我们就能快速的实现截图了。
以上就是JavaCV实现读取视频信息及自动截取封面图详解的详细内容,更多关于JavaCV读取视频信息 自动截图的资料请关注我们其它相关文章!
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~