最近接到一个老项目,由于老项目之前适配的是ie浏览器。该老项目中有很多wmv和avi格式的视频。最近需要更换视频其他浏览器访问,需要对除ie浏览器的其他浏览器进行适配。ie浏览器播放视频没有任何问题,但是在主流浏览器中,无法识别<embed>标签
,只支持<video>、<audio>标签
,然而这些标签支持的视频格式为主流的mp4格式的视频。导致兼容性问题,无法播放,以及主流浏览器无法播放非mp4格式的视频。尝试了很多,查阅了很多资料,前端无法解决该问题,最后尝试使用后端来解决该问题。通过java调用ffmpeg来对已经存储在系统中的视频进行自主的格式转换为mp4,前端通过判断是否为ie浏览器,而执行对应的js脚本。如果发现为非ie浏览器,并且视频为非mp4格式的视频,则主动调用后台接口,对该视频进行格式转换,同时更新数据库存储视频的目标位置,之后再访问该视频时,就查询到的是mp4格式的视频,就无需再做格式转换操作了。
文末附相关安装包、ffmpeg相关命令介绍
ffmpeg
ffmpeg是一个支持多个格式视频转换(包括asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv格式)的软件。在windows和linux环境下使用的方式不同。
首先需要下载ffmpeg软件,解压之后将ffmpeg.exe放入到项目目录中。通过java去调用该程序,执行命令对目标视频进行格式转换。
相关java代码
ConvertVideo
是接收需要转换的视频的类。需要注意的是,其中window环境下获取的ffmpeg目录与linux环境下获取ffmpeg目录是不同的。
public class ConvertVideo {
public static Boolean convertVedio(String inputPath) throws FFmpegException {
if (inputPath.substring(inputPath.lastIndexOf(".")).equals(".mp4") || inputPath.substring(inputPath.lastIndexOf(".")).equals(".MP4")){
return true;
}
String ffmpegPath = getFfmpegPath();
String outputPath = getOutputPath(inputPath);
if (new File(outputPath).exists()){
return true;
}
return FFmpegUtil.ffmpeg(ffmpegPath, inputPath, outputPath);
}
/**
* 获取ffmpeg执行文件的路径
*
* @return
*/
private static String getFfmpegPath() {
// windows环境
return new Object(){
public String getPath(){
return this.getClass().getResource("/").getPath().replaceAll("WEB-INF/classes/", "")+"ffmpeg/";
}
}.getPath();
// linux环境
//return "/opt/ffmpeg/ffmpeg-release.4.1/";
}
/**
* 获取输出文件名
*
* @param inputPath
* @return
*/
private static String getOutputPath(String inputPath) {
return inputPath.substring(0, inputPath.lastIndexOf(".")) + ".mp4";
}
public static String getNewFileUrl(String inputPath) {
return inputPath.substring(0, inputPath.lastIndexOf(".")) + ".mp4";
}
}
FFmpegException
这是定义ffmpeg异常类
public class FFmpegException extends Exception {
private static final long serialVersionUID = 1L;
public FFmpegException() {
super();
}
public FFmpegException(String message) {
super(message);
}
public FFmpegException(Throwable cause) {
super(cause);
}
public FFmpegException(String message, Throwable cause) {
super(message, cause);
}
}
FFmpegUtil
主要对视频进行格式转换的类
public class FFmpegUtil {
/**
* 将视频转换为mp4
*
* @param ffmpegPath ffmpegPath bin路径
* @param inputPath 源文件路径
* @param outputPath 输出文件路径
* @return
*/
public static Boolean ffmpeg(String ffmpegPath, String inputPath, String outputPath) throws FFmpegException{
if (!checkfile(inputPath)) {
throw new FFmpegException("文件格式不合法");
}
int type = checkContentType(inputPath);
List<String> command = getFfmpegCommand(type, ffmpegPath, inputPath, outputPath);
if (null != command && command.size() > 0) {
return process(command);
}
return false;
}
/**
* 检查视频的格式
*
* @param inputPath 源文件
* @return
*/
private static int checkContentType(String inputPath) {
String type = inputPath.substring(inputPath.lastIndexOf(".") + 1, inputPath.length()).toLowerCase();
// ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
if (type.equals("avi")) {
return 0;
} else if (type.equals("mpg")) {
return 0;
} else if (type.equals("wmv")) {
return 0;
} else if (type.equals("3gp")) {
return 0;
} else if (type.equals("mov")) {
return 0;
} else if (type.equals("mp4")) {
return 0;
} else if (type.equals("asf")) {
return 0;
} else if (type.equals("asx")) {
return 0;
} else if (type.equals("flv")) {
return 0;
}
// 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等)
else if (type.equals("wmv9")) {
return 1;
} else if (type.equals("rm")) {
return 1;
} else if (type.equals("rmvb")) {
return 1;
}
return 9;
}
/**
* 检查文件的合法性
*
* @param path 文件路径
* @return
*/
private static boolean checkfile(String path) {
File file = new File(path);
return file.isFile();
}
/**
* ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
*
* @param command ffmpeg的命令
* @throws FFmpegException
*/
private static boolean process(List<String> command) throws FFmpegException{
try {
if (null == command || command.size() == 0) {
return false;
}
Process videoProcess = new ProcessBuilder(command).redirectErrorStream(true).start();
new PrintStream(videoProcess.getErrorStream()).start();
new PrintStream(videoProcess.getInputStream()).start();
int exitcode = videoProcess.waitFor();
return exitcode != 1;
} catch (Exception e) {
throw new FFmpegException("file upload failed",e);
}
}
/**
* 根据文件类型设置ffmpeg命令
*
* @param type 该视频对应的类型
* @param ffmpegPath ffmpeg执行文件的路径
* @param oldfilepath 需要被转换的视频路径
* @param outputPath 转换后输出的路径
* @return
* @throws FFmpegException
*/
private static List<String> getFfmpegCommand(int type, String ffmpegPath, String oldfilepath, String outputPath) throws FFmpegException {
List<String> command = new ArrayList<String>();
if (type == 0) {
command.add(ffmpegPath+"ffmpeg");
command.add("-y");
command.add("-i");
command.add(oldfilepath);
command.add("-c:v");
command.add("libx264");
command.add("-mbd");
command.add("0");
command.add("-c:a");
command.add("aac");
command.add("-strict");
command.add("-2");
command.add("-pix_fmt");
command.add("yuv420p");
command.add("-movflags");
command.add("faststart");
command.add(outputPath);
} else{
throw new FFmpegException("不支持当前上传的文件格式");
}
return command;
}
}
// 开启新的线程对视频进行格式转换
class PrintStream extends Thread {
private static final Logger log = LoggerFactory.getLogger(PrintStream.class);
java.io.InputStream inputStream = null;
public PrintStream(java.io.InputStream is) {
inputStream = is;
}
@Override
public void run() {
try {
while (this != null) {
int ch = inputStream.read();
if (ch == -1) {
break;
} else {
System.out.print((char) ch);
}
}
} catch (Exception e) {
log.error("convert media error!", e);
}
}
}
linux环境下使用ffmpeg
安装GCC
yum install gcc
查看安装结果gcc --version
安装yasm
1.下载yasm
wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
2.解压yasm
执行:tar -zxvf yasm-1.3.0.tar.gz
3.进入解压目录
执行: cd yasm-1.3.0
4.编译和安装
执行1:./configure
执行2:make
执行3:make install
5.查看安装结果
执行yasm --version
安装nasm
1.下载nasm
wget http://www.nasm.us/pub/nasm/releasebuilds/2.13/nasm-2.13.tar.gz
2.解压nasm
执行 tar xzvf nasm-2.13.tar.gz
3.进入目录
执行:cd nasm-2.13
4.编译和安装
执行1:./configure
执行2:make
执行3:make install
5.查看安装结果
执行nasm --version
安装x264
1,下载x264 或解压x264
git clone https://code.videolan.org/videolan/x264.git
2.进入x264目录
cd x264
3.编译和安装
执行1:./configure --enable-shared
执行2:make
执行3:make install
4.查看安装结果
执行x264 --version
安装ffmpeg
1.下载ffmpeg4.1
wget https://git.ffmpeg.org/gitweb/ffmpeg.git/snapshot/refs/heads/release/4.1.tar.gz
2.解压ffmpeg4.1
执行: tar xzfv 4.1.tar.gz
3.进入解压目录
解压之后目录名为ffmpeg-release.4.1-d44da66
,请将目录名修改为ffmpeg-release.4.1
执行: cd ffmpeg-release.4.1/
4.编译和安装
执行1:./configure --enable-gpl --enable-libx264
如果出现类似error如下:
WARNING: using libfdk without pkg-config WARNING: using libx264 without pkg-config ERROR: x265 not found using pkg-config If you think configure made a mistake, make sure you are using the latest version from Git. If the latest version fails, report the problem to the ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.freenode.net. Include the log file "ffbuild/config.log" produced by configure as this will help solve the problem.
原因是需要设置PKG_CONFIG_PATH,通过pkg-config去指定路径自动寻找需要链接的依赖库,解决方法如下,执行命令:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig echo $PKG_CONFIG_PATH 查看结果为 /usr/local/lib/pkgconfig
解释:PKG_CONFIG_PATH (此路径为.pc文件所在路径,里面有x264.cp)
然后重新编译就ok了!
执行2:make
执行3:make install(大概30分钟左右)
5.查看安装结果 ffmpeg -version
如果出现如下:
6.编辑id.so.conf文件
执行vim /etc/ld.so.conf
在include ld.so.conf.d/*.conf后换行添加
/usr/local/lib
(如果有这句话,直接保存退出,没有就添加这句话)
:x
保存退出
在ffmpeg目录下,执行 ldconfig
然后再执行 ffmpeg -version
测试
将2.wmv
转换成2.mp4
本人安装ffmpeg时,是将ffmpeg安装在/home/herocheung/ffmpeg/目录下的,因此有了一下测试命令:
/home/herocheung/ffmpeg/ffmpeg-release.4.1/ffmpeg -i ./2.wmv -c:v libx264 -mbd 0 -c:a aac -strict -2 -pix_fmt yuv420p -movflags faststart ./2.mp4
-- 命令解释:
(指定ffmpeg安装目录下的ffmpeg) -i (需要转换的视频位置) -c:v libx264 -mbd 0 -c:a aac -strict -2 -pix_fmt yuv420p -movflags faststart (转换后视频存放位置)
安装完成之后,把java中相关的代码切换到linux环境下能够正确识别的路径即可实现java调用ffmpeg程序,实现视频格式转。
截取视频中的图片
从视频中截取第60s处的图片 ffmpeg -i test.mp4 -y -f image2 -ss 60 -vframes 1 test1.jpg
附件
【相关安装包(windows ffmpeg、linux ffmpeg相关包)】
链接:https://pan.baidu.com/s/1GFt-i4l4r_IlgscAVqcmkQ
提取码:ef26
【ffmpeg相关命令】http://linux.51yip.com/search/ffmpeg