Java提取视频中的指定桢数生成视频缩略图的解决方案
- 1.1 开发背景
- 1.2 如何使用JavaCV?
- 1.2.1 引入依赖
- 1.2.2 编写工具类库
- 1.2.3 测试调用
- 1.3 利用阿里云OOS获取视频缩略图
- 参考资料
1.1 开发背景
在Java后端开发中,当返回给前端或移动端视频列表的时候,客户端往往并不直接加载所有视频,而是先加载后端返回的视频缩略图列表。
然而这个视频缩略图列表从哪里来呢?总不能让上传视频的用户自己上传吧?
答案当然是不能, 我们Java后端其实是有办法解决这个问题的。
一种方法是使用FFmpeg 视频定时截图工具,这种局限在必须部署在windows 服务器。
另外一种是通过程序Java 代码编程方式使用JavaCV 类库实现。
那么什么是JavaCV 呢?
JavaCV
是对各种常用计算机视觉库的封装后的一组jar包,其中封装了FFmpeg
、OpenCV
等计算机视觉编程人员常用库的接口,可以通过其中的Utility类方便的在包括Android在内的Java平台上调用这些接口。- 最开始
Javacv
是googlecode
下面的一个项目,后来迁移到了github,因此JavaCV
相关的包名也由com.googlecode.javacv
改为org.bytedeco.javacv
。目前最新版本是 1.3.
上面这段话也解开了我的一个疑惑。
因为我之前尝试maven 中心仓库搜索javacv 后发现有这三个类库,到底使用哪一种开始心存疑惑。
google java cv 那个版本太老了,也就是说我们如果使用javacv,直接使用java CV Platform 类库即可。至于为什么不用JavaCV 那个,其实我也找了一篇博文,但是试了下貌似需要缺少so 库,于是放弃了。
JavaCV目前最新版本是 1.5.3。项目地址:https://github.com/bytedeco/javacv
1.2 如何使用JavaCV?
1.2.1 引入依赖
1
2
3
4
5
6
7<!-- https://mvnrepository.com/artifact/org.bytedeco/javacv-platform --> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.3</version> </dependency>
查看最新版本
1.2.2 编写工具类库
编写工具类库SmartFileUtils.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.Java2DFrameConverter; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.UUID; /** * @author qing-feng.zhao */ public class SmartFileUtils { /** * * 截取视频第六帧的图片 * * @param filePath 视频路径 * @param dir 文件存放的根目录 * @return 图片的相对路径 例:pic/1.png */ public static String videoImage(String filePath, String dir) throws FrameGrabber.Exception { String pngPath = ""; FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath); ff.setFormat("mp4"); ff.start(); int ffLength = ff.getLengthInFrames(); Frame f; int i = 0; while (i < ffLength) { f = ff.grabImage(); //截取第6帧 if ((i > 5) && (f.image != null)) { //生成图片的相对路径 例如:pic/uuid.png pngPath = getPngPath(); //执行截图并放入指定位置 doExecuteFrame(f, dir + pngPath); break; } i++; } ff.stop(); return pngPath; } /** * 生成图片的相对路径 * * @return 图片的相对路径 例:pic/1.png */ private static String getPngPath() { return "pic/" + getUUID() + ".png"; } /** * 生成唯一的uuid * * @return uuid */ private static String getUUID() { return UUID.randomUUID().toString().replace("-", ""); } /** * 截取缩略图 * * @param f Frame * @param targerFilePath:封面图片存放路径 */ private static void doExecuteFrame(Frame f, String targerFilePath) { String imagemat = "png"; if (null == f || null == f.image) { return; } Java2DFrameConverter converter = new Java2DFrameConverter(); BufferedImage bi = converter.getBufferedImage(f); File output = new File(targerFilePath); try { ImageIO.write(bi, imagemat, output); } catch (IOException e) { e.printStackTrace(); } } }
1.2.3 测试调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35import lombok.extern.slf4j.Slf4j; import org.bytedeco.javacv.FrameGrabber; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @Slf4j class SmartFileUtilsTest { private String testPath; @BeforeEach void setUp() { testPath="/Users/zhaoqingfeng/Documents/temp/test.mp4"; //testPath="https://v.qq.com/txp/iframe/player.html?vid=q0024wtk0v8"; } @AfterEach void tearDown() { } @Test void videoImage() { try { String filePath=SmartFileUtils.videoImage(testPath,"/Users/zhaoqingfeng/Documents/temp/"); log.info("{}",filePath); } catch (FrameGrabber.Exception e) { log.error("出错",e); } } }
然后就可以看到/Users/zhaoqingfeng/Documents/temp/test.mp4
视频的缩略图已经存放到/Users/zhaoqingfeng/Documents/temp/pic/
文件夹下了,图片名称命名我们使用了UUID.
PS:
如果出现错误,javacv-error-has-setformat-been-called 那么可能视频地址文件不对,请使用绝对路径。
另外,代码里不要少了这一行:ff.setFormat("mp4");
测试二在尝试获取腾讯视频地址的时候由于无法获取到视频真实文件地址,导致报错失败。
1.3 利用阿里云OOS获取视频缩略图
今天偶然发现的一个新操作,凡是存放在阿里云OOS上的视频,都可以很方便的获取视频缩略图。
操作示例如下:
比如这是阿里云OOS上一个视频:http://a-image-demo.oss-cn-qingdao.aliyuncs.com/demo.mp4
那么获取视频第一秒的png格式的缩略图缩略图就是:http://a-image-demo.oss-cn-qingdao.aliyuncs.com/demo.mp4?x-oss-process=video/snapshot,t_10000,m_fast,w_400,h_400,f_png
参数 | 描述 | 取值范围 |
---|---|---|
t | 截图时间 | 单位ms,[0,视频时长] |
w | 截图宽度,如果指定为0则自动计算 | 像素值:[0,视频宽度] |
h | 截图高度,如果指定为0则自动计算,如果w和h都为0则输出为原视频宽高 | 像素值:[0,视频高度] |
m | 截图模式,不指定则为默认模式,根据时间精确截图,如果指定为fast则截取该时间点之前的最近的一个关键帧 | 枚举值:fast |
f | 输出图片格式 | 枚举值:jpg、png |
本篇完~
参考资料
- JavaCV 学习(一):JavaCV 初体验
- JAVA生成视频缩略图的两种方式
- 用Java代码提取视频的缩略图的两种办法
- javacv-error-has-setformat-been-called
- https://github.com/bytedeco/javacv
- 阿里云oss视频上传后,如何获取视频封面
最后
以上就是想人陪手套最近收集整理的关于Java提取视频中的指定桢数生成视频缩略图的解决方案参考资料的全部内容,更多相关Java提取视频中内容请搜索靠谱客的其他文章。
发表评论 取消回复