新手学习FFmpeg - 通过API实现可控的Filter调用链
虽然通过声明[x][y]avfilter=a=x:b=y;avfilter=xxx
的方式可以创建一个可用的Filter
调用链,并且在绝大多数场合下这种方式都是靠谱和实用的。 但如果想精细化
的管理AVFilter
调用链,例如根据某些条件来动态生成AVFilter Graph
。这种声明方式就不太灵活(也可以通过if判断来动态组装字符串,如果你非常喜欢这种字符串声明方式,到此为止不在建议你往下阅读了)。
首先快速温习一下,如何创建一个AVFilter Graph
。
+-------+ +---------------------+ +---------------+
|buffer | |Filter ..... Filter N| | buffersink |
----------> | |output|------>|input| |output|---> |input| |-------->
+-------+ +---------------------+ +---------------+
创建三部曲:
- 初始化
buffer
和buffersink
。 - 初始化其它filter
- 设定Filter Graph的Input和Output。
其中buffer
和buffersink
分别代表Graph
的起始和结束。
然后快速封装args
也就是movie=t.png[wm];[in][wm]overlay=10:20[out]
这样的filter-complex命令。 而且通过avfilter_graph_parse_ptr
完成中间filter的初始化,
最后指定各个filter的input和output,一个graph就算搞定了。
好,下面来看如何通过API精细化
生成AVFilter Graph
。 生成下面的Graph:
+-------+ +---------------------+ +---------------+
|buffer | | Filter | | buffersink |
----------> | |output|------>|input| Fade |output|---> |input| |-------->
+-------+ +---------------------+ +---------------+
首先初始化各个AVFilter。所有的AVFilter的初始化都可以简化为两步操作:
- 通过
avfilter_get_by_name
查找指定的AVFilter - 通过
avfilter_graph_create_filter
初始化AVFilterContext
同AVcodec
和AVCodecContext
的关系一样, 所有的AVFilter的执行都依靠对应的AVFilterContext(在ffmpeg开发中,每个组件都会对应一个上下文管理器,由这个上下文管理器封装各种参数然后调用组件执行)。
通过avfilter_get_by_name
生成AVFilter实例之后,紧跟着就需要调用avfilter_graph_create_filter
初始化上下文管理器。
按照下面的流程,依次初始化三个AVFilter:
buffer_src = avfilter_get_by_name("buffer");
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffer_src, "in", args, NULL, filter_graph);
这里重点聊一下avfilter_graph_create_filter
。 下面是函数原型:
int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt,
const char *name, const char *args, void *opaque,
AVFilterGraph *graph_ctx);
filt_ctx表示这个AVFilter的上下文管理器。
name表明的是AVFilter在Graph中的名称,这个名称叫啥不重要但必须唯一。 例如Fade AVFilter
就可以叫做fade1
,fade2
或者ifade
等等。
args则是这个AVFilter的参数, 注意仅仅是这个AVFilter的参数,不是整个graph的参数。再拿Fade
举例,args就可以是t=in:st=3:d=3
。
opaque一般给NULL就可以了。
初始完这三个AVFilter之后,就进入到本次文档的重点: avfilter_link
.
int avfilter_link( AVFilterContext * src,
unsigned srcpad,
AVFilterContext * dst,
unsigned dstpad
)
avfilter_link
分别用来链接两个AVFilter(传说中的一手托两家)。 src
和dst
分别表示源Filter和目标Filter。 srcpad
表示src
第N个输出端, dstpad
表示dst
第N个输入端。 如果不好理解,直接看下面的图:
+-------------+ +-------------+
| src srcpad 1 -----> dstpad 3 dst |
| srcpad 2 -----> dstpad 2 |
| srcpad 3 -----> dstpad 1 |
+-------------+ +-------------+
上图假设src
和dst
分别有三个输出端和三个输入端(不是所有avfilter都有这么多的输入输出端,像fade只有一个,但overlay就有多个)。
而srcpad
和dstpad
表示的就是输出/输入端的序号。假如将buffer
第一个输出端对应fade
第一个输入端。 那么就应该这么写:
avfilter_link(buffersrc_ctx, 0, ifade_ctx, 0);
然后将fade
的第一个输出端对应buffersink
的输入端,就这么写:
avfilter_link(ifade_ctx, 0, buffersink_ctx, 0);
而所谓的精细化
就是在这里体现的,通过代码的逻辑判断,可以动态的组合不同的AVFilter
生成不同的Filter Graph
。并且还可以组合不同的输入/输出端。
本次代码示例可以参考ifilter
。同时也可以参考 ffmpeg-go-server(一个尝试为ffmpeg提供restful API的web server)。
新手学习FFmpeg - 通过API实现可控的Filter调用链的更多相关文章
- 新手学习FFmpeg - 通过API完成filter-complex功能
本篇尝试通过API实现Filter Graph功能. 源码请参看 https://andy-zhangtao.github.io/ffmpeg-examples/ FFmpeg提供了很多实用且强大的滤 ...
- 新手学习FFmpeg - 调用API完成录屏
调用FFMPEG Device API完成Mac录屏功能. 调用FFMPEG提供的API来完成录屏功能,大致的思路是: 打开输入设备. 打开输出设备. 从输入设备读取视频流,然后经过解码->编码 ...
- 新手学习FFmpeg - 调用API编写实现多次淡入淡出效果的滤镜
前面几篇文章聊了聊FFmpeg的基础知识,我也是接触FFmpeg不久,除了时间处理之外,很多高深(滤镜)操作都没接触到.在学习时间处理的时候,都是通过在ffmpeg目前提供的avfilter基础上面修 ...
- 新手学习FFmpeg - 调用API完成录屏并进行H.264编码
Screen Record H.264 目前在网络传输视频/音频流都一般会采用H.264进行编码,所以尝试调用FFMPEG API完成Mac录屏功能,同时编码为H.264格式. 在上一篇文章中,通过调 ...
- 新手学习FFmpeg - 调用API完成视频的读取和输出
在写了几个avfilter之后,原本以为对ffmpeg应该算是入门了. 结果今天想对一个视频文件进行转码操作,才发现基本的视频读取,输出都搞不定. 痛定思痛,仔细研究了一下ffmpeg提供的examp ...
- 新手学习FFmpeg - 调用API调整视频局部速率
通过修改setpts代码实现调整视频部分的播放速率. 完整代码可参考: https://andy-zhangtao.github.io/ffmpeg-examples/ 在前面提到了PTS/DTS/T ...
- 新手学习FFmpeg - 调用API完成两个视频的任意合并
本次尝试在视频A中的任意位置插入视频B. 在上一篇中,我们通过调整PTS可以实现视频的加减速.这只是对同一个视频的调转,本次我们尝试对多个视频进行合并处理. Concat如何运行 ffmpeg提供了一 ...
- 新手学习FFmpeg - 调用API计算关键帧渲染时间点
通过简单的计算来,线上I帧在视频中出现的时间点. 完整代码请参考 https://andy-zhangtao.github.io/ffmpeg-examples/ 名词解释 首先需要明确以下名词概念: ...
- 新手学习FFmpeg - 如何编写Kubernetes资源文件
Kubernetes API的使用方式 Kubernetes API属于声明式API编程, 它和常用的命令式编程有一些区别. 通俗的说,命令式编程是第一人称,我要做什么,我要怎么做. 操作系统最喜欢这 ...
随机推荐
- ionic app 优化三件套,让其更贴近原生app
这里推荐一个ionic大神的简书,里面有好多关于好多ionic的技术分享! http://www.jianshu.com/u/c2e637a941ef 捣鼓了好久的ionic,终于在优化过程终于有所进 ...
- sql建表经验总结——主要是建表现象
在建表方面你都有哪些感悟? 见过的建表的一些现象: 1,一对多业务,有时候在主表见一个字段xxIds,然后存多表的id,多个英文逗号隔开,不知道这样好不好? 2,大部分字段建成varchar(50), ...
- 大型互联网公司分布式ID方案总结
ID是数据的唯一标识,传统的做法是利用UUID和数据库的自增ID,在互联网企业中,大部分公司使用的都是Mysql,并且因为需要事务支持,所以通常会使用Innodb存储引擎,UUID太长以及无序,所以并 ...
- centos安装oracle11g
1.1 安装依赖,创建用户和目录 参考http://www.cnblogs.com/gaojun/archive/2012/11/22/2783257.html yum -y install binu ...
- 实参&形参
实参VS形参 1.实参 argument 实际参数,在函数调用的时候,传递给函数的参数.实参-按值调用 实际参数可以是变量.常量.表达式以及函数 实际参数必须得有确定的值(赋值.输入等),在函数调用时 ...
- codeforces 765 D. Artsem and Saunder(数学题)
题目链接:http://codeforces.com/contest/765/problem/D 题意:题目中给出你两个公式,g(h(x))==x,h(g(x))==f(x).现给你f(x) 让你求符 ...
- java hdu A+B for Input-Output Practice (IV)
A+B for Input-Output Practice (IV) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/327 ...
- MAC下安装REDIS和REDIS可视化工具RDM并连接REDIS
实验环境:一台mac V:10.13.6 一.安装redis brew install redis 二.安装RDM 直接下载安装rdm dmg文件 链接: https://pan.baidu.com/ ...
- Fortify安全漏洞一般处理方法
前段时间公司又一轮安全审查,要求对各项目进行安全扫描,排查漏洞并修复,手上有几个历史项目,要求在限定的时间内全部修复并提交安全报告,也不清楚之前是如何做的漏洞修复,这次使用工具扫描出来平均每个项目都还 ...
- 小程序 请求Promise简单封装
最近做小程序在调用后台接口的时候感觉总写很长一串,很冗杂.非常想念vue中promise封装的写法,于是自己初步封装了一下. 1.url 接口地址 2.headers请求头 3. params 请求参 ...