個人博客 地址:https://www.wenhaofan.com/article/20190407105818
引入依賴
<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>
代碼案例
package live.autu.ctcms.common.kit; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.imageio.ImageIO; import org.bytedeco.javacpp.opencv_core; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import com.jfinal.kit.PathKit; import com.jfinal.kit.Ret; public class VideoFrameUtil { private static String rootPath = PathKit.getWebRootPath() + "/video/img";// 服務器路徑 private static final String IMAGEMAT = "png"; // 圖片格式 private static final String ROTATE = "rotate"; public static final int MOD = 1;// 第一幀 public static Ret getVideoFirstFrame(String videoPath, String imageName) { return getVideoFrame(videoPath, imageName, MOD); } /** * 獲取視頻縮略圖 * * @param lpath * @param filePath:視頻路徑 * @param mod:視頻長度/mod獲取第幾幀 * @throws Exception */ public static Ret getVideoFrame(String filePath, String targetImageName, int mod) { // 根據視頻路徑生成縮略圖存放路徑 String targetFilePath = null; try (FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);) { ff.start(); String rotate = ff.getVideoMetadata(ROTATE); int ffLength = ff.getLengthInFrames(); Frame f = null; int i = 0; int index = mod; if (i >= ffLength) { return Ret.fail(); } for (int j = 0; j <= index; j++) { f = ff.grabImage(); } if (null != rotate && rotate.length() > 1) { OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage(); IplImage src = converter.convert(f); f = converter.convert(rotate(src, Integer.valueOf(rotate))); // 旋轉圖片 } targetFilePath = doExecuteFrame(f, targetImageName); ff.stop(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return Ret.ok("targetFilePath",targetFilePath) .set("relativeFilePath", "/video/img/"+targetImageName); // 返回的是視頻第一幀 } /** * 旋轉圖片 * * @param src * @param angle * @return */ public static IplImage rotate(IplImage src, int angle) { IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels()); opencv_core.cvTranspose(src, img); opencv_core.cvFlip(img, img, angle); return img; } /** * 根據視頻路徑生成縮略圖存放路徑 * * @param filePath:視頻路徑 * @param index:第幾幀 * @return:縮略圖的存放路徑 */ private static String getImagePath(String fileName) { return rootPath+"/" + fileName; } /** * 截取縮略圖 * * @param f * @param targerFilePath:封面圖片 * @throws IOException */ public static String doExecuteFrame(Frame f, String lpath) throws IOException { if(!new File(rootPath).exists()) { new File(rootPath).mkdirs(); } String targerFilePath = getImagePath(lpath); if (null == f || null == f.image) { return null; } Java2DFrameConverter converter = new Java2DFrameConverter(); BufferedImage bi = converter.getBufferedImage(f); File output = new File(targerFilePath); output.createNewFile(); ImageIO.write(bi, IMAGEMAT, output); return targerFilePath; } /** * 根據視頻長度隨機生成隨機數集合 * * @param baseNum:基礎數字,此處為視頻長度 * @param length:隨機數集合長度 * @return:隨機數集合 */ public static List<Integer> random(int baseNum, int length) { List<Integer> list = new ArrayList<Integer>(length); while (list.size() < length) { Integer next = (int) (Math.random() * baseNum); if (list.contains(next)) { continue; } list.add(next); } Collections.sort(list); return list; } }