获取视频帧图片

news2024/9/23 3:12:05

在实现了minio文件上传的基础上进行操作

一、编写pom

<dependency>
    <groupId>org.jcodec</groupId>
    <artifactId>jcodec</artifactId>
    <version>0.2.5</version>
</dependency>
<dependency>
    <groupId>org.jcodec</groupId>
    <artifactId>jcodec-javase</artifactId>
    <version>0.2.5</version>
</dependency>

二、新增创建FileItem的方法

@Slf4j
public class FileUtil {

    // 默认文件名
    private static final String defaultFilename = "file";

    public static FileItem createFileItem(InputStream inputStream) {
        final String filename = defaultFilename + "." +  MediaType.IMAGE_JPEG.getSubtype();
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem(filename, MediaType.MULTIPART_FORM_DATA_VALUE, true, filename);
        try(OutputStream os = item.getOutputStream()) {
            IOUtils.copy(inputStream, os);
        } catch (IOException e) {
            log.error("create fileItem stream copy occurred exception", e);
            throw new VideoFrameException(VideoFrameExceptionTypes.FILE_CREATE_FAILED);
        }
        return item;
    }
}

三、视频工具类获取帧

@Slf4j
public class VideoUtil {

    private static final List<String> videoSuffix = Arrays.asList(
            "avi", "wmv", "mov", "mpg", "mpeg", "rm", "ram", "flv", "swf", "mp4"
    );

    public static MultipartFile getFirstFrame(MultipartFile videoFile) {
        return getFrame(videoFile, 1);
    }

    public static MultipartFile getFrame(MultipartFile multipartFile, int frameNumber) {
        String originalFilename = multipartFile.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename) || !originalFilename.contains(".")) {
            throw new VideoFrameException(VideoFrameExceptionTypes.NOT_SUPPORTED_FILE_TYPE);
        }
        String[] filenameSplit = originalFilename.split("\\.");
        if (!videoSuffix.contains(filenameSplit[filenameSplit.length - 1])) {
            throw new VideoFrameException(VideoFrameExceptionTypes.NOT_SUPPORTED_FILE_TYPE);
        }
        CommonsMultipartFile cf = (CommonsMultipartFile) multipartFile;
        DiskFileItem fi = (DiskFileItem) cf.getFileItem();
        File file = fi.getStoreLocation();
        MultipartFile videoCover = null;
        try {
            Picture pic = FrameGrab.getFrameFromFile(file, frameNumber);
            BufferedImage bi = AWTUtil.toBufferedImage(pic);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(bi, MediaType.IMAGE_JPEG.getSubtype(), baos);
            InputStream input = new ByteArrayInputStream(baos.toByteArray());
            FileItem fileItem = FileUtil.createFileItem(input);
            videoCover = new CommonsMultipartFile(fileItem);
        } catch (IOException | JCodecException e) {
            log.error("获取视频帧出现异常", e);
            throw new VideoFrameException(VideoFrameExceptionTypes.GET_VIDEO_FRAME_FAILED);
        }
        return videoCover;
    }
}

四、编写Controller进行测试

@Slf4j
@RequestMapping("video")
@RestController
public class VideoController {

    @Resource
    private MinioService minioService;

    // 上传视频
    @PostMapping("/uploadVideo")
    public String uploadVideo(MultipartFile file) {
        String filename = minioService.upload(file);
        log.info("视频 {} 上传成功!", filename);
        MultipartFile firstFrame = VideoUtil.getFirstFrame(file);
        String firstFrameFilename = minioService.upload(firstFrame);
        log.info("封面 {} 上传成功!", firstFrameFilename);
        return filename;
    }
}
### 上传
POST http://127.0.0.1:8888/video/uploadVideo
Content-Type: multipart/form-data; boundary=WebAppBoundary

--WebAppBoundary
Content-Disposition: form-data; name="file"; filename="Grant_Gustin_share.mp4"

