最近项目需要将用户上传的视频如果不是MP4格式,需要全部转码为MP4格式的,这里我通过FFMPeg进行大文件视频转码的实现。
1、安装FFMPeg
首先我们需要在机器上安装FFMPeg用于我们的视频转码,传送门如下:
2、视频转码实现
package com.openailab.oascloud.file.common.helper;
import com.openailab.oascloud.file.common.config.BootstrapConfig;
import com.openailab.oascloud.file.common.consts.BootstrapConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
/**
* @description: 视频转码
* @author: zhangzhixiang
* @createDate: 2019/12/11
* @version: 1.0
*/
@Component
public class FileManagementHelper {
private static final Logger LOG = LoggerFactory.getLogger(FileManagementHelper.class);
@Autowired
private BootstrapConfig bootstrapConfig;
/**
* 文件转码
*
* @param filePath
* @return com.openailab.oascloud.common.model.ResponseResult
* @author zxzhang
* @date 2019/12/10
*/
public int transcode(String filePath) {
//1、获取文件名和后缀
String ext = getExt(filePath);
String fileDir = getFileDir(filePath);
String fileName = getFileName(filePath);
//2、删除同名文件
File originFile = new File(fileDir + fileName + BootstrapConst.SPOT + ext);
if (originFile.exists()){
originFile.delete();
}
//3、视频转码
LinkedList<String> ffmpegCmds = new LinkedList<>();
ffmpegCmds.add("ffmpeg");
ffmpegCmds.add("-i");
ffmpegCmds.add(bootstrapConfig.getFileRoot() + filePath);
ffmpegCmds.add("-c:v");
ffmpegCmds.add("libx264");
ffmpegCmds.add("-strict");
ffmpegCmds.add("-2");
ffmpegCmds.add(bootstrapConfig.getFileRoot() + fileDir + BootstrapConst.PATH_SEPARATOR + fileName + ".mp4");
ProcessBuilder builder = new ProcessBuilder();
builder.command(ffmpegCmds);
Process ffmpeg = null;
try {
ffmpeg = builder.start();
} catch (IOException e) {
e.printStackTrace();
}
String cmdStr = Arrays.toString(ffmpegCmds.toArray()).replace(",", "");
LOG.info("---开始执行FFmpeg指令:--- 执行线程名:" + builder.toString());
LOG.info("---已执行的FFmepg命令:---" + cmdStr);
// 取出输出流和错误流的信息
// 注意:必须要取出ffmpeg在执行命令过程中产生的输出信息,如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时,线程就回阻塞住
PrintStream errorStream = new PrintStream(ffmpeg.getErrorStream());
PrintStream inputStream = new PrintStream(ffmpeg.getInputStream());
errorStream.start();
inputStream.start();
// 等待ffmpeg命令执行完
int exit = 0;
try {
exit = ffmpeg.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
LOG.info("---执行结果:---" + (exit == 0 ? "【成功】" : "【失败】"));
if (exit == 0) {
originFile = new File(filePath);
if(originFile.exists()){
originFile.delete();
}
}
return exit;
}
/**
* 获取文件后缀
*
* @param fileName
* @return java.lang.String
* @author zxzhang
* @date 2019/12/10
*/
public String getExt(String fileName) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
/**
* 获取文件所在目录
*
* @param filePath
* @return java.lang.String
* @author zxzhang
* @date 2019/12/10
*/
public String getFileDir(String filePath) {
return filePath.substring(0, filePath.lastIndexOf(BootstrapConst.PATH_SEPARATOR));
}
/**
* 获取文件名
*
* @param filePath
* @return java.lang.String
* @author zxzhang
* @date 2019/12/10
*/
public String getFileName(String filePath) {
return filePath.substring(filePath.lastIndexOf(BootstrapConst.PATH_SEPARATOR) + 1, filePath.lastIndexOf("."));
}
}
class PrintStream extends Thread {
java.io.InputStream __is = null;
public PrintStream(java.io.InputStream is) {
__is = is;
}
@Override
public void run() {
try {
while (this != null) {
int _ch = __is.read();
if (_ch != -1) {
System.out.print((char) _ch);
} else {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、FFMPeg DockerFile实现
首先我们构建具有JDK1.8和FFMPeg环境的镜像
FROM jrottenberg/ffmpeg:centos
MAINTAINER oas.cloud
ADD jdk-8u231-linux-x64.tar.gz /usr/local/
ENV JAVA_HOME /usr/local/jdk1.8.0_231
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
WORKDIR /usr/local/oas/
然后将上述文件构建出的镜像的tag打为我们自己的镜像仓库地址,改为 10.12.1.202:8088/oascloud/ffmpeg:v1.0,我们的应用程序就可以以上述镜像文件(10.12.1.202:8088/oascloud/ffmpeg:v1.0)为基础构建出新的应用程序镜像,应用程序的DockerFile如下:
FROM 10.12.1.202:8088/oascloud/ffmpeg:v1.0
MAINTAINER oas.cloud
ENV LC_ALL=zh_CN.utf8
ENV LANG=zh_CN.utf8
ENV LANGUAGE=zh_CN.utf8
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
ARG JAR_FILE
COPY ${JAR_FILE} /usr/local/oas/
WORKDIR /usr/local/oas/
代码结构如下:
然后我们就可以快快乐乐的通过Docker容器的方式部署应用程序了。