POM依賴
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>0.8</version>
</dependency>
工具類
VideoCaptureUtils
package com.hsqyz.video.utils;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import sun.misc.BASE64Encoder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
/**
* 視頻截取指定幀圖片
*/
@Slf4j
public class VideoCaptureUtils {
/*默認(rèn)圖片格式 jpg*/
public static String DEFAULT_IMG_FORMAT = "jpg";
/*圖片格式 png*/
public static String IMG_FORMAT_PNG = "png";
/*圖片格式 jpg*/
public static String IMG_FORMAT_JPG = "jpg";
/*第一幀*/
public final static int FIRST = 0;
/*最后一幀*/
public final static int LAST = Integer.MAX_VALUE;
/**
* 獲取指定視頻的幀并保存為圖片JPG格式至指定文件
*
* @param videoFile 源視頻文件路徑
* @param targetFile 截取幀的圖片存放路徑
* @param frameNum 截取第幾幀
* @throws Exception
*/
public static void fetchFrameToFile(String videoFile, String targetFile, int frameNum) throws FrameGrabber.Exception, IOException {
//校驗(yàn)輸入和輸出
checkInAnOut(videoFile, targetFile);
try {
File frameFile = new File(targetFile);
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
ff.start();
int length = ff.getLengthInFrames();
/*第幾幀判斷設(shè)置*/
if (frameNum < 0) {
frameNum = 0;
}
if (frameNum > length) {
frameNum = length - 5;
}
//指定第幾幀
ff.setFrameNumber(frameNum);
int i = 0;
Frame f = null;
while (i < length) {
// 過濾前5幀裂明,避免出現(xiàn)全黑的圖片,依自己情況而定
f = ff.grabFrame();
if ((i >= 5) && (f.image != null)) {
break;
}
i++;
}
opencv_core.IplImage img = f.image;
int width = img.width();
int height = img.height();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
0, 0, null);
ff.flush();
ff.stop();
ImageIO.write(bi, DEFAULT_IMG_FORMAT, frameFile);
} catch (Exception e) {
throw new RuntimeException("轉(zhuǎn)換視頻圖片異常");
}
}
/**
* 獲取指定視頻的幀并保存為圖片自定義類型至指定文件
*
* @param videoFile 源視頻文件路徑
* @param targetFile 截取幀的圖片存放文件路徑
* @param outImgFormat 輸出圖片格式
* @param frameNum 截取第幾幀
* @throws Exception
*/
public static void fetchFrameToFile(String videoFile, String targetFile, String outImgFormat, int frameNum) throws FrameGrabber.Exception, IOException {
//校驗(yàn)輸入和輸出
checkInAnOut(videoFile, targetFile);
try {
File frameFile = new File(targetFile);
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
ff.start();
int length = ff.getLengthInFrames();
/*第幾幀判斷設(shè)置*/
if (frameNum < 0) {
frameNum = 0;
}
if (frameNum > length) {
frameNum = length - 5;
}
//指定第幾幀
ff.setFrameNumber(frameNum);
int i = 0;
Frame f = null;
while (i < length) {
// 過濾前5幀蚣驼,避免出現(xiàn)全黑的圖片望艺,依自己情況而定
f = ff.grabFrame();
if ((i >= 5) && (f.image != null)) {
break;
}
i++;
}
opencv_core.IplImage img = f.image;
int width = img.width();
int height = img.height();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
0, 0, null);
ff.flush();
ff.stop();
ImageIO.write(bi, outImgFormat, frameFile);
} catch (Exception e) {
throw new RuntimeException("轉(zhuǎn)換視頻圖片異常");
}
}
/**
* 獲取指定視頻的幀圖片,并轉(zhuǎn)換為base64字符串
*
* @param videoFile 源視頻文件路徑
* @param frameNum 截取第幾幀
* @throws Exception
*/
public static String fetchFrameToBase64(String videoFile, int frameNum) throws FrameGrabber.Exception, IOException {
//校驗(yàn)輸入
checkVideoFile(videoFile);
try (ByteArrayOutputStream output = new ByteArrayOutputStream();) {
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videoFile);
ff.start();
int length = ff.getLengthInFrames();
/*第幾幀判斷設(shè)置*/
if (frameNum < 0) {
frameNum = 0;
}
if (frameNum > length) {
frameNum = length - 5;
}
//指定第幾幀
ff.setFrameNumber(frameNum);
int i = 0;
Frame f = null;
while (i < length) {
// 過濾前5幀唯笙,避免出現(xiàn)全黑的圖片螟蒸,依自己情況而定
f = ff.grabFrame();
if ((i >= 5) && (f.image != null)) {
break;
}
i++;
}
opencv_core.IplImage img = f.image;
int width = img.width();
int height = img.height();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
bi.getGraphics().drawImage(f.image.getBufferedImage().getScaledInstance(width, height, Image.SCALE_SMOOTH),
0, 0, null);
ImageIO.write(bi, DEFAULT_IMG_FORMAT, output);
// 這里需要獲取圖片的base64數(shù)據(jù)串盒使,所以將圖片寫到流里面
ff.flush();
ff.stop();
return new BASE64Encoder().encode(output.toByteArray());
} catch (Exception e) {
throw new RuntimeException("轉(zhuǎn)換視頻圖片異常");
}
}
/**
* 校驗(yàn)輸入輸出
*
* @param videoFile
* @param targetFile
*/
public static void checkInAnOut(String videoFile, String targetFile) {
checkVideoFile(videoFile);
checkTargetFileDir(targetFile);
}
/**
* 驗(yàn)證文件目錄是否存在,不存在就創(chuàng)建
*
* @param targetFile 文件路徑
* @return
*/
public static void checkTargetFileDir(String targetFile) {
String dirPath = targetFile.substring(0, targetFile.lastIndexOf(File.separator) + 1);
File dir = new File(dirPath);
if (!dir.exists()) {
dir.mkdirs();
}
}
/**
* 檢驗(yàn)文件是否存在
*
* @param videoFile
*/
public static void checkVideoFile(String videoFile) {
File file = new File(videoFile);
if (!file.exists()) {
throw new RuntimeException("文件不存在");
}
}
}