xml
<properties>
<java.version>25</java.version>
<mybatis-flex.version>1.11.7</mybatis-flex.version>
<awssdk.version>2.42.21</awssdk.version>
<javacv.version>1.5.13</javacv.version>
<ffmpeg.version>8.0.1-${javacv.version}</ffmpeg.version>
<spring-ai.version>2.0.0</spring-ai.version>
<spring-ai-session.version>0.6.0</spring-ai-session.version>
</properties>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>${javacv.version}</version>
</dependency>
<profiles>
<profile>
<id>window</id>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>${ffmpeg.version}</version>
<classifier>windows-x86_64</classifier>
</dependency>
</dependencies>
</profile>
<profile>
<id>linux</id>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>${ffmpeg.version}</version>
<classifier>linux-x86_64</classifier>
</dependency>
</dependencies>
</profile>
</profiles>
java
package com.kongjs.smo.common.util;
import org.bytedeco.javacv.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class FFmpegUtil {
private static final Logger log = LoggerFactory.getLogger(FFmpegUtil.class);
public static void captureFirstFrame(String videoPath, String outImgPath, String format) {
FFmpegFrameGrabber grabber = null;
Java2DFrameConverter converter = new Java2DFrameConverter();
try {
grabber = new FFmpegFrameGrabber(videoPath);
grabber.start();
if (grabber.getImageWidth() <= 0 || grabber.getImageHeight() <= 0) {
return;
}
Frame frame = null;
int tryCount = 0;
while (tryCount < 100) {
frame = grabber.grabFrame();
tryCount++;
if (frame != null && frame.image != null) {
break;
}
}
if (frame == null || frame.image == null) {
return;
}
BufferedImage image = converter.convert(frame);
ImageIO.write(image, format, new File(outImgPath));
} catch (FFmpegFrameGrabber.Exception e) {
// 帧读取器异常
log.error("FFmpeg解码视频失败:" + e.getMessage());
} catch (FrameGrabber.Exception e) {
// FFmpeg 底层解码
log.error("帧采集器读取异常:" + e.getMessage());
} catch (IOException e) {
// 文件流异常
log.error("文件IO读写失败:" + e.getMessage());
} finally {
// 强制释放资源,防止句柄泄漏
if (grabber != null) {
try {
grabber.stop();
grabber.close();
} catch (Exception ignored) {
}
}
}
}
public static void captureFirstFrame(String videoPath, String outImgPath, String format, int thumbWidth, int thumbHeight, int quality) {
FFmpegFrameGrabber grabber = null;
FFmpegFrameRecorder recorder = null;
try {
grabber = new FFmpegFrameGrabber(videoPath);
grabber.start();
if (grabber.getImageWidth() <= 0 || grabber.getImageHeight() <= 0) {
return;
}
Frame frame = null;
int tryCount = 0;
while (tryCount < 100) {
// 抓取关键帧,避免黑屏
frame = grabber.grabKeyFrame();
tryCount++;
if (frame != null && frame.image != null) {
break;
}
}
if (frame == null || frame.image == null) {
return;
}
int width = grabber.getImageWidth();
int height = grabber.getImageHeight();
recorder = new FFmpegFrameRecorder(outImgPath, width, height);
recorder.setFormat(format);
recorder.setVideoQuality(quality);
recorder.start();
recorder.record(frame);
} catch (FFmpegFrameGrabber.Exception e) {
// 帧读取器异常
log.error("FFmpeg解码视频失败:" + e.getMessage());
} catch (FrameGrabber.Exception e) {
// FFmpeg 底层解码
log.error("帧采集器读取异常:" + e.getMessage());
} catch (IOException e) {
// 文件流异常
log.error("文件IO读写失败:" + e.getMessage());
} finally {
if (recorder != null) {
try {
recorder.close();
} catch (Exception ignored) {
}
}
// 强制释放资源,防止句柄泄漏
if (grabber != null) {
try {
grabber.close();
} catch (Exception ignored) {
}
}
}
}
static void main() {
captureFirstFrame("C:\\Users\\101202104016\\Videos\\Captures\\111111111111111111111111111111.mp4","C:\\Users\\101202104016\\Videos\\Captures\\111111111111111111111111111111.webp",
"webp",400,400,75);
}
}