http://blog.csdn.net/niu_gao/article/details/7219641

利用ffmpeg做图像的pixel format转换你还在用libswscale吗?嘿嘿,过时啦!
ffmpeg中有了新东西:libavfilter.使用它,可以完全代替libswscale,并且可以自动完成一些复杂的转换操作呢.libavfilter啊,用了都说好!但就是太复杂...
如果你仅仅是做图像的pixel format处理,用libswscale是相当简单,可以看看最新的ffplay.c中的代码,被#if
CONFIG_AVFILTER #endif包围的代码量非常大,而且让人一上来看得一头雾水,但为了赶潮流,我们还是得学习它啊...
先弄清楚avfilter中的几个相关的概念(注意:如果没有directShow基础的同学看不懂以下解释,请先学DirectShow的基本概念):
1 AVFilterGraph:几乎完全等同与directShow中的fitlerGraph,代表一串连接起来的filter们.
AVFilter:代表一个filter.
AVFilterPad:代表一个filter的输入或输出口,等同于DShow中的Pin.只有输出pad的filter叫source,只有输入pad的tilter叫sink.
AVFilterLink:代表两个连接的fitler之间的粘合物.
其实总体看起来,libavfitler跟DShow几乎一样了.

下面看一下AVFilter是如何被使用的,我们以ffplay.c为例吧,分析一下其中AVFilter相关的代码.
1 产生graph:
AVFilterGraph *graph = avfilter_graph_alloc();
2 创建source
AVFilterContext *filt_src;
avfilter_graph_create_filter(&filt_src, &input_filter, "src",NULL, is, graph);
第一个参数是生成的filter(是一个source),第二个参数是一个AVFilter结构的实例,第三个参数是要创建的fitler的名字,第四个
参数是不知道什么用,第五个参数是user
data(调用者的私有数据),第六个参数是graph的指针.其中第二个参数的实例必须由调用者自己实现,才能将帧送到graph中.
3 创建sink
AVFilterContext *filt_out;
ret = avfilter_graph_create_filter(&filt_out, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts, graph);
参数同上,不解释.所创建的这个sink是一个buffersink,可参考libavfitler的源码文件sink_buffer.c看看它是个什么
玩意.sink_buffer其实是一个能通过buffer输出帧的sink,当然它的输出不是通过pad,因为它后面没有fitler了.用它做
sink,可以让使用这个graph的代码轻松取得graph处理后的帧.
4 连接source和sink
avfilter_link(filt_src, 0, filt_out, 0);
第一个参数是接在前面的filter,第二个参数是前fitler的要连接的pad的序号,第三个参数是后面的filter,第四个参数是后filter的要连接的pad.
4 对graph做最后的检查
avfilter_graph_config(graph, NULL);
我们是从sink中取出处理完成的帧,所以最好把sink的引用保存下来,比如:
AVFilterContext *out_video_filter=filt_out;
6实现input_filter

由于input_filter是个source,所以只为它分配output pad,并且只有一个pad.

  1. static AVFilter input_filter =
  2. {
  3. .name      = "ffplay_input",
  4. .priv_size = sizeof(FilterPriv),
  5. .init      = input_init,
  6. .uninit    = input_uninit,
  7. .query_formats = input_query_formats,
  8. .inputs    = (AVFilterPad[]) {{ .name = NULL }},
  9. .outputs   = (AVFilterPad[]) {{ .name = "default",
  10. .type = AVMEDIA_TYPE_VIDEO,
  11. .request_frame = input_request_frame,
  12. .config_props  = input_config_props, },
  13. { .name = NULL }},
  14. };

再实现AVFilter的回调函数们:init()和uninit()--用于初始化/销毁所用到的资源.
看一下ffplay.c中的实现:

  1. static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
  2. {
  3. FilterPriv *priv = ctx->priv;
  4. AVCodecContext *codec;
  5. if(!opaque) return -1;
  6. priv->is = opaque;
  7. codec    = priv->is->video_st->codec;
  8. codec->opaque = ctx;
  9. if((codec->codec->capabilities & CODEC_CAP_DR1)) {
  10. av_assert0(codec->flags & CODEC_FLAG_EMU_EDGE);
  11. priv->use_dr1 = 1;
  12. codec->get_buffer     = input_get_buffer;
  13. codec->release_buffer = input_release_buffer;
  14. codec->reget_buffer   = input_reget_buffer;
  15. codec->thread_safe_callbacks = 1;
  16. }
  17. priv->frame = avcodec_alloc_frame();
  18. return 0;
  19. }

