Java使用FFmpeg(自定义cmd)
Java使用FFmpeg(自定义cmd)系列之获取视频/音频时长
Java使用FFmpeg(自定义cmd)系列之官方API获取视频/音频信息(File方式)
Java使用FFmpeg(自定义cmd)系列之官方API获取视频/音频信息(URL方式)
Java使用FFmpeg(自定义cmd)系列之获取视频/音频时长(File文件方式)
Java使用FFmpeg(自定义cmd)系列之mp4转hsl编码m3u8
Java使用FFmpeg(自定义cmd)系列之MP4 转码 HLS m3u8 AES128 加密
不用我们安装FFmpeg,项目自动依赖ffmpeg,已经有开源实现:
https://github.com/a-schild/jave2
下面的代码基于:3.1.1 version
maven坐标:
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-all-deps</artifactId>
<version>3.1.1</version>
</dependency>
cmd方式调用ffmpeg(封装):
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ws.schild.jave.process.ProcessKiller;
import ws.schild.jave.process.ProcessWrapper;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;
/**
*
* @Description:(cmd方式调用ffmpeg)
* @author: HeShengjin
* @date: 2021年6月22日 下午5:31:38
* @Copyright:
*/
public class FfmpegCmd {
private static final Logger LOG = LoggerFactory.getLogger(ProcessWrapper.class);
/** The process representing the ffmpeg execution. */
private Process ffmpeg = null;
/**
* A process killer to kill the ffmpeg process with a shutdown hook, useful if the jvm execution
* is shutted down during an ongoing encoding process.
*/
private ProcessKiller ffmpegKiller = null;
/** A stream reading from the ffmpeg process standard output channel. */
private InputStream inputStream = null;
/** A stream writing in the ffmpeg process standard input channel. */
private OutputStream outputStream = null;
/** A stream reading from the ffmpeg process standard error channel. */
private InputStream errorStream = null;
/**
* Executes the ffmpeg process with the previous given arguments.
*
* @param destroyOnRuntimeShutdown destroy process if the runtime VM is shutdown
* @param openIOStreams Open IO streams for input/output and errorout, should be false when
* destroyOnRuntimeShutdown is false too
* @param ffmpegCmd windows such as (mp4 transform to mov):
* " -i C:\\Users\\hsj\\AppData\\Local\\Temp\\jave\\honer.mp4 -c copy C:\\Users\\hsj\\AppData\\Local\\Temp\\jave\\honer_test.mov "
* @throws IOException If the process call fails.
*/
public void execute(boolean destroyOnRuntimeShutdown, boolean openIOStreams, String ffmpegCmd) throws IOException {
DefaultFFMPEGLocator defaultFFMPEGLocator = new DefaultFFMPEGLocator();
StringBuffer cmd = new StringBuffer(defaultFFMPEGLocator.getExecutablePath());
//insert blank for delimiter
cmd.append(" ");
cmd.append(ffmpegCmd);
String cmdStr = String.format("ffmpegCmd final is :%s", cmd.toString());
System.out.println(cmdStr);
LOG.info(cmdStr);
Runtime runtime = Runtime.getRuntime();
try {
ffmpeg = runtime.exec(cmd.toString());
if (destroyOnRuntimeShutdown) {
ffmpegKiller = new ProcessKiller(ffmpeg);
runtime.addShutdownHook(ffmpegKiller);
}
if (openIOStreams) {
inputStream = ffmpeg.getInputStream();
outputStream = ffmpeg.getOutputStream();
errorStream = ffmpeg.getErrorStream();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Returns a stream reading from the ffmpeg process standard output channel.
*
* @return A stream reading from the ffmpeg process standard output channel.
*/
public InputStream getInputStream() {
return inputStream;
}
/**
* Returns a stream writing in the ffmpeg process standard input channel.
*
* @return A stream writing in the ffmpeg process standard input channel.
*/
public OutputStream getOutputStream() {
return outputStream;
}
/**
* Returns a stream reading from the ffmpeg process standard error channel.
*
* @return A stream reading from the ffmpeg process standard error channel.
*/
public InputStream getErrorStream() {
return errorStream;
}
/** If there's a ffmpeg execution in progress, it kills it. */
public void destroy() {
if (inputStream != null) {
try {
inputStream.close();
} catch (Throwable t) {
LOG.warn("Error closing input stream", t);
}
inputStream = null;
}
if (outputStream != null) {
try {
outputStream.close();
} catch (Throwable t) {
LOG.warn("Error closing output stream", t);
}
outputStream = null;
}
if (errorStream != null) {
try {
errorStream.close();
} catch (Throwable t) {
LOG.warn("Error closing error stream", t);
}
errorStream = null;
}
if (ffmpeg != null) {
ffmpeg.destroy();
ffmpeg = null;
}
if (ffmpegKiller != null) {
Runtime runtime = Runtime.getRuntime();
runtime.removeShutdownHook(ffmpegKiller);
ffmpegKiller = null;
}
}
/**
* Return the exit code of the ffmpeg process If the process is not yet terminated, it waits for
* the termination of the process
*
* @return process exit code
*/
public int getProcessExitCode() {
// Make sure it's terminated
try {
ffmpeg.waitFor();
} catch (InterruptedException ex) {
LOG.warn("Interrupted during waiting on process, forced shutdown?", ex);
}
return ffmpeg.exitValue();
}
/**close**/
public void close() {
destroy();
}
}
cmd方式调用ffmpeg(使用):
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
*
* @Description:(cmd方式调用ffmpeg使用)
* @author: HeShengjin
* @date: 2021年6月22日 下午5:32:31
* @Copyright:
*/
public class FfmpegCmdTest {
//执行成功0,失败1
private static int CODE_SUCCESS = 0;
private static int CODE_FAIL = 1;
//将荣耀视频测试.mp4转换荣耀视频测试_转码.mov格式
private static String cmd_mp4_2_mov = " -i I:\\荣耀视频测试.mp4 -c copy I:\\荣耀视频测试_转码.mov ";
//将荣耀视频测试_转码.mov添加水印([email protected])荣耀视频测试_转码_水印.mov
private static String cmd_mov_water = " -i I:\\荣耀视频测试_转码.mov -vf \"drawtext=fontfile=Arial.ttf:text='[email protected]':y=h-line_h-20:x=(w-text_w)/2:fontsize=34:fontcolor=yellow:shadowy=2\" -b:v 3000k I:\\\\荣耀视频测试_转码_水印.mov ";
//多线程
private static int core = Runtime.getRuntime().availableProcessors();
private static ExecutorService pool = new ThreadPoolExecutor(core,//核心
core * 2,//最大
0L,//空闲立即退出
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024),//无边界阻塞队列
new ThreadPoolExecutor.AbortPolicy());
/**
* 第一步:mp4转mov
* 第二步:mov添加水印
* @param: @param args
* @return: void
* @throws
*/
public static void main(String[] args) {
//异步执行,获取执行结果code
CompletableFuture<Integer> completableFutureTask = CompletableFuture.supplyAsync(() ->{
return cmdExecut(cmd_mp4_2_mov);
}, pool)
.thenApplyAsync((Integer code)->{
if(CODE_SUCCESS != code) {return CODE_FAIL;}
System.out.println("第一步:mp4转mov,成功!");
Integer codeTmp = cmdExecut(cmd_mov_water);
if(CODE_SUCCESS != codeTmp) {return CODE_FAIL;}
System.out.println("第二步:mov添加水印,成功!");
return codeTmp;
}, pool);
//获取执行结果
//code=0表示正常
try {
System.out.println(String.format("获取最终执行结果:%s", completableFutureTask.get() == CODE_SUCCESS ? "成功!" : "失败!"));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
/**
*
* @Description: (执行ffmpeg自定义命令)
* @param: @param cmdStr
* @param: @return
* @return: Integer
* @throws
*/
public static Integer cmdExecut(String cmdStr) {
//code=0表示正常
Integer code = null;
FfmpegCmd ffmpegCmd = new FfmpegCmd();
/**
* 错误流
*/
InputStream errorStream = null;
try {
//destroyOnRuntimeShutdown表示是否立即关闭Runtime
//如果ffmpeg命令需要长时间执行,destroyOnRuntimeShutdown = false
//openIOStreams表示是不是需要打开输入输出流:
// inputStream = processWrapper.getInputStream();
// outputStream = processWrapper.getOutputStream();
// errorStream = processWrapper.getErrorStream();
ffmpegCmd.execute(false, true, cmdStr);
errorStream = ffmpegCmd.getErrorStream();
//打印过程
int len = 0;
while ((len=errorStream.read())!=-1){
System.out.print((char)len);
}
//code=0表示正常
code = ffmpegCmd.getProcessExitCode();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
ffmpegCmd.close();
}
//返回
return code;
}
}
我的小站:
http://www.binarydance.top//aticle_view.html?aticle_id=587710507340017664&t=1620287576763
gitee:
https://gitee.com/hsjjsh123/test-ffmpeg