热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

FFmpegfilter

一、FFmpegfilter简介FFmpeg中的libavfilter提供了一整套的基于filter的机制。filter本身是一个插件的形式,可以快速的组装需要的效

一、FFmpeg filter简介

FFmpeg中的libavfilter提供了一整套的基于filter的机制。filter本身是一个插件的形式,可以快速的组装需要的效果。
比如下面的filter,可以实现视频的水平镜像效果。
ffplay.exe sample.rmvb -vf hflip

FFmpeg定义的libavcodec接口已经成为在编解码领域的事实上的行业标准。但音视频filter并没有类似的标准,多个不同的多媒体项目(比如MPlayer、Xine、GStreamer等)都实现了自定义的filter系统。为了统一filter库API接口,FFmpeg提出了参考DirectDraw实现了高质量、高效、灵活的音视频filter接口。详细的文档资料可以参考FFmpeg filter。

filter的分类

按照处理数据的类型,通常多媒体的filter分为:

·                     音频filter

·                     视频filter

·                     字幕filter

FFmpegfilter分为:

·                     source filter (只有输出)

·                     audio filter

·                     video filter

·                     Multimedia filter

·                     sink filter (只有输入)

除了source和sink filter,其他filter都至少有一个输入、至少一个输出。

介绍了这么多,下面也是一个例子,使用filter实现宽高减半显示:

ffplay.exe sample.rmvb -vf scale=iw/2:ih/2

FFmpeg filter可以认为是一些预定义的范式,可以实现类似积木的多种功能的自由组合。每个filter都有固定数目的输入和输出,而且实际使用中不允许有空悬的输入输出端。使用文本描述时我们可以通过标识符指定输入和输出端口,将不同filter串联起来,构成更复杂的filter。这就形成了嵌套的filter。当然每个filter可以通过ffmpeg/ffplay命令行实现,但通常filter更方便。

ffmpeg.exe、ffplay.exe能够通过filter处理原始的音视频数据。ffmpeg将filtergraph分为simple filtergraph和complex filtergraph。通常simple filtergraph只有一个输入和输出,ffmpeg命令行中使用-vf、-af识别,基本原理图如下:

_________ ______________| | | || decoded | | encoded data || frames |\ _ | packets ||_________| \ /||______________|\ __________ /simple _\|| | / encoderfiltergraph | filtered |/| frames ||__________|

complex filtergraph,通常是具有多个输入输出文件,并有多条执行路径;ffmpeg命令行中使用-lavfi-filter_complex,基本原理图如下:

_________
| |
| input 0 |\ __________
|_________| \ | |
\ _________ /| output 0 |
\ | | / |__________|_________ \| complex | /
| | | |/
| input 1 |---->| filter |\
|_________| | | \ __________
/| graph | \ | |
/ | | \| output 1 |_________ / |_________| |__________|
| | /
| input 2 |/


FFmpegfilter包含三个层次,filter->filterchain->filtergraph。具体可以参考下图:

filter syntax

filter是ffmpeg的libavfilter提供的基础单元。在同一个线性链中的filter使用逗号分隔,在不同线性链中的filter使用分号隔开,比如下面的例子:

ffmpeg -i INPUT -vf "split[main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip]overlay=0:H/2" OUTPUT

这里crop、vflip处于同一个线性链,split、overlay位于另一个线性链。二者连接通过命名的label实现(位于中括号中的是label的名字)。在上例中split filter有两个输出,依次命名为[main]和[tmp];[tmp]作为crop filter输入,之后通过vflip filter输出[flip];overlay的输入是[main]和[flilp]。如果filter需要输入参数,多个参数使用冒号分割。
对于没有音频、视频输入的filter称为source filter,没有音频、视频输出的filter称为sink filter。

经典的filter

FFmpeg支持的所有filter可以通过filters查看。
这里选几个相对经典的filter。

音频filter

adelay filter
实现不同声道的延时处理。使用参数如下adelay=1500|0|500,这个例子中实现第一个声道的延迟1.5s,第三个声道延迟0.5s,第二个声道不做调整。

