Java视频按秒截取帧
1. Java视频按秒截取帧工具类
具体方法都在工具类中,可以文件地址,可以按照参数传递,
基本逻辑就是获取文件下载地址,将文件类型进行转换,然后传入javacv进行读取流操作。
具体场景需要根据工具类具体改造一下,但是基本原理是不变的。
<!--视频流-->
<!-- https://mvnrepository.com/artifact/com.github.vip-zpf/jave -->
<dependency>
<groupId>com.github.vip-zpf</groupId>
<artifactId>jave</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.github.vip-zpf</groupId>
<artifactId>jave</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.4-1.5.6</version>
</dependency>
package com.wondertek.util;
import com.wondertek.util.img.ConvertToMultipartFile;
import com.wondertek.web.fastdfs.DRFdfsUpAndDowService;
import it.sauronsoftware.jave.Encoder;
import it.sauronsoftware.jave.EncoderException;
import it.sauronsoftware.jave.MultimediaInfo;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xxx
*/
@Component
@Slf4j
public class VideoUtil {
private static DRFdfsUpAndDowService drFdfsUpAndDowService;
@Autowired
private DRFdfsUpAndDowService remoteDrFdfsUpAndDowService;
/**
* 获取视频帧数
*
* @param file
* @return
*/
public static Double getVideoFrameRate(MultipartFile file) {
try {
FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file.getInputStream()); // 获取视频文件
frameGrabber.start();
double frameRate = frameGrabber.getFrameRate();
// System.out.println("视频帧数:"+frameGrabber.getFrameRate()); // 视频帧数
// System.out.println("时长为:"+frameGrabber.getLengthInTime() / (1000 * 1000)); // 时长
frameGrabber.close();
return frameRate;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 根据读取到的视频文件,获取视频中的每一帧图片
*
* @param video 视频文件
* http://192.168.0.107:9087/datago/detectsysfiles/204/createFile/frameFile/001/frameFile001.mp4
* @param frameFilePath 图片的保存路径
* E:/detectsysfiles/204/createFile/frameFile/001/
* @param picPath 图像访问路径
* http://192.168.0.107:9087/datago/detectsysfiles/204/createFile/frameFile/001/
*/
public static Map<String, Object> getVideoPic(String frameFilePath, File video, String picPath) {
//1.根据一个视频文件,创建一个按照视频中每一帧进行抓取图片的抓取对象
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(video);
Map<String, Object> strMap = new HashMap<>();
List<String> strList = new ArrayList<>();
try {
ff.start();
//抓每一帧图片
//2.先知道这个视频一共有多少帧
int length = ff.getLengthInFrames();
//3.读取视频中每一帧图片
Frame frame = null;
for (int i = 1; i < length; i++) {
frame = ff.grabFrame();
if (frame.image == null) {
continue;
}
//将获取的帧,存储为图片
Java2DFrameConverter converter = new Java2DFrameConverter();//创建一个帧-->图片的转换器
BufferedImage image = converter.getBufferedImage(frame);//转换
String img = picPath + i + ".png";
File picFile = new File(img);
//将图片保存到目标文件中
ImageIO.write(image, "png", picFile);
strList.add(frameFilePath + "/" + i + ".png");
}
strMap.put("height", ff.getImageHeight());//视频高度
strMap.put("width", ff.getImageWidth());//视频宽度
strMap.put("frame", ff.getFrameRate());//帧率
strMap.put("imgPath", strList);//每一帧图像数据
ff.stop();
} catch (Exception e) {
e.printStackTrace();
}
return strMap;
}
/**
* 获取视频时长
*
* @param multipartFile
* @return
* @throws EncoderException
*/
public static int queryVideoDuration(MultipartFile multipartFile) throws EncoderException {
//机算视频时长
File dfile = null;
try {
dfile = File.createTempFile("prefix", "_" + multipartFile.getOriginalFilename());
multipartFile.transferTo(dfile);
} catch (IOException e) {
e.printStackTrace();
}
// 获取视频时长
Encoder encoder = new Encoder();
MultimediaInfo m = encoder.getInfo(dfile);
long ls = m.getDuration() / 1000;
int hour = (int) (ls / 3600);
int minute = (int) (ls % 3600) / 60;
int second = (int) (ls - hour * 3600 - minute * 60);
//删除临时文件
dfile.delete();
return second;
}
public static void approvalFile(MultipartFile filecontent, String path) {
OutputStream os = null;
InputStream inputStream = null;
String fileName = null;
try {
inputStream = filecontent.getInputStream();
fileName = filecontent.getOriginalFilename();
} catch (IOException e) {
e.printStackTrace();
}
try {
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流保存到本地文件
File tempFile = new File(path);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
// 开始读取
while ((len = inputStream.read(bs)) != -1) {
os.write(bs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 完毕,关闭所有链接
try {
os.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static BufferedImage rotate(BufferedImage src, int angel) {
int src_width = src.getWidth(null);
int src_height = src.getHeight(null);
int type = src.getColorModel().getTransparency();
Rectangle rect_des = calcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel);
BufferedImage bi = new BufferedImage(rect_des.width, rect_des.height, type);
Graphics2D g2 = bi.createGraphics();
g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);
g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);
g2.drawImage(src, 0, 0, null);
g2.dispose();
return bi;
}
private static Rectangle calcRotatedSize(Rectangle src, int angel) {
if (angel >= 90) {
if (angel / 90 % 2 == 1) {
int temp = src.height;
src.height = src.width;
src.width = temp;
}
angel = angel % 90;
}
double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
double angel_dalta_width = Math.atan((double) src.height / src.width);
double angel_dalta_height = Math.atan((double) src.width / src.height);
int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width));
int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height));
int des_width = src.width + len_dalta_width * 2;
int des_height = src.height + len_dalta_height * 2;
return new Rectangle(new Dimension(des_width, des_height));
}
/**
* fileUrl 根据视频在线地址获取文件url按秒截取帧
*/
public static List<MultipartFile> getVideoImageByUrl(String onlineFileUrl) {
//导出本地地址
// String filePath="C:\\Users\\wonder\\Desktop\\ai测试图片\\检测\\ai_ability_gateway\\视频截取后\\";
// File folder = new File(filePath);
// if (!folder.exists())
// {
// folder.mkdirs();//如果文件夹不存在则创建
// }
List<MultipartFile> list = new ArrayList<>();
try {
//url编码处理,中文名称会变成百分号编码
String fileUrl = URLDecoder.decode(onlineFileUrl, "utf-8");
MultipartFile multipartFile = drFdfsUpAndDowService.downloadMultipartByUrl(fileUrl);
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(multipartFile.getInputStream());
//FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(file);
grabber.start();
long ftp = grabber.getLengthInFrames();
Frame frame = null;
int sum = 1;
int count = (int) Math.round(grabber.getFrameRate());
for (int i = 1; i <= ftp; i++) {
frame = grabber.grabImage();
if (i % count == 0) {
String rotate = grabber.getVideoMetadata("rotate");
//创建BufferedImage对象
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
if (rotate != null) {
//旋转图片
bufferedImage = rotate(bufferedImage, Integer.parseInt(rotate));
}
String newFileName = sum + ".jpeg";
//写入本地
//ImageIO.write(bufferedImage, "jpeg", new File(filePath+newFileName));
//BufferedImage 转化为 ByteArrayOutputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpeg", out);
//ByteArrayOutputStream 转化为 byte[]
byte[] imageByte = out.toByteArray();
//将 byte[] 转为 MultipartFile
MultipartFile convertMultipartFile = new ConvertToMultipartFile(imageByte, null, newFileName, "jpeg", imageByte.length);
list.add(convertMultipartFile);
sum++;
}
}
grabber.close();
grabber.stop();
} catch (Exception e) {
System.out.printf("获取视频图片失败!", e);
}
return list;
}
/**
* fileUrl 根据视频在线地址获取文件url按秒截取帧
*/
public static List<MultipartFile> getVideoImageByUrlTest() {
//导出本地地址
String filePath = "C:\\Users\\wonder\\Desktop\\ai测试图片\\检测\\ai_ability_gateway\\视频截取后\\";
File folder = new File(filePath);
if (!folder.exists()) {
folder.mkdirs();//如果文件夹不存在则创建
}
List<MultipartFile> list = new ArrayList<>();
try {
//File file = new File("C:\\Users\\wonder\\Desktop\\ai测试图片\\检测\\ai_ability_gateway\\test.mp4");
File file = new File("C:\\Users\\wonder\\Desktop\\ai测试图片\\检测\\ai_ability_gateway\\测试视频.mp4");
MultipartFile multipartFile = FileUtil.fileToMultipartFile(file);
//MultipartFile multipartFile = drFdfsUpAndDowService.downloadMultipartByUrl(fileUrl);
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(multipartFile.getInputStream());
//FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(file);
grabber.start();
long ftp = grabber.getLengthInFrames();
Frame frame = null;
int sum = 1;
int flag = 0;
int count = (int) Math.round(grabber.getFrameRate());
for (int i = 1; i <= ftp; i++) {
frame = grabber.grabImage();
if (i % count == 0) {
String rotate = grabber.getVideoMetadata("rotate");
//创建BufferedImage对象
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
if (rotate != null) {
//旋转图片
bufferedImage = rotate(bufferedImage, Integer.parseInt(rotate));
}
String newFileName = sum + ".jpeg";
//写入本地
ImageIO.write(bufferedImage, "jpeg", new File(filePath + newFileName));
//BufferedImage 转化为 ByteArrayOutputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpeg", out);
//ByteArrayOutputStream 转化为 byte[]
byte[] imageByte = out.toByteArray();
//将 byte[] 转为 MultipartFile
MultipartFile convertMultipartFile = new ConvertToMultipartFile(imageByte, null, newFileName, "jpeg", imageByte.length);
list.add(convertMultipartFile);
sum++;
}
}
grabber.close();
grabber.stop();
} catch (Exception e) {
System.out.printf("获取视频图片失败!", e);
}
return list;
}
public static void main(String[] args) {
List<MultipartFile> videoImageByUrl = getVideoImageByUrlTest();
}
@PostConstruct
public void init() {
drFdfsUpAndDowService = remoteDrFdfsUpAndDowService;
}
}
2.获取视频时长
/**
* 获取视频时长
* @param multipartFile
* @return
* @throws EncoderException
*/
public static int queryVideoDuration(MultipartFile multipartFile) throws EncoderException {
//机算视频时长
File dfile = null;
try {
dfile = File.createTempFile("prefix", "_" + multipartFile.getOriginalFilename());
multipartFile.transferTo(dfile);
} catch (IOException e) {
e.printStackTrace();
}
// 获取视频时长
Encoder encoder = new Encoder();
MultimediaInfo m = encoder.getInfo(dfile);
long ls = m.getDuration()/1000;
int hour = (int) (ls/3600);
int minute = (int) (ls%3600)/60;
int second = (int) (ls-hour*3600-minute*60);
//删除临时文件
dfile.delete();
return second;
}
3.ConvertToMultipartFile 工具类
package com.wondertek.util.img;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
public class ConvertToMultipartFile implements MultipartFile {
private byte[] fileBytes;
String name;
String originalFilename;
String contentType;
boolean isEmpty;
long size;
public ConvertToMultipartFile(byte[] fileBytes, String name, String originalFilename, String contentType,
long size) {
this.fileBytes = fileBytes;
this.name = name;
this.originalFilename = originalFilename;
this.contentType = contentType;
this.size = size;
this.isEmpty = false;
}
@Override
public String getName() {
return name;
}
@Override
public String getOriginalFilename() {
return originalFilename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return isEmpty;
}
@Override
public long getSize() {
return size;
}
@Override
public byte[] getBytes() throws IOException {
return fileBytes;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(fileBytes);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(fileBytes);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/118670.html