java获取视频封面图片

依赖

<!-- 视频截图 -->
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.7</version>
</dependency>
<!-- 工具包 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>
<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

代码

import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.*;

public class Test {
    public static void main(String[] args) {
        // 你电脑本地的视频全路径,目前发现支持mp4、webm,其他的需要自己去尝试
        File videoFile = new File("C:\\download\\谷歌浏览器\\202207\\搞笑--一个字绝_爱给网_aigei_com.webm");
        // 封面数量
        long coverNum = 1;
        // 是否随机生成封面
        boolean random = false;
        Map<Long, String> coverMap = generateCover(videoFile, coverNum, random);
        coverMap.forEach((key, value) -> System.out.printf("截图秒数:%s秒;图片地址:%s\n", key, value));
    }

    /**
     * 生成视频封面
     * @author 明快de玄米61
     * @date   2022/12/4 16:34
     * @param  videoFile 视频全路径,目前发现支持mp4、webm,其他的需要自己去尝试
     * @param  coverNum 封面数量
     * @param  random 是否随机生成封面
     * @return map,其中key是秒数,而value是图片全路径
     **/
    private static Map<Long, String> generateCover(File videoFile, long coverNum, boolean random) {
        // 验证视频
        if (!(videoFile != null && videoFile.isFile() && videoFile.exists())) {
            throw new RuntimeException("参数:videoFile 不符合要求");
        }
        // 验证封面数量
        if (coverNum <= 0) {
            throw new RuntimeException("参数:coverNum 必须大于0");
        }

        // 存储封面
        Map<Long, String> coverMap = new TreeMap<>();

        // 生成封面
        FFmpegFrameGrabber grabber = null;
        try {
            // 初始化FFmpegFrameGrabber
            grabber = new FFmpegFrameGrabber(videoFile);
            grabber.start();

            // 获取截取秒数
            Set<Long> secondSet = generateSecondList(grabber, coverNum, random);

            // 循环生成封面
            for (Long second : secondSet) {
                // 设置封面截取时间
                grabber.setTimestamp(second * 1000000L);
                Frame f = grabber.grabImage();
                Java2DFrameConverter converter = new Java2DFrameConverter();
                BufferedImage bi = converter.getBufferedImage(f);

                // 指定封面保存地址
                File imgFile = createTempFile("cover.jpg");

                // 生成封面图片
                ImageIO.write(bi, "jpg", imgFile);

                // 装载封面图片
                coverMap.put(second, imgFile.getAbsolutePath());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }
            } catch (FFmpegFrameGrabber.Exception e) {
                e.printStackTrace();
            }
        }

        return coverMap;
    }

    /**
     * 获取封面截图秒数集合
     * @author 明快de玄米61
     * @date   2022/12/4 17:51
     * @param  grabber FFmpegFrameGrabber对象
     * @param  coverNum 封面数量
     * @param  random 是否随机生成封面
     * @return 封面截图秒数集合
     **/
    @SneakyThrows
    private static Set<Long> generateSecondList(FFmpegFrameGrabber grabber, long coverNum, boolean random) {
        // 存储封面截图秒数集合
        Set<Long> secondSet = new TreeSet<>();

        // 获取视频时长秒数;说明:除以1000000可以获取秒数
        long totalVideoSecond = grabber.getLengthInTime() / 1000000;

        // 随机生成截图时间
        if (random)
        {
            Random secureRandom = SecureRandom.getInstanceStrong();
            for (int i = 1; i <= coverNum; i++) {
                secondSet.add((long) (secureRandom.nextInt((int) totalVideoSecond - 1) + 1));
            }
        }
        // 自定义截图时间
        else
        {
            coverNum = totalVideoSecond > coverNum ? coverNum : totalVideoSecond;
            for (long i = 1; i <= coverNum; i++) {
                secondSet.add(i);
            }
        }

        return secondSet;
    }

    /**
     * 生成临时文件
     * @author 明快de玄米61
     * @date   2022/12/4 18:00
     * @param  fileName 文件全名称
     * @return file文件
     **/
    public static File createTempFile(String fileName) {
        try {
            // 参数判断
            if (StringUtils.isBlank(fileName) || fileName.lastIndexOf(".") < 0) {
                return null;
            }
            // 创建临时目录
            String tmpdirPath = System.getProperty("java.io.tmpdir");
            String dateStr = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String uuId = UUID.randomUUID().toString().replaceAll("-", "");
            String[] params = {tmpdirPath, dateStr, uuId};
            // 结果例如:C:\Users\Administrator\AppData\Local\Temp\20220630\0f774122c38b423793cc1c121611c142
            String fileUrl = StringUtils.join( params, File.separator);
            if (!new File(fileUrl).exists()) {
                new File(fileUrl).mkdirs();
            }
            // 创建临时文件
            File file = new File(fileUrl, fileName);
            file.createNewFile();
            return file;
        } catch (Exception e) {
            System.out.println("》》》创建临时文件失败,临时文件名称:" + fileName);
            e.printStackTrace();
        }
        return null;
    }
}

解释

以下内容是对代码中random参数的解释

  • 如果random是true,那么将按照coverNum来随机截取封面
  • 如果random是false,那么将按照coverNum来顺序截取封面,返回总封面数量不会超过视频总秒数

结果

截图秒数:1秒;图片地址:C:\Users\mingming\AppData\Local\Temp\20221204\9ce19ca9932947399bf17d9e0facd037\cover.jpg

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值