FFMPEG官网给出了FFMPEG 滤镜使用的实例,它是将视频中的像素点替换成字符,然后从终端输出。我在该实例的基础上稍微的做了修改,使它能够保存滤镜处理过后的文件。在上代码之前先明白几个概念:

Filter:代表单个filter 
    FilterPad:代表一个filter的输入或输出端口,每个filter都可以有多个输入和多个输出,只有输出pad的filter称为source,只有输入pad的filter称为sink 
    FilterLink:若一个filter的输出pad和另一个filter的输入pad名字相同,即认为两个filter之间建立了link 
    FilterChain:代表一串相互连接的filters,除了source和sink外,要求每个filter的输入输出pad都有对应的输出和输入pad

经典示例:

图中的一系列操作共使用了四个filter,分别是 
    splite:将输入的流进行分裂复制,分两路输出。 
    crop:根据给定的参数,对视频进行裁剪 
    vflip:根据给定参数,对视频进行翻转等操作 
    overlay:将一路输入覆盖到另一路之上,合并输出为一路视频

下面上代码:

  1. /*=============================================================================
  2. #     FileName: filter_video.c
  3. #         Desc: an example of ffmpeg fileter
  4. #       Author: licaibiao
  5. #   LastChange: 2017-03-16
  6. =============================================================================*/
  7. #define _XOPEN_SOURCE 600 /* for usleep */
  8. #include <unistd.h>
  9. #include "avcodec.h"
  10. #include "avformat.h"
  11. #include "avfiltergraph.h"
  12. #include "avcodec.h"
  13. #include "buffersink.h"
  14. #include "buffersrc.h"
  15. #include "opt.h"
  16. #define SAVE_FILE
  17. const charchar *filter_descr = "scale=iw*2:ih*2";
  18. static AVFormatContext *fmt_ctx;
  19. static AVCodecContext *dec_ctx;
  20. AVFilterContext *buffersink_ctx;
  21. AVFilterContext *buffersrc_ctx;
  22. AVFilterGraph *filter_graph;
  23. static int video_stream_index = -1;
  24. static int64_t last_pts = AV_NOPTS_VALUE;
  25. static int open_input_file(const charchar *filename)
  26. {
  27. int ret;
  28. AVCodec *dec;
  29. if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
  30. av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
  31. return ret;
  32. }
  33. if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
  34. av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
  35. return ret;
  36. }
  37. /* select the video stream  判断流是否正常 */
  38. ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
  39. if (ret < 0) {
  40. av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
  41. return ret;
  42. }
  43. video_stream_index = ret;
  44. dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
  45. av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0); /* refcounted_frames 帧引用计数 */
  46. /* init the video decoder */
  47. if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
  48. av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
  49. return ret;
  50. }
  51. return 0;
  52. }
  53. static int init_filters(const charchar *filters_descr)
  54. {
  55. char args[512];
  56. int ret = 0;
  57. AVFilter *buffersrc  = avfilter_get_by_name("buffer");     /* 输入buffer filter */
  58. AVFilter *buffersink = avfilter_get_by_name("buffersink"); /* 输出buffer filter */
  59. AVFilterInOut *outputs = avfilter_inout_alloc();
  60. AVFilterInOut *inputs  = avfilter_inout_alloc();
  61. AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;   /* 时间基数 */
  62. #ifndef SAVE_FILE
  63. enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
  64. #else
  65. enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
  66. #endif
  67. filter_graph = avfilter_graph_alloc();                     /* 创建graph  */
  68. if (!outputs || !inputs || !filter_graph) {
  69. ret = AVERROR(ENOMEM);
  70. goto end;
  71. }
  72. /* buffer video source: the decoded frames from the decoder will be inserted here. */
  73. snprintf(args, sizeof(args),
  74. "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
  75. dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
  76. time_base.num, time_base.den,
  77. dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
  78. /* 创建并向FilterGraph中添加一个Filter */
  79. ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
  80. args, NULL, filter_graph);
  81. if (ret < 0) {
  82. av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
  83. goto end;
  84. }
  85. /* buffer video sink: to terminate the filter chain. */
  86. ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
  87. NULL, NULL, filter_graph);
  88. if (ret < 0) {
  89. av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
  90. goto end;
  91. }
  92. /* Set a binary option to an integer list. */
  93. ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
  94. AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
  95. if (ret < 0) {
  96. av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
  97. goto end;
  98. }
  99. /*
  100. * Set the endpoints for the filter graph. The filter_graph will
  101. * be linked to the graph described by filters_descr.
  102. */
  103. /*
  104. * The buffer source output must be connected to the input pad of
  105. * the first filter described by filters_descr; since the first
  106. * filter input label is not specified, it is set to "in" by
  107. * default.
  108. */
  109. outputs->name       = av_strdup("in");
  110. outputs->filter_ctx = buffersrc_ctx;
  111. outputs->pad_idx    = 0;
  112. outputs->next       = NULL;
  113. /*
  114. * The buffer sink input must be connected to the output pad of
  115. * the last filter described by filters_descr; since the last
  116. * filter output label is not specified, it is set to "out" by
  117. * default.
  118. */
  119. inputs->name       = av_strdup("out");
  120. inputs->filter_ctx = buffersink_ctx;
  121. inputs->pad_idx    = 0;
  122. inputs->next       = NULL;
  123. /* Add a graph described by a string to a graph */
  124. if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
  125. &inputs, &outputs, NULL)) < 0)
  126. goto end;
  127. /* Check validity and configure all the links and formats in the graph */
  128. if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
  129. goto end;
  130. end:
  131. avfilter_inout_free(&inputs);
  132. avfilter_inout_free(&outputs);
  133. return ret;
  134. }
  135. #ifndef SAVE_FILE
  136. static void display_frame(const AVFrame *frame, AVRational time_base)
  137. {
  138. int x, y;
  139. uint8_t *p0, *p;
  140. int64_t delay;
  141. if (frame->pts != AV_NOPTS_VALUE) {
  142. if (last_pts != AV_NOPTS_VALUE) {
  143. /* sleep roughly the right amount of time;
  144. * usleep is in microseconds, just like AV_TIME_BASE. */
  145. /* 计算 pts 是用来把时间戳从一个时基调整到另外一个时基时候用的函数 */
  146. delay = av_rescale_q(frame->pts - last_pts,
  147. time_base, AV_TIME_BASE_Q);
  148. if (delay > 0 && delay < 1000000)
  149. usleep(delay);
  150. }
  151. last_pts = frame->pts;
  152. }
  153. /* Trivial ASCII grayscale display. */
  154. p0 = frame->data[0];
  155. puts("\033c");
  156. for (y = 0; y < frame->height; y++) {
  157. p = p0;
  158. for (x = 0; x < frame->width; x++)
  159. putchar(" .-+#"[*(p++) / 52]);
  160. putchar('\n');
  161. p0 += frame->linesize[0];
  162. }
  163. fflush(stdout);
  164. }
  165. #else
  166. FILEFILE * file_fd;
  167. static void write_frame(const AVFrame *frame)
  168. {
  169. static int printf_flag = 0;
  170. if(!printf_flag){
  171. printf_flag = 1;
  172. printf("frame widht=%d,frame height=%d\n",frame->width,frame->height);
  173. if(frame->format==AV_PIX_FMT_YUV420P){
  174. printf("format is yuv420p\n");
  175. }
  176. else{
  177. printf("formet is = %d \n",frame->format);
  178. }
  179. }
  180. fwrite(frame->data[0],1,frame->width*frame->height,file_fd);
  181. fwrite(frame->data[1],1,frame->width/2*frame->height/2,file_fd);
  182. fwrite(frame->data[2],1,frame->width/2*frame->height/2,file_fd);
  183. }
  184. #endif
  185. int main(int argc, charchar **argv)
  186. {
  187. int ret;
  188. AVPacket packet;
  189. AVFrame *frame = av_frame_alloc();
  190. AVFrame *filt_frame = av_frame_alloc();
  191. int got_frame;
  192. #ifdef SAVE_FILE
  193. file_fd = fopen("test.yuv","wb+");
  194. #endif
  195. if (!frame || !filt_frame) {
  196. perror("Could not allocate frame");
  197. exit(1);
  198. }
  199. if (argc != 2) {
  200. fprintf(stderr, "Usage: %s file\n", argv[0]);
  201. exit(1);
  202. }
  203. av_register_all();
  204. avfilter_register_all();
  205. if ((ret = open_input_file(argv[1])) < 0)
  206. goto end;
  207. if ((ret = init_filters(filter_descr)) < 0)
  208. goto end;
  209. /* read all packets */
  210. while (1) {
  211. if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
  212. break;
  213. if (packet.stream_index == video_stream_index) {
  214. got_frame = 0;
  215. ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, &packet);
  216. if (ret < 0) {
  217. av_log(NULL, AV_LOG_ERROR, "Error decoding video\n");
  218. break;
  219. }
  220. if (got_frame) {
  221. frame->pts = av_frame_get_best_effort_timestamp(frame);    /* pts: Presentation Time Stamp */
  222. /* push the decoded frame into the filtergraph */
  223. if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
  224. av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
  225. break;
  226. }
  227. /* pull filtered frames from the filtergraph */
  228. while (1) {
  229. ret = av_buffersink_get_frame(buffersink_ctx, filt_frame);
  230. if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
  231. break;
  232. if (ret < 0)
  233. goto end;
  234. #ifndef SAVE_FILE
  235. display_frame(filt_frame, buffersink_ctx->inputs[0]->time_base);
  236. #else
  237. write_frame(filt_frame);
  238. #endif
  239. av_frame_unref(filt_frame);
  240. }
  241. /* Unreference all the buffers referenced by frame and reset the frame fields. */
  242. av_frame_unref(frame);
  243. }
  244. }
  245. av_packet_unref(&packet);
  246. }
  247. end:
  248. avfilter_graph_free(&filter_graph);
  249. avcodec_close(dec_ctx);
  250. avformat_close_input(&fmt_ctx);
  251. av_frame_free(&frame);
  252. av_frame_free(&filt_frame);
  253. if (ret < 0 && ret != AVERROR_EOF) {
  254. fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
  255. exit(1);
  256. }
  257. #ifdef SAVE_FILE
  258. fclose(file_fd);
  259. #endif
  260. exit(0);
  261. }

