前言

  公司业务中有一些场景需要用到服务端音视频剪辑技术,最开始为了快速上线使用的是某公有云的商用解决方案,但由于费用太高所以我们团队经过一个星期的冲刺,给出了一个FFmpeg+Serverless的解决方案,更好地满足了业务方的视频剪辑需求。经过统计,自研方案成功地将剪辑失败率降到了万分之一左右,并且将费用成本降到了原本的15%左右,是一个非常大的突破。现在我们计划把该平台做得更加通用化,让更多的业务可以无缝接入,通过任务编排来实现更多定制化需求。

  题外话,为什么我们会选择Serverless来实现该业务呢,因为我们的业务高峰期特别明显,时效性要求也高,在使用某公有云解决方案期间经常触发系统QPS限制,经过多次沟通也只能临时调整,而且对方技术半夜还打电话来问我是否可以限制QPS,作为使用方肯定是不愿意的,所以除了成本外性能也是我们下决心自研系统的原因之一。Serverless在使用过程中遇到的问题我也会在后续时间里面记录下来。

  本编博客主要是记录在整个过程中涉及到的FFmpeg常见命令,以及一些坑,分享给大家使用,若有谬误请批评指正。

基本命令

音视频剪切

String.format("%s -i %s -vcodec libx264  -ss %s -to %s %s -y", ffmpegCommandPath, sourceFilePath, startTime, endTime, targetFilePath)

ffmpegCommandPath    表示FFmpeg执行命令的路径

sourceFilePath              表示源文件路径

startTime                     表示剪切的起始点,格式为 "00:00:00", 例如 "00:00:15" 表示剪切从第15秒开始

endTime                      表示剪切的终止点,格式为 "00:00:00", 例如 "00:00:20" 表示剪切截止到第20秒

targetFilePath               表示剪切后的输出文件

-y                               表示输出文件若存在则覆盖  

音频/视频简单拼接

String.format("%s -f concat -safe 0 -i %s -c copy %s", ffmpegCommandPath, concatListFilePath, destinationFilePath)

ffmpegCommandPath    表示FFmpeg执行命令的路径

concatListFilePath         表示拼接的配置文件,内容格式为

file 'filePath1.audio'

file 'filePath2.audio'

destinationFilePath        表示拼接后的输出文件

使用限制:该方式不涉及到文件的解码、编码,所以速度极快,但如果待处理文件的编码格式不同则请勿使用,否则输出的文件可能无法正常播放(或者只能播放一部分)。如果编码格式不同,请参考下文中的音频拼接/视频拼接方式,会更加可靠,当会更加消耗资源。

音频拼接

由于涉及到到参数拼接,所以直接上代码(Java方式)。

/**
* 音频文件拼接
* @param files 音频文件资源路径数组
* @param destinationFilePath 处理后输出文件路径
*/
public static void audioConcat(String[] files, String destinationFilePath) {
// command list
List<String> commandList = new ArrayList<>();
commandList.add("ffmpeg"); // input_options
for (String file : files) {
commandList.add("-i");
commandList.add(file);
} // filter_complex
StringBuilder filterComplexOptions = new StringBuilder();
for (int i = 0; i < files.length; i++) {
filterComplexOptions.append(String.format("[%s:0]", i));
}
filterComplexOptions.append(String.format("concat=n=%s:v=0:a=1[out]", files.length));
commandList.add("-filter_complex");
commandList.add(filterComplexOptions.toString());
commandList.add("-map");
commandList.add("[out]");
commandList.add(destinationFilePath);
Runtime.getRuntime().exec(commandList.toArray(new String[0])); // next process
}

视频拼接

由于涉及到到参数拼接,所以直接上代码(Java方式)。

/**
* 视频拼接
* @param files 音频文件资源路径数组
* @param destinationFilePath 处理后输出文件路径
* @param outputWidth 输出视频的宽度
* @param outputHeight 输出视频的高度
*/
public static void videoConcat(String[] files, String destinationFilePath, Integer outputWidth, Integer outputHeight) {
// command list
List<String> commandList = buildFfmpegCommand();
commandList.add("ffmpeg"); // input_options
for (String file : files) {
commandList.add("-i");
commandList.add(file);
} // filter_complex
StringBuilder filterComplexOptions = new StringBuilder();
StringBuilder streamsOptions = new StringBuilder();
for (int i = 0; i < files.length; i++) {
filterComplexOptions.append(String.format("[%s:v]scale=w=%s:h=%s,setsar=1/1[v%s];", i, outputWidth, outputHeight, i));
streamsOptions.append(String.format("[v%s][%s:a]", i, i));
}
streamsOptions.append(String.format("concat=n=%s:v=1:a=1 [vv] [aa]", files.length));
commandList.add("-filter_complex");
commandList.add(String.format("%s%s", filterComplexOptions.toString(), streamsOptions.toString()));
Collections.addAll(commandList, "-map", "[vv]", "-map", "[aa]", "-c:v", "libx264", "-x264-params",
"profile=main:level=3.1", "-crf", "18", "-y", "-vsync", "vfr");
commandList.add(destinationFilePath);
Runtime.getRuntime().exec(commandList.toArray(new String[0])); // next process
}

踩坑经验: 我们在拼接过程中遇到了视频拼接出错的情况,但数量比较少,通过FFprobe命令分析,发现这种情况出现在其中某个视频无音轨的情况,找了很多解决方案,最后采用的方式是为这个视频配一个音轨,相当于先把素材标准化处理,为视频注入音轨的方式见下文 "无音轨视频配音"。

音视频混合