aecho filter
实现回声效果,具体参考http://ffmpeg.org/ffmpeg-filters.html#aecho。

amerge filter
将多个音频流合并成一个多声道音频流。具体参考http://ffmpeg.org/ffmpeg-filters.html#amerge-1。

ashowinfo filter
显示每一个audioframe的信息,比如时间戳、位置、采样格式、采样率、采样点数等。具体参考http://ffmpeg.org/ffmpeg-filters.html#ashowinfo。

panfilter
特定声道处理,比如立体声变为单声道,或者通过特定参数修改声道或交换声道。主要有两大类:
混音处理,比如下面的例子pan=1c|c0=0.9*c0+0.1*c1,实现立体声到单声道的变换;
声道变换,比如5.1声道顺序调整,pan="5.1| c0=c1 | c1=c0| c2=c2 | c3=c3 | c4=c4 | c5=c5"。

silencedetect和silenceremove filter
根据特定参数检测静音和移除静音。

volume和volumedetect filter
这两个filter分别实现音量调整和音量检测。

audio source filter
aevalsrc filter按照特定表达式生成音频信号。
anullsrc filter生成特定的原始音频数据,用于模板或测试。
anoisesrc filter生成噪声音频信号。
sine filter生成正弦波音频信号。

audio sink filter
abuffersink filter和anullsink filter,这些filter只是用于特定情况下结束filterchain。

视频filter

blend和tblend filter
将两帧视频合并为一帧。具体参数参考http://ffmpeg.org/ffmpeg-filters.html#blend_002c-tblend。

crop filter
按照特定分辨率裁剪输入视频,具体参数参考http://ffmpeg.org/ffmpeg-filters.html#crop。

drawbox、drawgrid、drawtext filter
绘制box(对话框)、grid(表格)、text(文本)。

edgedetect filter
边缘检测filter。

fps filter
按照指定帧率输出视频帧(丢帧或者复制)。具体参考http://ffmpeg.org/ffmpeg-filters.html#fps-1。

hflip、vflip filter
水平和垂直镜像。

histogram filter
生成每帧的各颜色分量的直方图。

noise filter
在输入视频帧中添加白噪声。

overlay filter
视频叠加。具体参考http://ffmpeg.org/ffmpeg-filters.html#overlay-1。

pad filter
视频边界填充。具体参考http://ffmpeg.org/ffmpeg-filters.html#pad-1。

rotate filter
视频任意角度旋转。具体参考http://ffmpeg.org/ffmpeg-filters.html#rotate。

scale filter
使用libswscale库完成视频缩放的filter。

showinfo filter
显示视频帧的参数信息,比如时间戳、采样格式、帧类型等。

subtitles filter
使用libass库绘制subtitle(字幕)。

thumbnail filter
提取缩略图的filter。

transpose filter
图像转置的filter。参数参考http://ffmpeg.org/ffmpeg-filters.html#transpose。

source filter
主要有cellatuo、coreimagesrc、mptestsrc、life等filter,具体效果建议参考ffmpeg用户手册。

source sink
主要有buffersink、nullsink两个filter。

多媒体filter

ahistogram filter
将音频转化为视频输出,并显示为音量的直方图。

concat filter
将音频流、视频流拼接成一个。具体参考http://ffmpeg.org/ffmpeg-filters.html#concat。

metadata、ametadata filter
操作metadata信息。

setpts、asetpts filter
改变输入音频帧或视频帧的pts。

showfreqs、showspectrum、showspertrumpic、showvolume、showwaves filter
将输入音频转换为视频显示,并显示频谱、音量等信息

split、asplit filter
将输入切分为多个相同的输出。

source filter
主要是movie、amovie filter。从movie容器中读取音频或者视频帧。

为ffmpeg添加自定义滤镜
https://blog.csdn.net/xiaojun111111/article/details/50849182

二、过滤器使用流程和经常函数

基本的过滤器使用流程是:

     解码后的画面--->buffer过滤器---->其他过滤器---->buffersink过滤器--->处理完的画面