该工程中,我的Makefile文件如下:

  1. OUT_APP      = test
  2. INCLUDE_PATH = /usr/local/include/
  3. INCLUDE = -I$(INCLUDE_PATH)libavutil/ -I$(INCLUDE_PATH)libavdevice/ \
  4. -I$(INCLUDE_PATH)libavcodec/ -I$(INCLUDE_PATH)libswresample \
  5. -I$(INCLUDE_PATH)libavfilter/ -I$(INCLUDE_PATH)libavformat \
  6. -I$(INCLUDE_PATH)libswscale/
  7. FFMPEG_LIBS = -lavformat -lavutil -lavdevice -lavcodec -lswresample -lavfilter -lswscale
  8. SDL_LIBS    =
  9. LIBS        = $(FFMPEG_LIBS)$(SDL_LIBS)
  10. COMPILE_OPTS = $(INCLUDE)
  11. C            = c
  12. OBJ          = o
  13. C_COMPILER   = cc
  14. C_FLAGS      = $(COMPILE_OPTS) $(CPPFLAGS) $(CFLAGS)
  15. LINK         = cc -o
  16. LINK_OPTS    = -lz -lm  -lpthread
  17. LINK_OBJ     = test.o
  18. .$(C).$(OBJ):
  19. $(C_COMPILER) -c $(C_FLAGS) $<
  20. $(OUT_APP): $(LINK_OBJ)
  21. $(LINK)$@  $(LINK_OBJ)  $(LIBS) $(LINK_OPTS)
  22. clean:
  23. -rm -rf *.$(OBJ) $(OUT_APP) core *.core *~ *yuv

