最佳实践-Java调用ffmpeg[-vf(滤镜)多语句]示例

一、技术介绍

在日常工作中,经常会涉及到的对音视频的操作,这就不得不用到ffmpeg。ffmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。其中ffmpeg强大的视频滤镜功能是必不可少的,使用视频滤镜可以实现一系列的视频处理和转换效果,如:画面旋转,翻转,裁剪,缩放,色彩调整等效果;视频滤镜VideoFilter,可以同时设置一个或多个滤镜 , 多个滤镜之间使用逗号隔开,因此又称为"视频滤镜链"。

对于单个视频滤镜,在通过JAVA调用时,可以直接通过Process调用实现。 例如:

String cmd = "ffmpeg -y -i " + inPath + " -vf scale=1920:1080 " + outPut;
Process process = Runtime.getRuntime().exec(cmd);
……

但视频滤镜链按上面的写法,程序是不能正确识别的

ffmpeg指令:
ffmpeg -i input.mov -vf "color=white:size=720x1280:d=1.0:r=30[bg];[bg][0:v]overlay=(W-w)/2:(H-h)/2:format=auto,scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p" -c:a copy -r 30 -y output.mp4
程序执行期间或报错:
[AVFilterGraph @ 0xcac840] No such filter: 'color=white:size=720x1280:d=1.0:r=30[bg];[bg][0:v]overlay=(W-w)/2:(H-h)/2:format=auto,scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p'

面对这种问题,两种思路:化整为零,把滤镜链拆分成一个个单视频滤镜,多次调用;化零为整,探索一种整合的新办法。

二、解决问题的思路和方法

化整为零,拆指令很显然不是最佳解决方案;我们采用“化零为整”,把ffmpeg的视频滤镜链写到一个.sh脚本里。

三、实践过程描述

编写ffmpeg.sh并存放在resource/conf目录下

#bin/bash

INPUT_VIDEO="$1"
INPUT_RESOLUTIONS="$2"
INPUT_FPS="$3"
OUTPUT_VIDEO="$4"
ffmpeg -i ${INPUT_VIDEO} -vf "color=white:size=${INPUT_RESOLUTIONS}:d=1.0:r=${INPUT_FPS}[bg];[bg][0:v]overlay=(W-w)/2:(H-h)/2:format=auto,scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p" -vcodec libx264 -acodec aac -ac 1 -pix_fmt yuv420p -r ${INPUT_FPS} -b:v 5000k -y ${OUTPUT_VIDEO}

通过JAVA调用ffmpeg.sh脚本

List<URL> resources = ClassUtil.getResources("conf/ffmpeg.sh");
if (CollUtil.isEmpty(resources)) {
    LOGGER.error("conf/ffmpeg.sh shell脚本不存在!");
    throw new Exception("ffmpeg转码视频出现了错误,conf/ffmpeg.sh shell脚本不存在!");
}
String shellPath = resources.get(0).getPath();
// 构建ffmpeg命令
String commandSb = String.format("sh %s %s %s %s %s",shellPath,inPath,resolutionStr,frameRate,outPut);
LOGGER.info("【processStandardFormatVideo】 命令是:{}", commandSb);
// 执行命令
Process process = Runtime.getRuntime().exec(commandSb);
// 处理进程的输出流
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String errorLine;
while ((errorLine = errorReader.readLine()) != null) {
    LOGGER.info(errorLine);
}

// 等待进程结束
int exitCode = process.waitFor();
if (exitCode == 0) {
    return outPut;
}

四、对实践过程的思考和对效果的评价

充分理解问题的关键卡点,通过报错信息可以得出Process在解析滤镜链时无法识别,但滤镜链直接通过ffmpeg执行是没问题的,那问题就出现在了传参方式上,所以我们应该尝试不同的传参方式,来解决这类问题,而不是把复杂的滤镜链拆成一个个的单滤镜。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值