java 精简使用ffmpeg

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);
    }

}
相关推荐
驭渊的小故事9 分钟前
Spring AOP 核心概念与通知类型详解
java·后端·spring
vipxieliang10 分钟前
ValidX vs 手写验证代码:开发效率对比实测
java·spring boot·后端
白杨尚青27 分钟前
C++进阶篇(五):红黑树——四条规则、三种插入情况与旋转变色
开发语言·数据结构·c++·stl·红黑树·平衡二叉树
vipxieliang30 分钟前
虚拟线程与 GraalVM:Spring Boot 3.x 云原生性能跃迁
java·spring boot·后端
Rain的Java大神之路31 分钟前
面试官最烦的答案:“我用 Redis + Token”!接口幂等 8 种方案 + 四层防御,把重复扣款工单干到 0
java·后端·面试
.道阻且长.34 分钟前
Linux基本开发工具:gdb和cgdb的使用
linux·运维·服务器·开发语言
Rainmicro1 小时前
【无标题】
java·数据库·算法
starzy19901 小时前
深入理解Scala匿名函数:函数式编程基石
开发语言·scala
Android系统攻城狮1 小时前
Linux FFmpeg深度解析之av_guess_format调用流程与实战(三十六)
linux·运维·服务器·ffmpeg·ffmpeg音视频进阶
驭渊的小故事1 小时前
Spring AOP 入门:从 AOP 概念到第一个耗时统计切面
java·后端·spring