运行结果如下:

  1. licaibiao@ubuntu:~/test/FFMPEG/filter$ ls
  2. Makefile  school.flv  test  test.c  test.o
  3. licaibiao@ubuntu:~/test/FFMPEG/filter$ ./test school.flv
  4. [flv @ 0x12c16c0] video stream discovered after head already parsed
  5. [flv @ 0x12c16c0] audio stream discovered after head already parsed
  6. frame widht=1024,frame height=576
  7. format is yuv420p
  8. licaibiao@ubuntu:~/test/FFMPEG/filter$ ls
  9. Makefile  school.flv  test  test.c  test.o  test.yuv

在这里,我打印出来了输出视频的格式和图片的长和宽,该实例生成的是一个YUV420 格式的视频,使用YUV播放器播放视频的时候,需要设置正确的视频长度和宽度。在代码中通过设置enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };来设置输出格式。

过滤器的参数设置是通过const char *filter_descr = "scale=iw*2:ih*2"; 来设置。它表示将视频的长和框都拉伸到原来的两倍。具体的filter参数可以通过命令:ffmpeg -filters 来查询。结果如下:

  1. Filters:
  2. T.. = Timeline support
  3. .S. = Slice threading
  4. ..C = Command support
  5. A = Audio input/output
  6. V = Video input/output
  7. N = Dynamic number and/or type of input/output
  8. | = Source or sink filter
  9. ... abench            A->A       Benchmark part of a filtergraph.
  10. ... acompressor       A->A       Audio compressor.
  11. ... acrossfade        AA->A      Cross fade two input audio streams.
  12. ... acrusher          A->A       Reduce audio bit resolution.
  13. .............................................................................

