相信不少做app开发的同事,都遇到一种需求,要做视频的轮播图,这时候我们没办法或者不好直接将视频作为轮播,所以通常的解决方案是获取到视频的第一帧图像作为首图,使用该首图作为轮播。实现首图获取无非就是前端获取或者后端获取后传给前端。在使用uniapp作为前端基础开发app应用时,限于组件的约束,要实现视频第一帧的获取是比较麻烦的,所以我们通常可以选择后端进行获取。
一、网上提供的方案
我使用的语言是java,初次接触这个问题,大家都会去搜索网上是如何实现的,在参考大量文章之后,我们发现,大部分文章提供的都是如下的方式:
引入依赖:
实现代码:
启动执行main方法,在指定的文件夹汇总,惊喜的发现我们成功得到了第一帧的图片。
于是信心满满的部署到了服务器上(作者环境是docker),结果发现问题并没有我们想象的如此简单,我们得到了下面的错误:
那怎么解决呢?我们在容器当中安装对应的组件就行吗?带着疑问进行尝试;因为javacv图像处理的核心还是使用的ffmpeg
这个工具组件,所以我们不妨在doker当中安装一下,看看能否解决问题。基于我们的环境可以查看当前linux中是否带有这个组件,我以Alpine Linux
为例,通过下面的命令进行查找和安装:
shell
# 查找系统是否有ffmpeg
apk search ffmpeg
# 安装(如果有的话)
apk add ffmpeg
安装成功后,我们再次尝试在获取第一帧图片的功能,于是惊奇的发现又报了其他我的错误:
不能进行初始化,就是下面这行代码:
java
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(videofile);
这是怎么回事呢?其实我也不知道,于是又开始不停的在网上搜索相关的内容,得到的结果大概有两种方式:
- 替换pom引用,我的javacv版本较低,于是乎就开始像无头苍蝇一样的替换各种依赖,调整各种实现代码,结果无一例外的,在windows好使,docker中仍然是一样的效果。即使咱们针对不同的错误去处理,你会发现像无底洞一样,不同的错误会一一出现在你的眼前,最终还是不能再linux使用。
- 于是乎我们不得不怀疑是不是我们的环境有问题,所以在有些文章里会提到,是不是我们可以尝试更换下jdk等,比如更换成openjdk等。
由于我开始尝试了第一种方式,没达到效果,也不想去尝试更换openjdk了,毕竟结果似乎也没有被人验证。所以我不得不转换一下自己的思路。
二、使用cmd调用ffmpeg
经过前面的踩坑过程,我能确定的是,我们可以使用ffmpeg去获取第一帧,不过要转换下自己的思路,首先需要简单了解下ffmpeg
是什么。
ffmpeg是一个完整的跨平台解决方案,用于录制、转换和流式传输音频和视频。
2.1 安装
windows安装
在官网下载对应的安装包:
如上下载完成后解压到本地,同时去配置对应的环境变量:
此时就可以进行验证了,查看版本:
cmd
C:\Users\86133>ffmpeg -version
ffmpeg version N-111780-g7098bec73b-20230817 Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 13.1.0 (crosstool-NG 1.25.0.196_227d99d)
configuration: --prefix=/ffbuild/prefix --pkg-config-flags=--static --pkg-config=pkg-config --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 --enable-gpl --enable-version3 --disable-debug --enable-shared --disable-static --disable-w32threads --enable-pthreads --enable-iconv --enable-libxml2 --enable-zlib --enable-libfreetype --enable-libfribidi --enable-gmp --enable-lzma --enable-fontconfig --enable-libvorbis --enable-opencl --disable-libpulse --enable-libvmaf --disable-libxcb --disable-xlib --enable-amf --enable-libaom --enable-libaribb24 --enable-avisynth --enable-chromaprint --enable-libdav1d --enable-libdavs2 --disable-libfdk-aac --enable-ffnvcodec --enable-cuda-llvm --enable-frei0r --enable-libgme --enable-libkvazaar --enable-libass --enable-libbluray --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librist --enable-libssh --enable-libtheora --enable-libvpx --enable-libwebp --enable-lv2 --enable-libvpl --enable-openal --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenh264 --enable-libopenjpeg --enable-libopenmpt --enable-librav1e --enable-librubberband --enable-schannel --enable-sdl2 --enable-libsoxr --enable-libsrt --enable-libsvtav1 --enable-libtwolame --enable-libuavs3d --disable-libdrm --disable-vaapi --enable-libvidstab --enable-vulkan --enable-libshaderc --enable-libplacebo --enable-libx264 --enable-libx265 --enable-libxavs2 --enable-libxvid --enable-libzimg --enable-libzvbi --extra-cflags=-DLIBTWOLAME_STATIC --extra-cxxflags= --extra-ldflags=-pthread --extra-ldexeflags= --extra-libs=-lgomp --extra-version=20230817
libavutil 58. 16.101 / 58. 16.101
libavcodec 60. 23.100 / 60. 23.100
libavformat 60. 10.100 / 60. 10.100
libavdevice 60. 2.101 / 60. 2.101
libavfilter 9. 11.100 / 9. 11.100
libswscale 7. 3.100 / 7. 3.100
libswresample 4. 11.100 / 4. 11.100
libpostproc 57. 2.100 / 57. 2.100
将mp4文件转换成avi文件:
cmd
C:\Users\86133>ffmpeg -i C:\Users\86133\Desktop\视频\1.mp4 C:\Users\86133\Desktop\视频\2.avi
下面办我们的正事儿,获取视频的第一帧图片:
cmd
ffmpeg -i C:\Users\86133\Desktop\视频\1.mp4 -ss 00:00:01 -vframes 1 -y C:\Users\86133\Desktop\视频\2.jpg
linux安装
linux安装比较简单了,像我前面提到过:
-
在Alpine Linux当中,基础组件里面就会有对应的安装包,只要使用如下方式安装即可:
shell# 查找系统是否有ffmpeg apk search ffmpeg # 安装(如果有的话) apk add ffmpeg
-
如果是centos可以在线使用yum安装,例如,安装过程可能遇到问题,可以参考下面的文章: linux.xiaosiseo.com/post/8523.h...
-
也可以像windos一样,下载安装包,上传到服务器,同时需要配置环境变量等,相对要比windows复杂,可以参考下面的文章: blog.csdn.net/weixin_4469...
安装完成后一样可以通过查看版本验证是否安装成功:
shell
/ # ffmpeg -version
ffmpeg version 3.4.6 Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 6.4.0 (Alpine 6.4.0)
configuration: --prefix=/usr --enable-avresample --enable-avfilter --enable-gnutls --enable-gpl --enable-libass --enable-libmp3lame --enable-libvorbis --enable-libvpx --enable-libxvid --enable-libx264 --enable-libx265 --enable-libtheora --enable-libv4l2 --enable-postproc --enable-pic --enable-pthreads --enable-shared --enable-libxcb --disable-stripping --disable-static --disable-librtmp --enable-vaapi --enable-vdpau --enable-libopus --disable-debug
libavutil 55. 78.100 / 55. 78.100
libavcodec 57.107.100 / 57.107.100
libavformat 57. 83.100 / 57. 83.100
libavdevice 57. 10.100 / 57. 10.100
libavfilter 6.107.100 / 6.107.100
libavresample 3. 7. 0 / 3. 7. 0
libswscale 4. 8.100 / 4. 8.100
libswresample 2. 9.100 / 2. 9.100
libpostproc 54. 7.100 / 54. 7.100
2.2 Java调用
我们就使用前面提到的命令,实现我们第一帧图片的获取,不过对应的地址要更换成服务器的路径:
java
/**
* 获取指定视频的帧并保存为图片至指定目录
*
* @param sourcePath 源视频文件路径
* @param targetPath 截取帧的图片存放路径
* @throws Exception
*/
public static void fetchFrame(String sourcePath, String targetPath)
throws Exception {
// 使用 ffmpeg 获取视频封面
String cmd = "ffmpeg -i " + sourcePath + " -ss 00:00:01 -vframes 1 -y -loglevel quiet " + targetPath;
Process process = Runtime.getRuntime().exec(cmd);
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
如果在执行代码时发现程序卡在这一行:
java
process.waitFor();
请注意的你的ffmpeg命令中是否有参数:quiet
,该参数能够让程序静默工作,不输出版本、工作信息。
三、小结
到此为止,已经将java整合ffmpeg实现视频处理的内容给大家做了简单的扫盲。包括在windows和linux当中的安装和使用方式。文章开篇也包含我在使用中遇到的问题,希望大家不要再走重复的路,直接使用命令的方式调用即可。ffmpeg的功能非常强大,大家可以在自己需要的场景进行使用,但是切记不要做违法乱纪的事哦~~