音视频流媒体开发-目录
ffmpeg的filter⽤起来是和Gstreamer的plugin是⼀样的概念,通过avfilter_link,将各个创建好的filter按⾃⼰想要的次序链接到⼀起,然后avfilter_graph_config之后,就可以正常使⽤。
⽐较常⽤的滤镜有:scale、trim、overlay、rotate、movie、yadif。scale 滤镜⽤于缩放,trim 滤镜⽤于帧级剪切,overlay 滤镜⽤于视频叠加,rotate 滤镜实现旋转,movie 滤镜可以加载第三⽅的视频,
1 主要结构体和API介绍
AVFilterGraph-对filters系统的整体管理
重点
struct AVFilterGraph
{
AVFilterContext **filters;
unsigned nb_filters;
}
完整结构体
// 对filters系统的整体管理
typedef struct AVFilterGraph {
const AVClass *av_class;
AVFilterContext **filters;
unsigned nb_filters;
char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters
#if FF_API_LAVR_OPTS
attribute_deprecated char *resample_lavr_opts; ///< libavresample options to use for the auto-inserted resample filters
#endif
/**
* Type of multithreading allowed for filters in this graph. A combination
* of AVFILTER_THREAD_* flags.
*
* May be set by the caller at any point, the setting will apply to all
* filters initialized after that. The default is allowing everything.
*
* When a filter in this graph is initialized, this field is combined using
* bit AND with AVFilterContext.thread_type to get the final mask used for
* determining allowed threading types. I.e. a threading type needs to be
* set in both to be allowed.
*/
int thread_type;
/**
* Maximum number of threads used by filters in this graph. May be set by
* the caller before adding any filters to the filtergraph. Zero (the
* default) means that the number of threads is determined automatically.
*/
int nb_threads;
/**
* Opaque object for libavfilter internal use.
*/
AVFilterGraphInternal *internal;
/**
* Opaque user data. May be set by the caller to an arbitrary value, e.g. to
* be used from callbacks like @ref AVFilterGraph.execute.
* Libavfilter will not touch this field in any way.
*/
void *opaque;
/**
* This callback may be set by the caller immediately after allocating the
* graph and before adding any filters to it, to provide a custom
* multithreading implementation.
*
* If set, filters with slice threading capability will call this callback
* to execute multiple jobs in parallel.
*
* If this field is left unset, libavfilter will use its internal
* implementation, which may or may not be multithreaded depending on the
* platform and build options.
*/
avfilter_execute_func *execute;
char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions
/**
* Private fields
*
* The following fields are for internal use only.
* Their type, offset, number and semantic can change without notice.
*/
AVFilterLink **sink_links;
int sink_links_count;
unsigned disable_auto_convert;
} AVFilterGraph;
AVFilter-定义filter本身的能⼒
重点
const char *name; // overlay
const AVFilterPad *inputs;
const AVFilterPad *outputs;
⽐如:
1 AVFilter ff_vf_overlay = {
2 .name = "overlay",
3 .description = NULL_IF_CONFIG_SMALL("Overlay a video source ontop of the input."),
4 .preinit = overlay_framesync_preinit,
5 .init = init,
6 .uninit = uninit,
7 .priv_size = sizeof(OverlayContext),
8 .priv_class = &overlay_class,
9 .query_formats = query_formats,
10 .activate = activate,
11 .process_command = process_command,
12 .inputs = avfilter_vf_overlay_inputs,
13 .outputs = avfilter_vf_overlay_outputs,
14 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
15 AVFILTER_FLAG_SLICE_THREADS,
16 };
// 定义filter本身的能⼒,拥有的pads,回调函数接⼝定义
/**
* Filter definition. This defines the pads a filter contains, and all the
* callback functions used to interact with the filter.
*/
typedef struct AVFilter {
/**
* Filter name. Must be non-NULL and unique among filters.
*/
const char *name;
/**
* A description of the filter. May be NULL.
*
* You should use the NULL_IF_CONFIG_SMALL() macro to define it.
*/
const char *description;
/**
* List of inputs, terminated by a zeroed element.
*
* NULL if there are no (static) inputs. Instances of filters with
* AVFILTER_FLAG_DYNAMIC_INPUTS set may have more inputs than present in
* this list.
*/
const AVFilterPad *inputs;
/**
* List of outputs, terminated by a zeroed element.
*
* NULL if there are no (static) outputs. Instances of filters with
* AVFILTER_FLAG_DYNAMIC_OUTPUTS set may have more outputs than present in
* this list.
*/
const AVFilterPad *outputs;
/**
* A class for the private data, used to declare filter private AVOptions.
* This field is NULL for filters that do not declare any options.
*
* If this field is non-NULL, the first member of the filter private data
* must be a pointer to AVClass, which will be set by libavfilter generic
* code to this class.
*/
const AVClass *priv_class;
/**
* A combination of AVFILTER_FLAG_*
*/
int flags;
/*****************************************************************
* All fields below this line are not part of the public API. They
* may not be used outside of libavfilter and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
/**
* Filter pre-initialization function
*
* This callback will be called immediately after the filter context is
* allocated, to allow allocating and initing sub-objects.
*
* If this callback is not NULL, the uninit callback will be called on
* allocation failure.
*
* @return 0 on success,
* AVERROR code on failure (but the code will be
* dropped and treated as ENOMEM by the calling code)
*/
int (*preinit)(AVFilterContext *ctx);
/**
* Filter initialization function.
*
* This callback will be called only once during the filter lifetime, after
* all the options have been set, but before links between filters are
* established and format negotiation is done.
*
* Basic filter initialization should be done here. Filters with dynamic
* inputs and/or outputs should create those inputs/outputs here based on
* provided options. No more changes to this filter's inputs/outputs can be
* done after this callback.
*
* This callback must not assume that the filter links exist or frame
* parameters are known.
*
* @ref AVFilter.uninit "uninit" is guaranteed to be called even if
* initialization fails, so this callback does not have to clean up on
* failure.
*
* @return 0 on success, a negative AVERROR on failure
*/
int (*init)(AVFilterContext *ctx);
/**
* Should be set instead of @ref AVFilter.init "init" by the filters that
* want to pass a dictionary of AVOptions to nested contexts that are
* allocated during init.
*
* On return, the options dict should be freed and replaced with one that
* contains all the options which could not be processed by this filter (or
* with NULL if all the options were processed).
*
* Otherwise the semantics is the same as for @ref AVFilter.init "init".
*/
int (*init_dict)(AVFilterContext *ctx, AVDictionary **options);
/**
* Filter uninitialization function.
*
* Called only once right before the filter is freed. Should deallocate any
* memory held by the filter, release any buffer references, etc. It does
* not need to deallocate the AVFilterContext.priv memory itself.
*
* This callback may be called even if @ref AVFilter.init "init" was not
* called or failed, so it must be prepared to handle such a situation.
*/
void (*uninit)(AVFilterContext *ctx);
/**
* Query formats supported by the filter on its inputs and outputs.
*
* This callback is called after the filter is initialized (so the inputs
* and outputs are fixed), shortly before the format negotiation. This
* callback may be called more than once.
*
* This callback must set AVFilterLink.out_formats on every input link and
* AVFilterLink.in_formats on every output link to a list of pixel/sample
* formats that the filter supports on that link. For audio links, this
* filter must also set @ref AVFilterLink.in_samplerates "in_samplerates" /
* @ref AVFilterLink.out_samplerates "out_samplerates" and
* @ref AVFilterLink.in_channel_layouts "in_channel_layouts" /
* @ref AVFilterLink.out_channel_layouts "out_channel_layouts" analogously.
*
* This callback may be NULL for filters with one input, in which case
* libavfilter assumes that it supports all input formats and preserves
* them on output.
*
* @return zero on success, a negative value corresponding to an
* AVERROR code otherwise
*/
int (*query_formats)(AVFilterContext *);
int priv_size; ///< size of private data to allocate for the filter
int flags_internal; ///< Additional flags for avfilter internal use only.
/**
* Used by the filter registration system. Must not be touched by any other
* code.
*/
struct AVFilter *next;
/**
* Make the filter instance process a command.
*
* @param cmd the command to process, for handling simplicity all commands must be alphanumeric only
* @param arg the argument for the command
* @param res a buffer with size res_size where the filter(s) can return a response. This must not change when the command is not supported.
* @param flags if AVFILTER_CMD_FLAG_FAST is set and the command would be
* time consuming then a filter should treat it like an unsupported command
*
* @returns >=0 on success otherwise an error code.
* AVERROR(ENOSYS) on unsupported commands
*/
int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags);
/**
* Filter initialization function, alternative to the init()
* callback. Args contains the user-supplied parameters, opaque is
* used for providing binary data.
*/
int (*init_opaque)(AVFilterContext *ctx, void *opaque);
/**
* Filter activation function.
*
* Called when any processing is needed from the filter, instead of any
* filter_frame and request_frame on pads.
*
* The function must examine inlinks and outlinks and perform a single
* step of processing. If there is nothing to do, the function must do
* nothing and not return an error. If more steps are or may be
* possible, it must use ff_filter_set_ready() to schedule another
* activation.
*/
int (*activate)(AVFilterContext *ctx);
} AVFilter;
AVFilterContext-filter实例,管理filter与外部的联系
// filter实例,管理filter与外部的联系
重点
struct AVFilterContext
{
const AVFilter *filter;
char *name;
AVFilterPad *input_pads;
AVFilterLink **inputs;
unsigned nb_inputs
AVFilterPad *output_pads;
AVFilterLink **outputs;
unsigned nb_outputs;
struct AVFilterGraph *graph; // 从属于哪个AVFilterGraph
}
完整结构体
/** An instance of a filter */
struct AVFilterContext {
const AVClass *av_class; ///< needed for av_log() and filters common options
const AVFilter *filter; ///< the AVFilter of which this is an instance
char *name; ///< name of this filter instance
AVFilterPad *input_pads; ///< array of input pads
AVFilterLink **inputs; ///< array of pointers to input links
unsigned nb_inputs; ///< number of input pads
AVFilterPad *output_pads; ///< array of output pads
AVFilterLink **outputs; ///< array of pointers to output links
unsigned nb_outputs; ///< number of output pads
void *priv; ///< private data for use by the filter
struct AVFilterGraph *graph; ///< filtergraph this filter belongs to
/**
* Type of multithreading being allowed/used. A combination of
* AVFILTER_THREAD_* flags.
*
* May be set by the caller before initializing the filter to forbid some
* or all kinds of multithreading for this filter. The default is allowing
* everything.
*
* When the filter is initialized, this field is combined using bit AND with
* AVFilterGraph.thread_type to get the final mask used for determining
* allowed threading types. I.e. a threading type needs to be set in both
* to be allowed.
*
* After the filter is initialized, libavfilter sets this field to the
* threading type that is actually used (0 for no multithreading).
*/
int thread_type;
/**
* An opaque struct for libavfilter internal use.
*/
AVFilterInternal *internal;
struct AVFilterCommand *command_queue;
char *enable_str; ///< enable expression string
void *enable; ///< parsed expression (AVExpr*)
double *var_values; ///< variable values for the enable expression
int is_disabled; ///< the enabled state from the last expression evaluation
/**
* For filters which will create hardware frames, sets the device the
* filter should create them in. All other filters will ignore this field:
* in particular, a filter which consumes or processes hardware frames will
* instead use the hw_frames_ctx field in AVFilterLink to carry the
* hardware context information.
*/
AVBufferRef *hw_device_ctx;
/**
* Max number of threads allowed in this filter instance.
* If <= 0, its value is ignored.
* Overrides global number of threads set per filter graph.
*/
int nb_threads;
/**
* Ready status of the filter.
* A non-0 value means that the filter needs activating;
* a higher value suggests a more urgent activation.
*/
unsigned ready;
/**
* Sets the number of extra hardware frames which the filter will
* allocate on its output links for use in following filters or by
* the caller.
*
* Some hardware filters require all frames that they will use for
* output to be defined in advance before filtering starts. For such
* filters, any hardware frame pools used for output must therefore be
* of fixed size. The extra frames set here are on top of any number
* that the filter needs internally in order to operate normally.
*
* This field must be set before the graph containing this filter is
* configured.
*/
int extra_hw_frames;
};
AVFilterLink-定义两个filters之间的联接
重点
struct AVFilterLink
{
AVFilterContext *src;
AVFilterPad *srcpad;
AVFilterContext *dst;
AVFilterPad *dstpad;
struct AVFilterGraph *graph;
}
完整结构体
/**
* A link between two filters. This contains pointers to the source and
* destination filters between which this link exists, and the indexes of
* the pads involved. In addition, this link also contains the parameters
* which have been negotiated and agreed upon between the filter, such as
* image dimensions, format, etc.
*
* Applications must not normally access the link structure directly.
* Use the buffersrc and buffersink API instead.
* In the future, access to the header may be reserved for filters
* implementation.
*/
struct AVFilterLink {
AVFilterContext *src; ///< source filter
AVFilterPad *srcpad; ///< output pad on the source filter
AVFilterContext *dst; ///< dest filter
AVFilterPad *dstpad; ///< input pad on the dest filter
enum AVMediaType type; ///< filter media type
/* These parameters apply only to video */
int w; ///< agreed upon image width
int h; ///< agreed upon image height
AVRational sample_aspect_ratio; ///< agreed upon sample aspect ratio
/* These parameters apply only to audio */
uint64_t channel_layout; ///< channel layout of current buffer (see libavutil/channel_layout.h)
int sample_rate; ///< samples per second
int format; ///< agreed upon media format
/**
* Define the time base used by the PTS of the frames/samples
* which will pass through this link.
* During the configuration stage, each filter is supposed to
* change only the output timebase, while the timebase of the
* input link is assumed to be an unchangeable property.
*/
AVRational time_base;
/*****************************************************************
* All fields below this line are not part of the public API. They
* may not be used outside of libavfilter and can be changed and
* removed at will.
* New public fields should be added right above.
*****************************************************************
*/
/**
* Lists of formats and channel layouts supported by the input and output
* filters respectively. These lists are used for negotiating the format
* to actually be used, which will be loaded into the format and
* channel_layout members, above, when chosen.
*
*/
AVFilterFormats *in_formats;
AVFilterFormats *out_formats;
/**
* Lists of channel layouts and sample rates used for automatic
* negotiation.
*/
AVFilterFormats *in_samplerates;
AVFilterFormats *out_samplerates;
struct AVFilterChannelLayouts *in_channel_layouts;
struct AVFilterChannelLayouts *out_channel_layouts;
/**
* Audio only, the destination filter sets this to a non-zero value to
* request that buffers with the given number of samples should be sent to
* it. AVFilterPad.needs_fifo must also be set on the corresponding input
* pad.
* Last buffer before EOF will be padded with silence.
*/
int request_samples;
/** stage of the initialization of the link properties (dimensions, etc) */
enum {
AVLINK_UNINIT = 0, ///< not started
AVLINK_STARTINIT, ///< started, but incomplete
AVLINK_INIT ///< complete
} init_state;
/**
* Graph the filter belongs to.
*/
struct AVFilterGraph *graph;
/**
* Current timestamp of the link, as defined by the most recent
* frame(s), in link time_base units.
*/
int64_t current_pts;
/**
* Current timestamp of the link, as defined by the most recent
* frame(s), in AV_TIME_BASE units.
*/
int64_t current_pts_us;
/**
* Index in the age array.
*/
int age_index;
/**
* Frame rate of the stream on the link, or 1/0 if unknown or variable;
* if left to 0/0, will be automatically copied from the first input
* of the source filter if it exists.
*
* Sources should set it to the best estimation of the real frame rate.
* If the source frame rate is unknown or variable, set this to 1/0.
* Filters should update it if necessary depending on their function.
* Sinks can use it to set a default output frame rate.
* It is similar to the r_frame_rate field in AVStream.
*/
AVRational frame_rate;
/**
* Buffer partially filled with samples to achieve a fixed/minimum size.
*/
AVFrame *partial_buf;
/**
* Size of the partial buffer to allocate.
* Must be between min_samples and max_samples.
*/
int partial_buf_size;
/**
* Minimum number of samples to filter at once. If filter_frame() is
* called with fewer samples, it will accumulate them in partial_buf.
* This field and the related ones must not be changed after filtering
* has started.
* If 0, all related fields are ignored.
*/
int min_samples;
/**
* Maximum number of samples to filter at once. If filter_frame() is
* called with more samples, it will split them.
*/
int max_samples;
/**
* Number of channels.
*/
int channels;
/**
* Link processing flags.
*/
unsigned flags;
/**
* Number of past frames sent through the link.
*/
int64_t frame_count_in, frame_count_out;
/**
* A pointer to a FFFramePool struct.
*/
void *frame_pool;
/**
* True if a frame is currently wanted on the output of this filter.
* Set when ff_request_frame() is called by the output,
* cleared when a frame is filtered.
*/
int frame_wanted_out;
/**
* For hwaccel pixel formats, this should be a reference to the
* AVHWFramesContext describing the frames.
*/
AVBufferRef *hw_frames_ctx;
#ifndef FF_INTERNAL_FIELDS
/**
* Internal structure members.
* The fields below this limit are internal for libavfilter's use
* and must in no way be accessed by applications.
*/
char reserved[0xF000];
#else /* FF_INTERNAL_FIELDS */
/**
* Queue of frames waiting to be filtered.
*/
FFFrameQueue fifo;
/**
* If set, the source filter can not generate a frame as is.
* The goal is to avoid repeatedly calling the request_frame() method on
* the same link.
*/
int frame_blocked_in;
/**
* Link input status.
* If not zero, all attempts of filter_frame will fail with the
* corresponding code.
*/
int status_in;
/**
* Timestamp of the input status change.
*/
int64_t status_in_pts;
/**
* Link output status.
* If not zero, all attempts of request_frame will fail with the
* corresponding code.
*/
int status_out;
#endif /* FF_INTERNAL_FIELDS */
};
AVFilterPad-定义filter的输⼊/输出接⼝
// 定义filter的输⼊/输出接⼝
重点
struct AVFilterPad
{
const char *name;
AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);
AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
int (*filter_frame)(AVFilterLink *link, AVFrame *frame);
int (*request_frame)(AVFilterLink *link);
}
完整结构体
1 /**
2 * A filter pad used for either input or output.
3 */
4 struct AVFilterPad {
5 /**
6 * Pad name. The name is unique among inputs and among outputs,but an
7 * input may have the same name as an output. This may be NULL if this
8 * pad has no need to ever be referenced by name.
9 */
10 const char *name;
11
12 /**
13 * AVFilterPad type.
14 */
15 enum AVMediaType type;
16
17 /**
18 * Callback function to get a video buffer. If NULL, the filter system will
19 * use ff_default_get_video_buffer().
20 *
21 * Input video pads only.
22 */
23 AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);
24
25 /**
26 * Callback function to get an audio buffer. If NULL, the filter system will
27 * use ff_default_get_audio_buffer().
28 *
29 * Input audio pads only.
30 */
31 AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
32
33 /**
34 * Filtering callback. This is where a filter receives a frame with
35 * audio/video data and should do its processing.
36 *
37 * Input pads only.
38 *
39 * @return >= 0 on success, a negative AVERROR on error. This function
40 * must ensure that frame is properly unreferenced on error if it
41 * hasn't been passed on to another filter.
42 */
43 int (*filter_frame)(AVFilterLink *link, AVFrame *frame);
44
45 /**
46 * Frame poll callback. This returns the number of immediately available
47 * samples. It should return a positive value if the next request_frame()
48 * is guaranteed to return one frame (with no delay).
49 *
50 * Defaults to just calling the source poll_frame() method.
51 *
52 * Output pads only.
53 */
54 int (*poll_frame)(AVFilterLink *link);
55
56 /**
57 * Frame request callback. A call to this should result in some progress
58 * towards producing output over the given link. This should return zero
59 * on success, and another value on error.
60 *
61 * Output pads only.
62 */
63 int (*request_frame)(AVFilterLink *link);
24
64
65 /**
66 * Link configuration callback.
67 *
68 * For output pads, this should set the link properties such as
69 * width/height. This should NOT set the format property - that is
70 * negotiated between filters by the filter system using the
71 * query_formats() callback before this function is called.
72 *
73 * For input pads, this should check the properties of the link,and update
74 * the filter's internal state as necessary.
75 *
76 * For both input and output filters, this should return zero on success,
77 * and another value on error.
78 */
79 int (*config_props)(AVFilterLink *link);
80
81 /**
82 * The filter expects a fifo to be inserted on its input link,
83 * typically because it has a delay.
84 *
85 * input pads only.
86 */
87 int needs_fifo;
88
89 /**
90 * The filter expects writable frames from its input link,
91 * duplicating data buffers if needed.
92 *
93 * input pads only.
94 */
95 int needs_writable;
96 };
AVFilterInOut-过滤器链输⼊/输出的链接列表
/**
* A linked-list of the inputs/outputs of the filter chain.
*
* This is mainly useful for avfilter_graph_parse() / avfilter_graph_parse2(),
* where it is used to communicate open (unlinked) inputs and outputs from and
* to the caller.
* This struct specifies, per each not connected pad contained in the graph, the
* filter context and the pad index required for establishing a link.
*/
typedef struct AVFilterInOut {
/** unique name for this input/output in the list */
char *name;
/** filter context associated to this input/output */
AVFilterContext *filter_ctx;
/** index of the filt_ctx pad to use for linking */
int pad_idx;
/** next input/input in the list, NULL if this is the last */
struct AVFilterInOut *next;
} AVFilterInOut;
在AVFilter模块中定义了AVFilter结构,很个AVFilter都是具有独⽴功能的节点,如scale filter的作⽤就是进⾏图像尺⼨变换,overlay filter的作⽤就是进⾏图像的叠加。
这⾥需要重点提的是两个特别的filter,⼀个是buffer,⼀个是buffersink,
- 滤波器buffer代表filter graph中的源头,原始数据就往这个filter节点输⼊的;
- ⽽滤波器buffersink代表filter graph中的输出节点,处理完成的数据从这个filter节点输出。
2 函数使⽤
// 获取FFmpeg中定义的filter,调⽤该⽅法前需要先调⽤avfilter_register_all();进⾏滤波器注册
AVFilter avfilter_get_by_name(const char name);
// 往源滤波器buffer中输⼊待处理的数据
int av_buffersrc_add_frame(AVFilterContext ctx, AVFrame frame);
// 从⽬的滤波器buffersink中获取处理完的数据
int av_buffersink_get_frame(AVFilterContext ctx, AVFrame frame);
// 创建⼀个滤波器图filter graph
AVFilterGraph *avfilter_graph_alloc(void);
// 创建⼀个滤波器实例AVFilterContext,并添加到AVFilterGraph中
int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt,const char name, const char args, void *opaque,AVFilterGraph *graph_ctx);
// 连接两个滤波器节点
int avfilter_link(AVFilterContext *src, unsigned srcpad,
AVFilterContext *dst, unsigned dstpad);
3 AVFilter主体框架流程
在利⽤AVFilter进⾏⾳视频数据处理前先将在进⾏的处理流程绘制出来,现在以FFmpeg filter官⽅⽂档中
的⼀个例⼦为例进⾏说明。
1 [main]
2 input --> split ---------------------> overlay --> output
3 | ^
4 |[tmp] [flip]|
5 +-----> crop --> vflip -------+
这个例⼦的处理流程如上所示,⾸先使⽤split滤波器将input流分成两路流(main和tmp),然后分别对两路流进⾏处理。对于tmp流,先经过crop滤波器进⾏裁剪处理,再经过flip滤波器进⾏垂直⽅向上的翻转操作,输出的结果命名为flip流。再将main流和flip流输⼊到overlay滤波器进⾏合成操作。上图的input就是
上⾯提过的buffer源滤波器,output就是上⾯的提过的buffersink滤波器。上图中每个节点都是⼀个AVFilterContext,每个连线就是AVFliterLink。所有这些信息都统⼀由AVFilterGraph来管理。
案例1-视频过滤器:video-watermark
.pro
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.c
win32 {
INCLUDEPATH += $$PWD/ffmpeg-4.2.1-win32-dev/include
LIBS += $$PWD/ffmpeg-4.2.1-win32-dev/lib/avformat.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/avcodec.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/avdevice.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/avfilter.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/avutil.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/postproc.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/swresample.lib \
$$PWD/ffmpeg-4.2.1-win32-dev/lib/swscale.lib
}
main.c
#include
#include
#include
//#include
#include
#include
#include
#include
#include
int main(int argc, char* argv)
{
int ret = 0;
// input yuv
FILE* inFile = NULL;
const char* inFileName = "768x320.yuv";
fopen_s(&inFile, inFileName, "rb+");
if (!inFile) {
printf("Fail to open file\n");
return -1;
}
int in_width = 768;
int in_height = 320;
// output yuv
FILE* outFile = NULL;
const char* outFileName = "out_crop_vfilter.yuv";
fopen_s(&outFile, outFileName, "wb");
if (!outFile) {
printf("Fail to create file for output\n");
return -1;
}
avfilter_register_all();
AVFilterGraph* filter_graph = avfilter_graph_alloc();
if (!filter_graph) {
printf("Fail to create filter graph!\n");
return -1;
}
// source filter
char args[512];
sprintf(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);
AVFilter* bufferSrc = avfilter_get_by_name("buffer"); // AVFilterGraph的输入源
AVFilterContext* bufferSrc_ctx;
ret = avfilter_graph_create_filter(&bufferSrc_ctx, bufferSrc, "in", args, NULL, filter_graph);
if (ret < 0) {
printf("Fail to create filter bufferSrc\n");
return -1;
}
// sink filter
AVBufferSinkParams *bufferSink_params;
AVFilterContext* bufferSink_ctx;
AVFilter* bufferSink = avfilter_get_by_name("buffersink");
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
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);
if (ret < 0) {
printf("Fail to create filter sink filter\n");
return -1;
}
// split filter
AVFilter *splitFilter = avfilter_get_by_name("split");
AVFilterContext *splitFilter_ctx;
ret = avfilter_graph_create_filter(&splitFilter_ctx, splitFilter, "split", "outputs=2",
NULL, filter_graph);
if (ret < 0) {
printf("Fail to create split filter\n");
return -1;
}
// crop filter
AVFilter *cropFilter = avfilter_get_by_name("crop");
AVFilterContext *cropFilter_ctx;
ret = avfilter_graph_create_filter(&cropFilter_ctx, cropFilter, "crop",
"out_w=iw:out_h=ih/2:x=0:y=0", NULL, filter_graph);
if (ret < 0) {
printf("Fail to create crop filter\n");
return -1;
}
// vflip filter
AVFilter *vflipFilter = avfilter_get_by_name("vflip");// vflip:镜像反转
AVFilterContext *vflipFilter_ctx;
ret = avfilter_graph_create_filter(&vflipFilter_ctx, vflipFilter, "vflip", NULL, NULL, filter_graph);
if (ret < 0) {
printf("Fail to create vflip filter\n");
return -1;
}
// overlay filter
AVFilter *overlayFilter = avfilter_get_by_name("overlay");
AVFilterContext *overlayFilter_ctx;
ret = avfilter_graph_create_filter(&overlayFilter_ctx, overlayFilter, "overlay",
"y=0:H/2", NULL, filter_graph);
if (ret < 0) {
printf("Fail to create overlay filter\n");
return -1;
}
// src filter to split filter
ret = avfilter_link(bufferSrc_ctx, 0, splitFilter_ctx, 0);
if (ret != 0) {
printf("Fail to link src filter and split filter\n");
return -1;
}
// split filter's first pad to overlay filter's main pad
ret = avfilter_link(splitFilter_ctx, 0, overlayFilter_ctx, 0);
if (ret != 0) {
printf("Fail to link split filter and overlay filter main pad\n");
return -1;
}
// split filter's second pad to crop filter
ret = avfilter_link(splitFilter_ctx, 1, cropFilter_ctx, 0);
if (ret != 0) {
printf("Fail to link split filter's second pad and crop filter\n");
return -1;
}
// crop filter to vflip filter
ret = avfilter_link(cropFilter_ctx, 0, vflipFilter_ctx, 0);
if (ret != 0) {
printf("Fail to link crop filter and vflip filter\n");
return -1;
}
// vflip filter to overlay filter's second pad
ret = avfilter_link(vflipFilter_ctx, 0, overlayFilter_ctx, 1);
if (ret != 0) {
printf("Fail to link vflip filter and overlay filter's second pad\n");
return -1;
}
// overlay filter to sink filter
ret = avfilter_link(overlayFilter_ctx, 0, bufferSink_ctx, 0);
if (ret != 0) {
printf("Fail to link overlay filter and sink filter\n");
return -1;
}
// check filter graph
ret = avfilter_graph_config(filter_graph, NULL);
if (ret < 0) {
printf("Fail in filter graph\n");
return -1;
}
char *graph_str = avfilter_graph_dump(filter_graph, NULL);
FILE* graphFile = NULL;
fopen_s(&graphFile, "graphFile.txt", "w"); // 打印filtergraph的具体情况
fprintf(graphFile, "%s", graph_str);
av_free(graph_str);
AVFrame *frame_in = av_frame_alloc();
unsigned char *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);
AVFrame *frame_out = av_frame_alloc();
unsigned char *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;
uint32_t frame_count = 0;
while (1) {
// 读取yuv数据
if (fread(frame_buffer_in, 1, in_width*in_height * 3 / 2, inFile) != in_width*in_height * 3 / 2) {
break;
}
//input Y,U,V
frame_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.\n");
break;
}
// filter内部自己处理
/* pull filtered pictures from the filtergraph */
ret = av_buffersink_get_frame(bufferSink_ctx, frame_out);
if (ret < 0)
break;
//output Y,U,V
if (frame_out->format == AV_PIX_FMT_YUV420P) {
for (int i = 0; i < frame_out->height; i++) {
fwrite(frame_out->data[0] + frame_out->linesize[0] * i, 1, frame_out->width, outFile);
}
for (int i = 0; i < frame_out->height / 2; i++) {
fwrite(frame_out->data[1] + frame_out->linesize[1] * i, 1, frame_out->width / 2, outFile);
}
for (int i = 0; i < frame_out->height / 2; i++) {
fwrite(frame_out->data[2] + frame_out->linesize[2] * i, 1, frame_out->width / 2, outFile);
}
}
++frame_count;
if(frame_count % 25 == 0)
printf("Process %d frame!\n",frame_count);
av_frame_unref(frame_out);
}
fclose(inFile);
fclose(outFile);
av_frame_free(&frame_in);
av_frame_free(&frame_out);
avfilter_graph_free(&filter_graph); // 内部去释放AVFilterContext产生的内存
return 0;
}