在上面的代码中,我们设置的是将图片拉升到原来图像的两倍,其显示效果如下,可能是截图的问题,这里看好像没有拉伸到两倍。

原图

拉伸后

在上面的代码中,我们设置的是:

const char *filter_descr = "scale=iw*2:ih*2";   iw 表示输入视频的宽,ih表示输入视频的高。可以任意比例的缩放视频。这里*2 表示放大两倍,如果是/2表示缩小两倍。

视频缩放还可以直接设置:

const char *filter_descr = "scale=320:240"; 设置视频输出宽为320,高位240,当然也是可以随意的设置其他的参数。

视频的裁剪可以设置为:

const char *filter_descr = "crop=320:240:0:0";   具体含义是 crop=width:height:x:y,其中 width 和 height 表示裁剪后的尺寸,x:y 表示裁剪区域的左上角坐标。

视频添加一个网格水印可以设置为:

const char *filter_descr = "drawgrid=width=100:height=100:thickness=2:color=red@0.5";    具体含义是 width 和 height 表示添加网格的宽和高,thickness表示网格的线宽,color表示颜色 。其效果如下:

更多filter参数的使用,可以直接参考ffmpeg 的官方文档:http://www.ffmpeg.org/ffmpeg-filters.html

FFMPEG 最简滤镜filter使用实例(实现视频缩放,裁剪,水印等)的更多相关文章

  1. FFMPEG基于内存的转码实例——输入输出视频均在内存

    我在6月份写了篇文章<FFMPEG基于内存的转码实例>,讲如何把视频转码后放到内存,然后通过网络发送出去.但该文章只完成了一半,即输入的数据依然是从磁盘文件中读取.在实际应用中,有很多数据 ...

  2. (转)FFMPEG filter使用实例(实现视频缩放,裁剪,水印等)

    本文转载自http://blog.csdn.net/li_wen01/article/details/62442162 FFMPEG官网给出了FFMPEG 滤镜使用的实例,它是将视频中的像素点替换成字 ...

  3. FFMpeg ver 20160219-git-98a0053 滤镜中英文对照 2016.02.21 by 1CM

    FFMpeg ver 20160219-git-98a0053 滤镜中英文对照 2016.02.21 by 1CM T.. = Timeline support 支持时间轴 .S. = Slice t ...

  4. FFMpeg ver 20160213-git-588e2e3 滤镜中英文对照

    1 FFMpeg ver 20160213-git-588e2e3 滤镜中英文对照 2016.02.18 by 1CM 2 T.. = Timeline support 3 支持时间轴 4 .S. = ...

  5. ffmpeg入门篇-滤镜的基本使用

    转发自白狼栈:查看原文 滤镜 什么是滤镜?百度百科介绍说"滤镜主要是用来实现图像的各种特殊效果......". 我们最早在ffmpeg是如何转码的一文中了解过滤镜,来回顾下当时的转 ...

  6. FFmpeg frei0r water 滤镜

    FFmpeg frei0r water 滤镜, 在 linux 环境中很流畅,但在 XP 环境中抛出异常 研究一段时间修改了代码,能在 XP 里跑得动. sample.water.avi water. ...

  7. 兼容ie8 rgba()用法 滤镜filter的用法

    原文  http://blog.csdn.net/westernranger/article/details/40836861 今天遇到了一个问题,要在一个页面中设置一个半透明的白色div.这个貌似不 ...

  8. 在ie中用滤镜 (filter:progid:DXImageTransform.Microsoft.gradient)会触发overflow:hidden?

    1.在ie中用滤镜 (filter:progid:DXImageTransform.Microsoft.gradient)会触发overflow:hidden 在项目中做一个背景层透明内容(菜单)不透 ...

  9. CSS3的滤镜filter属性

    css3的滤镜filter属性,可以对网页中的图片进行类似Photoshop图片处理的效果,例如背景的毛玻璃效果.老照片(黑白照片).火焰效果等. 一.blur(px)高斯模糊 二.brightnes ...