< /Users/wangfeihu/IdeaProjects/video-frame/src/main/resources/video/Grant_Gustin_share.mp4
--WebAppBoundary--

测试
首帧图片
获取并上传视频首帧成功!

代码仓库: video-frame-demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1440750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Modern C++ 内存篇1 - allocator

1. 前言 从今天起我们开始内存相关的话题&#xff0c;内存是个很大的话题&#xff0c;一时不知从何说起。内存离不开allocator&#xff0c;我们就从allocator开始吧。allocator目前有两种&#xff1a;std::allocator, std::pmr::polymorphic_allocator&#xff0c;各有优缺点。…

中小型网络系统总体规划与设计方法

目录 1.基于网络的信息系统基本结构 2.网络需求调研与系统设计原则 3.网络用户调查 4.网络节点地理位置分布情况 5.网络需求详细分析 6.应用概要分析 7.网络工程设计总体目标与设计原则 8.网络结构与拓扑构型设计方法 9.核心层网络结构设计 10.接入核心路由器 11.汇聚…

寒假作业2024.2.8

1.现有文件test.c\test1.c\main.c,请编写Makefile Makefile文件&#xff1a; CCgcc EXEfile OBJS$(patsubst %.c,%.o,$(wildcard *.c)) CFLAGS-c -o all:$(EXE)file:test.o test1.o main.o$(CC) $^ -o $%.o:%.c$(CC) $(CFLAGS) $ $^.PHONY:clean clean:rm $(OBJS)main.c文件:…

Codeforces Round 260 (Div. 1)A. Boredom(dp)

最开始写了一发贪心wa了&#xff0c;然后这种选和不选的组合优化问题&#xff0c;一般是考虑动态规划 d p [ i ] [ 0 ] &#xff1a; dp[i][0]&#xff1a; dp[i][0]&#xff1a;表示第i个数不选的最大值 d p [ i ] [ 1 ] &#xff1a; dp[i][1]&#xff1a; dp[i][1]&#xf…

【LeetCode】37. 解数独(困难)——代码随想录算法训练营Day30

题目链接&#xff1a;37. 解数独 题目描述 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&…

Python进阶--爬取美女图片壁纸(基于回车桌面网的爬虫程序)

目录 一、前言 二、爬取下载美女图片 1、抓包分析 a、分析页面 b、明确需求 c、抓包搜寻 d、总结特点 2、编写爬虫代码 a、获取图片页网页源代码 b、提取所有图片的链接和标题 c、下载并保存这组图片 d、 爬取目录页的各种类型美女图片的链接 e、实现翻页 三、各…

TCP和UDP相关问题(重点)——8.TCP的拥塞控制怎么实现的?

在某段时间内&#xff0c;若对网络中某一资源的需求超过了该资源所能提供的可用部分&#xff0c;网络性能就会变坏&#xff0c;比如在高速公路上行驶的车辆&#xff0c;如果一时期内涌入了太多的车辆&#xff0c;道路将变得拥堵&#xff0c;交通状况变差。网络中也是一样&#…

Android 识别车牌信息

打开我们心爱的Android Studio 导入需要的资源 gradle //开源车牌识别安卓SDK库implementation("com.github.HyperInspire:hyperlpr3-android-sdk:1.0.3")button.setOnClickListener(v -> {Log.d("Test", "");try (InputStream file getAs…

Java并发基础:Deque接口和Queue接口的区别?

核心概念 Deque&#xff08;double ended queue&#xff0c;双端队列&#xff09;和Queue&#xff08;队列&#xff09;都是Java集合框架中的接口&#xff0c;它们用于处理元素的排队和出队&#xff0c;但是它们之间存在一些重要的区别&#xff0c;如下&#xff1a; 1、Queue…

RSA算法加密、签名和验签、解密