所有的过滤器形成了过滤器链,一定要的两个过滤器是buffer过滤器和buffersink过滤器,前者的作用是将解码后的画面加载到过滤器链中,后者的作用是将处理好的画面从过滤器链中读取出来。

过滤器相关的结构体:

AVFilterGraph: 管理所有的过滤器图像

AVFilterContext: 过滤器上下文

AVFilter: 过滤器

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

avfilter_register_all():注册所有AVFilter。
avfilter_graph_alloc():为FilterGraph分配内存。
avfilter_graph_create_filter():创建并向FilterGraph中添加一个Filter。
avfilter_graph_parse_ptr():将一串通过字符串描述的Graph添加到FilterGraph中。参数3,4结构中可以指定需要连接输入过滤器、输出过滤器。

avfilter_link():连接过滤器。连接输入输出过滤器。比如:

avfilter_link(filter_buffer_ctx, 0,filter_yadif_ctx, 0);avfilter_link(filter_yadif_ctx, 0,filter_buffersink_ctx, 0);

avfilter_graph_config():检查FilterGraph的配置。

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

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

三、实例

1、  ffmeg 反交错

参考:https://blog.csdn.net/crazyman2010/article/details/42913055

2、最简单的基于FFmpeg的AVfilter的例子

// test_avfilter.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"/**
* 最简单的基于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
//Windows
extern "C"
{
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/avutil.h"
#include "libavutil/imgutils.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include
#include
#include
#include
#include
#ifdef __cplusplus
};
#endif
#endif#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avfilter.lib")
#pragma comment(lib,"swscale.lib")
#pragma comment(lib,"SDL2.lib")
#pragma comment(lib,"SDL2main.lib")int main(int argc, char* argv[])
{getchar();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 &#61; -1;//Input YUVFILE *fp_in &#61; fopen("trans.yuv", "rb&#43;");if (fp_in &#61;&#61; NULL) {printf("Error open input file.\n");return -1;}int in_width &#61; 1588;int in_height &#61; 900;//Output YUVFILE *fp_out &#61; fopen("output.yuv", "wb&#43;");if (fp_out &#61;&#61; NULL) {printf("Error open output file.\n");return -1;}//const char *filter_descr &#61; "lutyuv&#61;&#39;u&#61;128:v&#61;128&#39;";//const char *filter_descr &#61; "boxblur";//const char *filter_descr &#61; "hflip";//const char *filter_descr &#61; "hue&#61;&#39;h&#61;60:s&#61;-3&#39;";//const char *filter_descr &#61; "crop&#61;2/3*in_w:2/3*in_h";//const char *filter_descr &#61; "drawbox&#61;x&#61;100:y&#61;100:w&#61;100:h&#61;100:color&#61;pink&#64;0.5";const char *filter_descr &#61; "drawtext&#61;fontfile&#61;arial.ttf:fontcolor&#61;red:fontsize&#61;30:text&#61;&#39;Lei Xiaohua&#39;:x&#61;50:y&#61;50";avfilter_register_all();char args[512];AVFilter *buffersrc &#61; avfilter_get_by_name("buffer");AVFilter *buffersink &#61; avfilter_get_by_name("buffersink");//老版本ffmpeg使用 avfilter_get_by_name("ffbuffersink")AVFilterInOut *outputs &#61; avfilter_inout_alloc();AVFilterInOut *inputs &#61; avfilter_inout_alloc();enum AVPixelFormat pix_fmts[] &#61; { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };AVBufferSinkParams *buffersink_params;filter_graph &#61; avfilter_graph_alloc();/* buffer video source: the decoded frames from the decoder will be inserted here. */snprintf(args, sizeof(args),"video_size&#61;%dx%d:pix_fmt&#61;%d:time_base&#61;%d/%d:pixel_aspect&#61;%d/%d",in_width, in_height, AV_PIX_FMT_YUV420P,1, 25, 1, 1);ret &#61; avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",args, NULL, filter_graph);if (ret <0) {printf("Cannot create buffer source\n");return ret;}/* buffer video sink: to terminate the filter chain. */buffersink_params &#61; av_buffersink_params_alloc();buffersink_params->pixel_fmts &#61; pix_fmts;ret &#61; 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\n");return ret;}/* Endpoints for the filter graph. */outputs->name &#61; av_strdup("in");outputs->filter_ctx &#61; buffersrc_ctx;outputs->pad_idx &#61; 0;outputs->next &#61; NULL;inputs->name &#61; av_strdup("out");inputs->filter_ctx &#61; buffersink_ctx;inputs->pad_idx &#61; 0;inputs->next &#61; NULL;if ((ret &#61; avfilter_graph_parse_ptr(filter_graph, filter_descr,&inputs, &outputs, NULL)) <0)return ret;if ((ret &#61; avfilter_graph_config(filter_graph, NULL)) <0)return ret;frame_in &#61; av_frame_alloc();frame_buffer_in &#61; (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 &#61; av_frame_alloc();frame_buffer_out &#61; (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 &#61; in_width;frame_in->height &#61; in_height;frame_in->format &#61; AV_PIX_FMT_YUV420P;while (1) {if (fread(frame_buffer_in, 1, in_width*in_height * 3 / 2, fp_in) !&#61; in_width*in_height * 3 / 2) {break;}//input Y,U,Vframe_in->data[0] &#61; frame_buffer_in;frame_in->data[1] &#61; frame_buffer_in &#43; in_width*in_height;frame_in->data[2] &#61; frame_buffer_in &#43; in_width*in_height * 5 / 4;if (av_buffersrc_add_frame(buffersrc_ctx, frame_in) <0) {printf("Error while add frame.\n");break;}/* pull filtered pictures from the filtergraph */ret &#61; av_buffersink_get_frame(buffersink_ctx, frame_out);if (ret <0)break;//output Y,U,Vif (frame_out->format &#61;&#61; AV_PIX_FMT_YUV420P) {for (int i &#61; 0; iheight; i&#43;&#43;) {fwrite(frame_out->data[0] &#43; frame_out->linesize[0] * i, 1, frame_out->width, fp_out);}for (int i &#61; 0; iheight / 2; i&#43;&#43;) {fwrite(frame_out->data[1] &#43; frame_out->linesize[1] * i, 1, frame_out->width / 2, fp_out);}for (int i &#61; 0; iheight / 2; i&#43;&#43;) {fwrite(frame_out->data[2] &#43; frame_out->linesize[2] * i, 1, frame_out->width / 2, fp_out);}}printf("Process 1 frame!\n");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;
}