FilterPriv是ffplay实现的filter(也就是input_filter)的私有数据结构.主要的工作是分配了一个AVFrame,用于保存从设备取得的帧.uninit()更简单,就不用看了.
还需实现output pad的request_frame(),才能使input_filter后面的filter获取到帧

  1. static int input_request_frame(AVFilterLink *link)
  2. {
  3. FilterPriv *priv = link->src->priv;
  4. AVFilterBufferRef *picref;
  5. int64_t pts = 0;
  6. AVPacket pkt;
  7. int ret;
  8. while (!(ret = get_video_frame(priv->is, priv->frame, &pts, &pkt)))
  9. av_free_packet(&pkt);
  10. if (ret < 0)
  11. return -1;
  12. if(priv->use_dr1 && priv->frame->opaque) {
  13. picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
  14. } else {
  15. picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
  16. av_image_copy(picref->data, picref->linesize,
  17. priv->frame->data, priv->frame->linesize,
  18. picref->format, link->w, link->h);
  19. }
  20. av_free_packet(&pkt);
  21. avfilter_copy_frame_props(picref, priv->frame);
  22. picref->pts = pts;
  23. avfilter_start_frame(link, picref);
  24. avfilter_draw_slice(link, 0, link->h, 1);
  25. avfilter_end_frame(link);
  26. return 0;
  27. }

调用者从sink中获取处理后的帧:
av_buffersink_get_buffer_ref(filt_out, &picref, 0);
获取后的帧保存在picref中.这个函数会引起graph中的filter从后向前依次调用上一个filter的outpad的
request_frame(),最后调用到source的request_frame(),也就是
input_request_frame(),input_request_frame()调用get_video_frame()(见
ffplay.c)从设备获取一帧(可能需要解码),然后将这帧数据复制到picref中,filter们处理的帧是用
AVFilterBufferRef表示的.然后将帧的一些属性也复制到picref中,最后调用avfilter_start_frame(link,
picref);avfilter_draw_slice(link, 0, link->h,
1);avfilter_end_frame(link);来处理这一帧.这三个函数对应着pad上的三个函数指
针:start_frame,draw_slice,end_frame.以start_frame为例,其调用过程是这样的:首先是source的
start_frame被调用,做一些必要的处理后,再调用连接到source之后的filter的start_frame.每个filter的
output pad都负责在这个函数中向下传递这个调用.当sink调用完start_frame()时再一层层返回到source的output
pad.当这三个函数都被source的output pad调用完成后,这一帧的最终结果就出来了.于是可以用sink上获得.
与DShow比较起来,avfilter没有那些推模式,拉模式的概念,没有在source的output pad上实现线程,整个graph的运转都是由调用者驱动.