随机推荐

  1. Linux进程间通信(一) - 管道

    管道(pipe) 普通的Linux shell都允许重定向,而重定向使用的就是管道. 例如:ps | grep vsftpd .管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准 ...

  2. 如何更好的利用Node.js的性能极限

    通过使用非阻塞.事件驱动的I/O操作,Node.js为构建和运行大规模网络应用及服务提供了很好的平台,也受到了广泛的欢迎.其主要特性表现为能够处理庞大的并且高吞吐量的并发连接,从而构建高性能.高扩展性 ...

  3. socket java 实例

    简单的java socket 示例 一.搭建服务器端 a).创建ServerSocket对象绑定监听端口. b).通过accept()方法监听客户端的请求. c).建立连接后,通过输入输出流读取客户端 ...

  4. 九度OJ 1205:N阶楼梯上楼问题 (斐波那契数列)

    时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:3739 解决:1470 题目描述: N阶楼梯上楼问题:一次可以走两阶或一阶,问有多少种上楼方式.(要求采用非递归) 输入: 输入包括一个整 ...

  5. flex (html弹性布局)

    flex是什么? 任何容器都可以指定为flex布局: .box{ display: flex;  /* 行内元素可以使用:inline-flex,webket内核浏览器必须 -webkit-flex ...

  6. netbeans无法新建项目

    在ubuntu上安装netbeans最新版(7.3.1),但是安装之后发现无法新建项目,一直提示请等待,google之后说是jdk的问题,查看了一下jdk的版本为1.6.试着安装了1.7版本的,问题解 ...

  7. 使用OpenSSL工具制作X.509证书的方法及其注意事项总结

    版权声明:本文为博主原创文章.转载请注明出处. https://blog.csdn.net/Ping_Fani07/article/details/21622545 怎样使用OpenSSL工具生成根证 ...

  8. (转)jquery $.proxy的使用

    在某些情况下,我们调用Javascript函数时候,this指针并不一定是我们所期望的那个.例如: 1 //正常的this使用 2 $('#myElement').click(function() { ...

  9. Apache Shiro 使用手册(三)Shiro 授权(转发:http://kdboy.iteye.com/blog/1155450)

    授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限. 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等. 一.授权的三要素 授权有着三 ...

  10. Python字典的入门案例

    查看python版本: [root@localhost ~]# python -V Python 2.7.5 1.基本的字典操作 案例1:简单电话本实现 [root@localhost ~]# vim ...