String.format("%s -i %s -i %s -filter_complex amix -map 0:v -map 0:a -map 1:a -shortest -y %s", ffmpegCommandPath, videoFilePath, audioFilePath, targetFilePath)

ffmpegCommandPath    表示FFmpeg执行命令的路径

videoFilePath                表示视频文件路径

audioFilePath                表示音频文件路径

targetFilePath               表示输出文件路径

无音轨视频配音

String.format("%s -i %s -f lavfi -i aevalsrc=0 -shortest -y %s", ffmpegCommandPath, videoFilePath, targetFilePath)

ffmpegCommandPath    表示FFmpeg执行命令的路径

videoFilePath                表示视频文件路径

targetFilePath               表示输出文件路径

音视频点播服务基础系列(Fmpeg常用命令)的更多相关文章

  1. Linux基础系列:常用命令(6)_nfs服务与nginx服务

    NFS介绍: NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向外公布.功能是通过网络让不同的机器.不同的操作系统 ...

  2. Linux基础系列:常用命令(5)_samba服务与nginx服务

    作业一:部署samba 每个用户有自己的目录,可以浏览内容,也可以删除 所有的用户共享一个目录,只能浏览内容,不能删 安装samba服务 1.准备环境 setenforce 0 2.安装软件包 yum ...

  3. Linux基础系列:常用命令(4)_系统监控

    1. 系统监视和进程控制工具—top和free 1) top命令的功能:top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器. 2) ...

  4. Linux基础系列:常用命令(1)

    1.开启Linux操作系统,要求以root用户登录GNOME图形界面,语言支持选择为汉语 2.使用快捷键切换到虚拟终端2,使用普通用户身份登录,查看系统提示符 命令:ctrl+alt+F2 3.使用命 ...

  5. Linux基础系列:常用命令(7)_正则表达式

    一.环境边量 每个用户登录shell需要执行的四个文件 /etc/profile /home/egon/.bashrc_profile /home/egon/.bashrc /etc/bashrc 非 ...

  6. Linux基础系列:常用命令(3)

    作业一: ) 将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/.txt(覆盖) cat /etc/passwd /etc/group > /test/.txt ) 将用户信息数据库文件 ...

  7. Linux基础系列:常用命令(8)_shell script

    一.什么是shell script 将OS命令堆积到可执行的文件里,由上至下的顺序执行文本里的OS命令 就是脚本了. 再加上些智能(条件/流控)控制,就变成了智能化脚本了 二.变量命名规则 以字母或下 ...

  8. Linux基础系列:常用命令(2)

    作业一: 1) 新建用户natasha,uid为1000,gid为555,备注信息为“master” groupadd -g 555 natasha useradd -u 1000 -g 555 -c ...

  9. Linux基础 - 系统优化及常用命令

    目录 Linux基础系统优化及常用命令 Linux基础系统优化 网卡配置文件详解 ifup,ifdown命令 ifconfig命令 ifup,ifdown命令 ip命令 用户管理与文件权限篇 创建普通 ...

随机推荐

  1. SRP(单一职责)——没有一只能飞能走的鸟

    单一职责原则(SRP:Single responsibility principle)又称单一功能原则.它规定一个类应该只有一个发生变化的原因. 一.起因 编码中,需要创建一只小鸟,既能飞,用能走. ...

  2. Git 系列教程(8)- 远程仓库的使用

    查看远程仓库 如果想查看你已经配置的远程仓库服务器,可以运行 git remote 命令,它会列出你指定的每一个远程服务器的名称 如果是刚 clone 下来的自己的库,能看到 origin,这是 Gi ...

  3. CAS的理解

    CAS(CompareAndSweep)工作方式 ​ CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被 ...

  4. [笔记] 《我的第一本c++书》

    函数 优秀函数的五个要点 函数的返回值:直接返回和间接返回(指针) 在函数的入口处对参数有效性进行检验:if语句,断言(assert) 如果函数有返回值,不可返回一个指向函数体内局部对象的指针或引用 ...

  5. 查看 swappiness 值

    Swap的使用频率  发表于 2017-06-02 |  分类于 Linux |  评论数: 通过调整swappiness的值, 可以调整系统使用 swap 的频率 该值越小, 表示越大限度的使用物理 ...

  6. .jnlp 文件打开方式

    .jnlp 文件打开方式 jnlp文件打开需要安装jre ,java环境,通过java环境运行即可,下面介绍详细步骤 1.下载.安装最新版jre环境,直接下一步即可 2 java配置 打开控制面板,查 ...

  7. cento 7使用minicom串口调试工具

    cento 7使用minicom串口调试工具   因为要使用串口配置设备,所以考虑要用串口管理软件,windows下比较容易了,直接用超级终端也好,用CRT也可以,CentOS系统稍微麻烦一点,前几天 ...

  8. 042.Python进程队列介绍

    进程队列介绍 1  基本语法及过程 先进先出,后进后出,q = Queue() 过程 (1)把数据放到q队列中 put (2)把书局从队列中拿出来 get from multiprocessing i ...

  9. 在Linux服务器,搭建K8s服务【脚本篇】

    前言 好久没有写博客了,本文主要是对网上文章的总结篇,主要是将安装和运行代码做了一次真机实验,亲测可用.文章内包含的脚本和代码,多来自于网络,也有我自己的调整和配置,文章末尾对参考的文献做了列举,方便 ...

  10. Java反射机制详情(2)

    | |目录 运行环境 Java语言的反射机制 Class中的常用方法(获得类的构造方法) Class中的常用方法(获得类的属性) Class中的常用方法(获得类的方法) 反射动态调用类的成员 1.运行 ...