一、背景介绍 RSA是一种非对称加密算法&#xff0c;该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥&#xff0c;公钥是公开的&#xff08;可能同时多人持有&#xff09;。 二、RSA算法工具类 package com.hl.rsademo.util;import java.i…

MYSQL分区NOW()不支持

传说同事写个复杂的SQL代码,跑一次需要7-10秒, 复杂如上,我也懒得去分析 IF IF IF是怎么回事了! 发现此表是分区表,后面要求加上了分区时间,以便利用到分区裁剪技术. 因为需求是查近10天来到期还款的人和金额.就是今天应该还款的人, 一般还款周期是7天. 给个10天的范围挺可以的…

【DDD】学习笔记-领域实现模型

实现模型与编码质量 领域设计模型体现了类的静态结构与动态协作&#xff0c;领域实现模型则进一步把领域知识与技术实现连接起来&#xff0c;但同时它必须守住二者之间的边界&#xff0c;保证业务与技术彼此隔离。这条边界线应由设计模型明确给出&#xff0c;其中的关键是遵循…

基于SSM的网络在线考试系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的网络在线考试系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring …

数字图像处理实验记录十(图像分割实验)

一、基础知识 1、什么是图像分割 图像分割就是指把图像分成各具特性的区域并提取出感兴趣目标的技术和过程&#xff0c;特性可以是灰度、颜色、纹理等&#xff0c;目标可以对应单个区域&#xff0c;也可以对应多个区域。 2、图像分割是怎么实现的 图像分割算法基于像素值的不连…

Java微服务学习Day1

文章目录 认识微服务服务拆分及远程调用服务拆分服务远程调用提供者与消费者 Eureka注册中心介绍构建EurekaServer注册user-serviceorder-service完成服务拉取 Ribbon负载均衡介绍原理策略饥饿加载 Nacos注册中心介绍配置分级存储负载均衡环境隔离nacos注册中心原理 认识微服务…

《剑指 Offer》专项突破版 - 面试题 30 和 31:详解如何设计哈希表以及利用哈希表设计更加高级、复杂的数据结构

目录 一、哈希表的基础知识 二、哈希表的设计 2.1 - 插入、删除和随机访问都是 O(1) 的容器 2.2 - 最近最少使用缓存 一、哈希表的基础知识 哈希表是一种常见的数据结构&#xff0c;在解决算法面试题的时候经常需要用到哈希表。哈希表最大的优点是高效&#xff0c;在哈希表…

java实现算法

一、二分法 二分法查找主要是为了快速查找给定数组内&#xff0c;期待值在数组中的位置&#xff08;下标&#xff09; 二分法查找通过对整个数组取中间值&#xff0c;判断期待值所在的范围并缩小范围&#xff0c;每次查找范围折半&#xff0c;直到范围的边界重合&#xff0c;…

终端命令提示符:如何查看我们电脑端口是否被占用和处理方式

文章目录 端口信息查看1、Windows:2、Linux/macOS: 使用 netstat使用 lsof 端口信息查看 在不同的操作系统中&#xff0c;查看端口是否被占用的指令有所不同。以下是一些常见的指令&#xff1a; 1、Windows: 使用命令行工具 netstat 来查看端口占用情况。 电脑键盘按住 win…

第九个知识点:内部对象

Date对象: <script>var date new Date();date.getFullYear();//年date.getMonth();//月date.getDate();//日date.getDay();//星期几date.getHours();//时date.getMinutes();//分date.getSeconds();//秒date.getTime();//获取时间戳&#xff0c;时间戳时全球统一&#x…

[计算机提升] 备份系统:系统映像

6.3 备份系统&#xff1a;系统映像 备份系统和还原系统是一套互补的操作。 操作系统的备份就是将操作系统当前的所有数据复制到硬盘的一个空闲区域&#xff0c;以防止系统崩溃或数据丢失。还原操作则是将先前备份的数据恢复到操作系统中&#xff0c;使系统回到之前的样子&…