此前libavfilter一直是结合着libavcodec等类库的接口函数使用的,因此我一直以为libavfilter库与libavcodec等类库是高度耦合的(也就是如果想使用libavfilter的视音频特效功能的话必须使用libavcodec等类库的函数)。这两天空闲的时候研究了一下libavfilter的代码后发现实际情况不是这样的:libavfilter可以独立于libavcodec等类库的接口函数作为一个“纯粹”的视音频特效类库进行使用。本文记录的“纯净版”的avfilter的例子即实现了一个纯粹的视频特效添加的功能。该例子输入为一个YUV文件,输出也是一个YUV文件,通过avfilter的功能可以处理该YUV文件实现去色调、模糊、水平翻转、裁剪、加方框、叠加文字等功能。

流程图

该程序的流程图如下所示。AVFilter的初始化比较复杂,而使用起来比较简单。初始化的时候需要调用avfilter_register_all()到avfilter_graph_config()一系列函数。而使用的时候只有两个函数:av_buffersrc_add_frame()用于向FilterGraph中加入一个AVFrame,而av_buffersink_get_frame()用于从FilterGraph中取出一个AVFrame。

流程中的关键函数如下所示:

avfilter_register_all():注册所有AVFilter。

avfilter_graph_alloc():为FilterGraph分配内存。

avfilter_graph_create_filter():创建并向FilterGraph中添加一个Filter。

avfilter_graph_parse_ptr():将一串通过字符串描述的Graph添加到FilterGraph中。

avfilter_graph_config():检查FilterGraph的配置。

av_buffersrc_add_frame():向FilterGraph中加入一个AVFrame。

av_buffersink_get_frame():从FilterGraph中取出一个AVFrame。

代码