3、最简单的基于FFmpeg的AVfilter例子&#xff08;水印叠加&#xff09;

https://blog.csdn.net/leixiaohua1020/article/details/29368911

源代码&#xff1a;https://github.com/leixiaohua1020/simplest_ffmpeg_video_filter

 四、注意事项

1、 显示文字乱码问题&#xff0c;文字需要是utf-8格式&#xff0c;字体也必须存在。

2、 调用avfilter_graph_parse_ptr解析字幕水印时返回-22&#xff0c;ffmpeg报错No suchfilter: &#39;drawtext&#39;&#xff0c;这是由于编译的时候没有开启FreeType字体引擎库&#xff0c;编译的时候./configure--enable-libfreetype。

3、 调用avfilter_graph_parse_ptr解析参数时返回-2&#xff0c;drawtext&#61;fontfile&#61;arial.ttf:fontcolor&#61;red:fontsize&#61;30:text&#61;&#39;LeiXiaohua&#39;:x&#61;50:y&#61;50里面的arial.ttf是字体文件&#xff0c;要保证字体文件在程序可以找到的目录&#xff0c;冒号在里面是分隔符&#xff0c;路径中不能带冒号。

4、 编译完ffmpeg后可能没有libpostproc.so这个库&#xff0c;编译的时候加入开启这个库的编译选项--enable-postproc。

参考资料&#xff1a;

https://www.cnblogs.com/tocy/p/ffmpeg-filter-intro.html

https://blog.csdn.net/shixin_0125/article/details/78400252


推荐阅读
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
author-avatar
gloriamm_520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有