ffmpeg的新东东:AVFilter的更多相关文章

  1. SQLSERVER 里经常看到的CACHE STORES是神马东东?

    SQLSERVER 里经常看到的CACHE STORES是神马东东? 当我们在SSMS里执行下面的SQL语句清空SQLSERVER的缓存的时候,我们会在SQL ERRORLOG里看到一些信息 DBCC ...

  2. 在JS中,一切东东其实都是对象

    对象是组成JavaScript的基本单元,在JS中,一切东东其实都是对象,而且功能非常强大,它不仅风格独特,功能也与众不同. 一.引用(reference) 引用的概念是JS的基础之一,它是指向对象实 ...

  3. C++ 中可调用的且有函数功能的东东

    第一个:函数     其实函数在声明的时候都有个名字: 这个名字可以看作是是指针,将其直接赋值给函数指针 也可以看作是可取指的对其& 再赋值给函数指针 第二个:函数指针   通过其被赋值的方式 ...

  4. json是个啥东东

    xml 不用说 只要是搞web开发的 没听说谁不知道的 一种类似数据传输格式定义的语言 但是他却不是一个真正的轻量级的东西 其他的不说 只要传输一点很少的数据 经过他那左括号右括号 还有什么属性 一包 ...

  5. 长见识了,知道了collected和Graphite 这两个东东

    今天下午的讨论会议中,听到了两个名词collected和Graphite这是神马东东,以前在bingo的时候也没听说过,开完会下去查了下.原来他两是监控系统的啊.以前也从来没做过系统监控方面的项目,这 ...

  6. BPEL是个什么东东

    研究团队有个做智能服务组合的,其中用到叫BPEL的东西,因为全称是Business Process Execution Language,译成中文就是商业执行过程语言,这个东东的是整合SOA的一个执行 ...

  7. 【UVA 1151】 Buy or Build (有某些特别的东东的最小生成树)

    [题意] 平面上有n个点(1<=N<=1000),你的任务是让所有n个点连通,为此,你可以新建一些边,费用等于两个端点的欧几里得距离的平方. 另外还有q(0<=q<=8)个套餐 ...

  8. JSNI GWT中的东东

    二.JavaScript Native InterfaceJavaScript本地接口JSNI.1)声明一个本地方法在JSNI中声明一个本地方法时,使用Java的标准native关键字,就像在JNI( ...

  9. Lambda 表达式 是 个 好东东

    Lambda 表达式 是 个 好东东 首先,通过 Lambda 表达式 + 动态语言特性 dynamic , C# 已经 可以 实现 函数式 编程 了 其次, 利用 Lambda, 可以 实现 AOP ...

  10. 页面生命周期里面还有很东西,如PageHandlerFactory等等这些东东也够吃一壶的,发现每走到一个领域,发现要学的东西实在是太多太多啦,总感觉自己所学的东西只是沧海一粟,走过了这道坎,又是一片海洋,我只能呐喊:生命永不止息,学海无涯----够用就好。

    页面生命周期里面还有很东西,如PageHandlerFactory等等这些东东也够吃一壶的,发现每走到一个领域,发现要学的东西实在是太多太多啦,总感觉自己所学的东西只是沧海一粟,走过了这道坎,又是一片 ...

随机推荐

  1. ZOJ 3872 Beauty of Array【无重复连续子序列的贡献和/规律/DP】

    Edward has an array A with N integers. He defines the beauty of an array as the summation of all dis ...

  2. 洛谷——P1190 接水问题

    P1190 接水问题 题目描述 学校里有一个水房,水房里一共装有 m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 1. 现在有 n 名同学准备接水,他们的初始接水顺序已经确定.将这些同学 ...

  3. shell脚本报错退出

    在shell脚本中,比如有以下的代码: cd /root/test88 rm -rf  backup 如果目录/root/test88不存在,脚本不会停止,依然会执行rm -rf backup这个命令 ...

  4. 反编译apk 修改 合成

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 反编译apk帮助文档 准备工具 dex2jar(dex转换jar工具),下载地址: ht ...

  5. 进阶的Redis之哈希分片原理与集群实战

    前面介绍了<进阶的Redis之数据持久化RDB与AOF>和<进阶的Redis之Sentinel原理及实战>,这次来了解下Redis的集群功能,以及其中哈希分片原理. 集群分片模 ...

  6. 为什么fis没有freemarker的解决方案啊?_前端吧_百度贴吧

    为什么fis没有freemarker的解决方案啊?_前端吧_百度贴吧 fis-plus:适用于PHP+Smarty后端选型jello:适用于Java+Velocity后端选型goiz:适用于go+ma ...

  7. 【荐】利用NAT、Host-Only双虚拟网卡,实现Virtual Box中CentOS5.x联网

    一.虚拟机与主机互联,通常有三种方式,详细介绍请看: VMware虚拟机三种网络模式(Bridged,Nat,Host-only)区别详解 二.通过网络共享,Host-Only联网,详细案例请看: W ...

  8. 【POI】解析xls报错:java.util.zip.ZipException: error in opening zip file

    今天使用POI解析XLS,报错如下: Servlet.service() for servlet [rest] in context with path [/cetBrand] threw excep ...

  9. VMware8安装MacOS 10.8

    前一篇博客,介绍了如何利用VMware安装MacOS系统,虽然可以安装成功,但也有不友好的地方,如: 1)MacOS系统文件需要是ISO格式,不是原生的dmg格式: 2)每次开机都需要借助HJMac工 ...

  10. PostgreSQL配置文件--日志和错误

    6 错误操作和日志 ERROR REPORTING AND LOGGING 6.1 日志写到哪里 Where to Log 6.1.1 log_destination 字符串 默认: log_dest ...