/**  * 最简单的基于FFmpeg的AVFilter例子 - 纯净版 * Simplest FFmpeg AVfilter Example - Pure * * 雷霄骅 Lei Xiaohua * leixiaohua1020@126.com * 中国传媒大学/数字电视技术 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 *  * 本程序使用FFmpeg的AVfilter实现了YUV像素数据的滤镜处理功能。 * 可以给YUV数据添加各种特效功能。 * 是最简单的FFmpeg的AVFilter方面的教程。 * 适合FFmpeg的初学者。 * * This software uses FFmpeg's AVFilter to process YUV raw data. * It can add many excellent effect to YUV data. * It's the simplest example based on FFmpeg's AVFilter.  * Suitable for beginner of FFmpeg  * */#include  #define __STDC_CONSTANT_MACROS #ifdef _WIN32#define snprintf _snprintf//Windowsextern "C"{#include "libavfilter/avfiltergraph.h"#include "libavfilter/buffersink.h"#include "libavfilter/buffersrc.h"#include "libavutil/avutil.h"#include "libavutil/imgutils.h"};#else//Linux...#ifdef __cplusplusextern "C"{#endif#include #include #include #include #include #ifdef __cplusplus};#endif#endif    int main(int argc, char* argv[]){    int ret;    AVFrame *frame_in;AVFrame *frame_out;unsigned char *frame_buffer_in;unsigned char *frame_buffer_out; AVFilterContext *buffersink_ctx;AVFilterContext *buffersrc_ctx;AVFilterGraph *filter_graph;static int video_stream_index = -1; //Input YUVFILE *fp_in=fopen("sintel_480x272_yuv420p.yuv","rb+");if(fp_in==NULL){printf("Error open input file.");return -1;}int in_width=480;int in_height=272; //Output YUVFILE *fp_out=fopen("output.yuv","wb+");if(fp_out==NULL){printf("Error open output file.");return -1;} //const char *filter_descr = "lutyuv='u=128:v=128'";const char *filter_descr = "boxblur";//const char *filter_descr = "hflip";//const char *filter_descr = "hue='h=60:s=-3'";//const char *filter_descr = "crop=2/3*in_w:2/3*in_h";//const char *filter_descr = "drawbox=x=100:y=100:w=100:h=100:color=pink@0.5";//const char *filter_descr = "drawtext=fontfile=arial.ttf:fontcolor=green:fontsize=30:text='Lei Xiaohua'";avfilter_register_all(); char args[512];AVFilter *buffersrc  = avfilter_get_by_name("buffer");AVFilter *buffersink = avfilter_get_by_name("ffbuffersink");AVFilterInOut *outputs = avfilter_inout_alloc();AVFilterInOut *inputs  = avfilter_inout_alloc();enum PixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, PIX_FMT_NONE };AVBufferSinkParams *buffersink_params; filter_graph = avfilter_graph_alloc(); /* buffer video source: the decoded frames from the decoder will be inserted here. */snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",in_width,in_height,AV_PIX_FMT_YUV420P,1, 25,1,1); ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",args, NULL, filter_graph);if (ret < 0) {printf("Cannot create buffer source");return ret;} /* buffer video sink: to terminate the filter chain. */buffersink_params = av_buffersink_params_alloc();buffersink_params->pixel_fmts = pix_fmts;ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",NULL, buffersink_params, filter_graph);av_free(buffersink_params);if (ret < 0) {printf("Cannot create buffer sink");return ret;} /* Endpoints for the filter graph. */outputs->name       = av_strdup("in");outputs->filter_ctx = buffersrc_ctx;outputs->pad_idx    = 0;outputs->next       = NULL; inputs->name       = av_strdup("out");inputs->filter_ctx = buffersink_ctx;inputs->pad_idx    = 0;inputs->next       = NULL; if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_descr,&inputs, &outputs, NULL)) < 0)return ret; if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)return ret; frame_in=av_frame_alloc();frame_buffer_in=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, in_width,in_height,1));av_image_fill_arrays(frame_in->data, frame_in->linesize,frame_buffer_in,AV_PIX_FMT_YUV420P,in_width, in_height,1); frame_out=av_frame_alloc();frame_buffer_out=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, in_width,in_height,1));av_image_fill_arrays(frame_out->data, frame_out->linesize,frame_buffer_out,AV_PIX_FMT_YUV420P,in_width, in_height,1); frame_in->width=in_width;frame_in->height=in_height;frame_in->format=AV_PIX_FMT_YUV420P;    while (1) { if(fread(frame_buffer_in, 1, in_width*in_height*3/2, fp_in)!= in_width*in_height*3/2){break;}//input Y,U,Vframe_in->data[0]=frame_buffer_in;frame_in->data[1]=frame_buffer_in+in_width*in_height;frame_in->data[2]=frame_buffer_in+in_width*in_height*5/4;         if (av_buffersrc_add_frame(buffersrc_ctx, frame_in) < 0) {            printf( "Error while add frame.");            break;        }         /* pull filtered pictures from the filtergraph */ret = av_buffersink_get_frame(buffersink_ctx, frame_out);        if (ret < 0)            break; //output Y,U,Vif(frame_out->format==AV_PIX_FMT_YUV420P){for(int i=0;iheight;i++){fwrite(frame_out->data[0]+frame_out->linesize[0]*i,1,frame_out->width,fp_out);}for(int i=0;iheight/2;i++){fwrite(frame_out->data[1]+frame_out->linesize[1]*i,1,frame_out->width/2,fp_out);}for(int i=0;iheight/2;i++){fwrite(frame_out->data[2]+frame_out->linesize[2]*i,1,frame_out->width/2,fp_out);}}printf("Process 1 frame!");av_frame_unref(frame_out);    } fclose(fp_in);fclose(fp_out); av_frame_free(&frame_in);av_frame_free(&frame_out);    avfilter_graph_free(&filter_graph);     return 0;}

结果

本程序输入为一个名称为“sintel_480x272_yuv420p.yuv”的YUV420P视频数据,输出为一个名称为“output.yuv” 的YUV420P视频数据。输入的视频数据的内容如下所示。

程序中提供了几种特效:

lutyuv='u=128:v=128'

boxblur

hflip

hue='h=60:s=-3'

crop=2/3*in_w:2/3*in_h

drawbox=x=100:y=100:w=100:h=100:color=pink@0.5

drawtext=fontfile=arial.ttf:fontcolor=green:fontsize=30:text='Lei Xiaohua'

可以通过修改程序中的filter_descr字符串实现上述几种特效。下面展示几种特效的效果图。

lutyuv='u=128:v=128'

boxblur

hflip

hue='h=60:s=-3'

crop=2/3*in_w:2/3*in_h

drawbox=x=100:y=100:w=100:h=100:color=pink@0.5

drawtext=fontfile=arial.ttf:fontcolor=green:fontsize=30:text='Lei Xiaohua'

————————————————

版权声明:本文为CSDN博主「雷霄骅」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/leixiaohua1020/article/details/50618190

另外还有一些关于c++ Linux后台服务器开发的一些知识点分享:Linux,Nginx,MySQL,Redis,P2P,K8S,Docker,TCP/IP,协程,DPDK,webrtc,音视频等等视频。

需要的朋友可以后台私信【1】获取学习视频

c++ ffmpeg内存推流_最简单的基于FFmpeg的AVfilter的例子相关推荐

  1. 最简单的基于FFmpeg的移动端例子:Android 推流器

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  2. 最简单的基于FFmpeg的内存读写的例子:内存转码器

    ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的 ...

  3. 最简单的基于FFmpeg的内存读写的例子:内存播放器

    ===================================================== 最简单的基于FFmpeg的内存读写的例子系列文章列表: 最简单的基于FFmpeg的内存读写的 ...

  4. 最简单的基于FFmpeg的移动端例子附件:SDL Android HelloWorld

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  5. 最简单的基于FFmpeg的移动端例子:Android 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  6. 最简单的基于FFmpeg的移动端例子:Android 视频解码器-单个库版

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  7. 最简单的基于FFmpeg的移动端例子:Android HelloWorld

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  8. 最简单的基于FFmpeg的移动端样例:IOS 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...

  9. 最简单的基于FFmpeg的移动端例子:Windows Phone HelloWorld

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

最新文章

  1. SqlServer 索引
  2. echarts柱状图同一页面点击不同得按钮切换_不可思议,这个PPT居然有按钮滑动效果...
  3. c++ 常见问题之string
  4. go 分段锁ConcurrentMap,map+读写锁,sync.map的效率测试
  5. 【WebRTC---入门篇】(十八)WebRTC非音视频数据传输
  6. AutoMapper 9.0的改造(续)
  7. CI项目设计Redis队列
  8. 关于javafx支持IOS、android等智能手机解决方案
  9. mysql从库应用负载_线上MySQL数据库高负载的解决思路--再次论程序应用索引的重要性...
  10. Chromium OS 开源项目
  11. AYOJ N皇后问题
  12. 安全套接字层协议SSL
  13. UE4之vs2019IntelliSense错误
  14. 用c语言将学生系统插入音效,增加音效.cpp
  15. 牛客题库—软件测试(二)
  16. 安卓手机安装谷歌框架
  17. 【职场加油站】给职场新人的几条忠告
  18. 【Linux】一万七千字详解 —— 基本指令(二)
  19. vue获取上一个路由地址
  20. Python 如何 ping

热门文章

  1. 飞鸽传书的这一新的通信方式采用云技术
  2. 电脑操作者的养生之道
  3. C语言实现MATLAB 6.5中M文件的方法
  4. 好玩有趣,Google 首款小程序来啦!
  5. mysql双向同步读写_mysql数据双向同步
  6. 实变函数与泛函分析课本pdf_实变函数与泛函分析
  7. python中swap函数_python swap
  8. 你的数据可也可以发三篇NAR的文章
  9. 一图感受各种机器学习算法
  10. 推荐一个神器 - 把你的照片随心所欲的摆成各种形状