前言
众所周知,FFmpeg 的代码开发上手难度较高,源于官方提供的文档很少有包含代码教程相关的。要想熟练掌握 FFmpeg 的代码库开发,需要借助它的头文件,FFmpeg 把很多代码库教程都写在头文件里面。因此,熟读头文件的内容很重要,为此,我对 FFmpeg 6.x 版本的头文件进行了翻译,方便大家阅读理解。相信我,通读一遍头文件的注释后,你的 FFmpeg 的代码库开发技能将更上一层。
本文适用于有 FFmpeg 代码库开发基础,但想深入熟练使用的同学。
同时也可以参考我的Github 仓库,下载到本地慢慢品读~
libavfilter 模块用于给未编码的帧使用各种过滤器,主要有如下头文件:
- avfilter.h
- buffersink.h
- buffersrc.h
avfilter.h
#ifndef AVFILTER_AVFILTER_H
#define AVFILTER_AVFILTER_H
/**
* @file
* @ingroup lavfi
* libavfilter主要公共API头文件
*/
/**
* @defgroup lavfi libavfilter
* 基于图的帧编辑库。
*
* @{
*/
#include <stddef.h>
#include "libavutil/attributes.h"
#include "libavutil/avutil.h"
#include "libavutil/buffer.h"
#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/samplefmt.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
#include "libavfilter/version_major.h"
#ifndef HAVE_AV_CONFIG_H
/* 当作为ffmpeg构建的一部分时,仅包含主版本号
* 以避免不必要的重新构建。当外部包含时,继续包含
* 完整的版本信息。 */
#include "libavfilter/version.h"
#endif
/**
* 返回LIBAVFILTER_VERSION_INT常量。
*/
unsigned avfilter_version(void);
/**
* 返回libavfilter的编译时配置。
*/
const char *avfilter_configuration(void);
/**
* 返回libavfilter的许可证。
*/
const char *avfilter_license(void);
typedef struct AVFilterContext AVFilterContext;
typedef struct AVFilterLink AVFilterLink;
typedef struct AVFilterPad AVFilterPad;
typedef struct AVFilterFormats AVFilterFormats;
typedef struct AVFilterChannelLayouts AVFilterChannelLayouts;
/**
* 获取AVFilterPad的名称。
*
* @param pads AVFilterPad数组
* @param pad_idx 数组中pad的索引;调用者负责
* 确保索引有效
*
* @return pads中第pad_idx个pad的名称
*/
const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx);
/**
* 获取AVFilterPad的类型。
*
* @param pads AVFilterPad数组
* @param pad_idx 数组中pad的索引;调用者负责
* 确保索引有效
*
* @return pads中第pad_idx个pad的类型
*/
enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx);
/**
* 过滤器输入的数量不仅由AVFilter.inputs决定。
* 过滤器可能会根据提供给它的选项在初始化期间添加额外的输入。
*/
#define AVFILTER_FLAG_DYNAMIC_INPUTS (1 << 0)
/**
* 过滤器输出的数量不仅由AVFilter.outputs决定。
* 过滤器可能会根据提供给它的选项在初始化期间添加额外的输出。
*/
#define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1)
/**
* 过滤器通过将帧分割成多个部分并并发处理它们来支持多线程。
*/
#define AVFILTER_FLAG_SLICE_THREADS (1 << 2)
/**
* 这是一个"元数据"过滤器 - 它不会以任何方式修改帧数据。
* 它可能只会影响元数据(即那些由av_frame_copy_props()复制的字段)。
*
* 更准确地说,这意味着:
* - 视频:过滤器输出的任何帧的数据必须完全等于
* 在其输入之一上接收的某个帧。此外,在给定输出上
* 产生的所有帧必须对应于在同一输入上接收的帧,
* 并且它们的顺序必须保持不变。注意过滤器仍然可能
* 丢弃或复制帧。
* - 音频:过滤器在其任何输出上产生的数据(例如,
* 视为交错样本的数组)必须完全等于过滤器在其
* 输入之一上接收的数据。
*/
#define AVFILTER_FLAG_METADATA_ONLY (1 << 3)
/**
* 过滤器可以使用AVFilterContext.hw_device_ctx创建硬件帧。
*/
#define AVFILTER_FLAG_HWDEVICE (1 << 4)
/**
* 一些过滤器支持通用的"enable"表达式选项,可用于
* 在时间线中启用或禁用过滤器。支持此选项的过滤器
* 设置此标志。当enable表达式为false时,将调用默认的
* 无操作filter_frame()函数,而不是在每个输入pad上定义的
* filter_frame()回调,因此帧将不变地传递给下一个过滤器。
*/
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC (1 << 16)
/**
* 与AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC相同,除了即使
* enable表达式为false时,过滤器仍将像往常一样调用其
* filter_frame()回调。过滤器将在filter_frame()回调内
* 禁用过滤,例如执行依赖于AVFilterContext->is_disabled
* 值的代码。
*/
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL (1 << 17)
/**
* 用于测试过滤器是否支持时间线功能的便捷掩码
* (内部或通用)。
*/
#define AVFILTER_FLAG_SUPPORT_TIMELINE (AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL)
/**
* 过滤器定义。这定义了过滤器包含的pad,以及所有用于
* 与过滤器交互的回调函数。
*/
typedef struct AVFilter {
/**
* 过滤器名称。必须非NULL且在过滤器中唯一。
*/
const char *name;
/**
* 过滤器的描述。可以为NULL。
*
* 你应该使用NULL_IF_CONFIG_SMALL()宏来定义它。
*/
const char *description;
/**
* 静态输入列表。
*
* 如果没有(静态)输入则为NULL。设置了AVFILTER_FLAG_DYNAMIC_INPUTS
* 的过滤器实例可能有比此列表更多的输入。
*/
const AVFilterPad *inputs;
/**
* 静态输出列表。
*
* 如果没有(静态)输出则为NULL。设置了AVFILTER_FLAG_DYNAMIC_OUTPUTS
* 的过滤器实例可能有比此列表更多的输出。
*/
const AVFilterPad *outputs;
/**
* 用于私有数据的类,用于声明过滤器私有AVOptions。
* 对于不声明任何选项的过滤器,此字段为NULL。
*
* 如果此字段非NULL,过滤器私有数据的第一个成员
* 必须是指向AVClass的指针,libavfilter通用代码
* 将把它设置为这个类。
*/
const AVClass *priv_class;
/**
* AVFILTER_FLAG_*的组合
*/
int flags;
/*****************************************************************
* 此行以下的所有字段都不是公共API的一部分。它们
* 不能在libavfilter外使用,并且可以随意更改和
* 删除。
* 新的公共字段应该添加在上面。
*****************************************************************
*/
/**
* 输入列表中的条目数。
*/
uint8_t nb_inputs;
/**
* 输出列表中的条目数。
*/
uint8_t nb_outputs;
/**
* 此字段确定formats联合的状态。
* 它是一个FilterFormatsState枚举值。
*/
uint8_t formats_state;
/**
* 过滤器预初始化函数
*
* 此回调将在过滤器上下文分配后立即调用,
* 以允许分配和初始化子对象。
*
* 如果此回调非NULL,则在分配失败时将调用uninit回调。
*
* @return 成功时返回0,
* 失败时返回AVERROR代码(但调用代码会
* 丢弃该代码并将其视为ENOMEM)
*/
int (*preinit)(AVFilterContext *ctx);
/**
* 过滤器初始化函数。
*
* 此回调在过滤器生命周期内只会调用一次,在所有
* 选项设置之后,但在建立过滤器之间的链接和
* 进行格式协商之前。
*
* 应该在这里完成基本的过滤器初始化。具有动态
* 输入和/或输出的过滤器应该根据提供的选项在
* 这里创建这些输入/输出。在此回调之后,不能
* 对此过滤器的输入/输出进行更多更改。
*
* 此回调不能假设过滤器链接存在或帧参数已知。
*
* 即使初始化失败,也保证会调用@ref AVFilter.uninit "uninit",
* 因此此回调不需要在失败时进行清理。
*
* @return 成功时返回0,失败时返回负的AVERROR
*/
int (*init)(AVFilterContext *ctx);
/**
* 过滤器取消初始化函数。
*
* 仅在过滤器释放之前调用一次。应该释放过滤器
* 持有的任何内存,释放任何缓冲区引用等。它不
* 需要释放AVFilterContext.priv内存本身。
*
* 即使@ref AVFilter.init "init"未调用或失败,
* 也可能调用此回调,因此它必须准备好处理这种
* 情况。
*/
void (*uninit)(AVFilterContext *ctx);
/**
* 以下联合的状态由formats_state确定。
* 请参阅internal.h中FilterFormatsState枚举的文档。
*/
union {
/**
* 查询过滤器在其输入和输出上支持的格式。
*
* 此回调在过滤器初始化后调用(因此输入和输出是固定的),
* 在格式协商之前不久。此回调可能被调用多次。
*
* 此回调必须在每个输入链接上设置::AVFilterLink的
* @ref AVFilterFormatsConfig.formats "outcfg.formats"
* 和在每个输出链接上设置
* @ref AVFilterFormatsConfig.formats "incfg.formats"
* 为过滤器在该链接上支持的像素/样本格式列表。
* 对于音频链接,此过滤器还必须设置
* @ref AVFilterFormatsConfig.samplerates "incfg.samplerates"
* /
* @ref AVFilterFormatsConfig.samplerates "outcfg.samplerates"
* 和@ref AVFilterFormatsConfig.channel_layouts "incfg.channel_layouts"
* /
* @ref AVFilterFormatsConfig.channel_layouts "outcfg.channel_layouts"
* 类似地。
*
* 当联合处于此状态时,此回调决不能为NULL。
*
* @return 成功时返回零,失败时返回对应于
* AVERROR代码的负值
*/
int (*query_func)(AVFilterContext *);
/**
* 指向由AV_PIX_FMT_NONE分隔的可接受像素格式数组的指针。
* 通用代码将使用此列表来表明此过滤器支持这些像素格式中的
* 每一个,前提是所有输入和输出使用相同的像素格式。
*
* 当联合处于此状态时,此列表决不能为NULL。
* 使用此的所有过滤器的输入和输出的类型必须是
* AVMEDIA_TYPE_VIDEO。
*/
const enum AVPixelFormat *pixels_list;
/**
* 类似于pixels,但由AV_SAMPLE_FMT_NONE分隔
* 并限制为仅具有AVMEDIA_TYPE_AUDIO输入和输出的过滤器。
*
* 除此之外,通用代码将标记所有输入和所有输出
* 支持所有采样率和每个声道数和声道布局,只要所有
* 输入和输出使用相同的采样率和声道数/布局。
*/
const enum AVSampleFormat *samples_list;
/**
* 等同于{ pix_fmt, AV_PIX_FMT_NONE }作为pixels_list。
*/
enum AVPixelFormat pix_fmt;
/**
* 等同于{ sample_fmt, AV_SAMPLE_FMT_NONE }作为samples_list。
*/
enum AVSampleFormat sample_fmt;
} formats;
int priv_size; ///< 为过滤器分配的私有数据的大小
int flags_internal; ///< 仅供avfilter内部使用的附加标志。
/**
* 使过滤器实例处理命令。
*
* @param cmd 要处理的命令,为了处理简单,所有命令必须只包含字母数字
* @param arg 命令的参数
* @param res 大小为res_size的缓冲区,过滤器可以在其中返回响应。当命令不支持时,这不能改变。
* @param flags 如果设置了AVFILTER_CMD_FLAG_FAST且命令会
* 耗时,则过滤器应将其视为不支持的命令
*
* @returns 成功时返回>=0,否则返回错误代码。
* 不支持的命令返回AVERROR(ENOSYS)
*/
int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags);
/**
* 过滤器激活函数。
*
* 当需要从过滤器进行任何处理时调用,而不是在pad上
* 调用任何filter_frame和request_frame。
*
* 该函数必须检查输入链接和输出链接并执行单个
* 处理步骤。如果没有要做的事情,该函数必须
* 什么都不做且不返回错误。如果更多步骤是可能的
* 或可能的,它必须使用ff_filter_set_ready()来
* 安排另一次激活。
*/
int (*activate)(AVFilterContext *ctx);
} AVFilter;
/**
* 获取AVFilter的输入或输出数组中的元素数量。
*/
unsigned avfilter_filter_pad_count(const AVFilter *filter, int is_output);
/**
* 并发处理帧的多个部分。
*/
#define AVFILTER_THREAD_SLICE (1 << 0)
typedef struct AVFilterInternal AVFilterInternal;
/** 过滤器的一个实例 */
struct AVFilterContext {
const AVClass *av_class; ///< 用于av_log()和过滤器通用选项所需
const AVFilter *filter; ///< 此实例所属的AVFilter
char *name; ///< 此过滤器实例的名称
AVFilterPad *input_pads; ///< 输入pad数组
AVFilterLink **inputs; ///< 指向输入链接的指针数组
unsigned nb_inputs; ///< 输入pad的数量
AVFilterPad *output_pads; ///< 输出pad数组
AVFilterLink **outputs; ///< 指向输出链接的指针数组
unsigned nb_outputs; ///< 输出pad的数量
void *priv; ///< 供过滤器使用的私有数据
struct AVFilterGraph *graph; ///< 此过滤器所属的过滤器图
/**
* 允许/使用的多线程类型。AVFILTER_THREAD_* 标志的组合。
*
* 在初始化过滤器之前,调用者可以设置此字段以禁止此过滤器的某些
* 或所有类型的多线程。默认允许所有类型。
*
* 当过滤器初始化时,此字段与AVFilterGraph.thread_type进行按位与运算
* 以获得用于确定允许的线程类型的最终掩码。即一个线程类型需要在两处
* 都设置才被允许。
*
* 过滤器初始化后,libavfilter将此字段设置为实际使用的线程类型
* (0表示无多线程)。
*/
int thread_type;
/**
* 供libavfilter内部使用的不透明结构。
*/
AVFilterInternal *internal;
struct AVFilterCommand *command_queue;
char *enable_str; ///< 启用表达式字符串
void *enable; ///< 解析后的表达式(AVExpr*)
double *var_values; ///< 启用表达式的变量值
int is_disabled; ///< 上次表达式求值的启用状态
/**
* 对于将创建硬件帧的过滤器,设置过滤器应在其中创建帧的设备。
* 所有其他过滤器将忽略此字段:特别是,消费或处理硬件帧的过滤器
* 将使用AVFilterLink中的hw_frames_ctx字段来携带硬件上下文信息。
*
* 在使用avfilter_init_str()或avfilter_init_dict()初始化过滤器之前,
* 可由调用者在标记为AVFILTER_FLAG_HWDEVICE的过滤器上设置。
*/
AVBufferRef *hw_device_ctx;
/**
* 此过滤器实例允许的最大线程数。
* 如果 <= 0,则忽略其值。
* 覆盖每个过滤器图设置的全局线程数。
*/
int nb_threads;
/**
* 过滤器的就绪状态。
* 非0值表示过滤器需要激活;
* 更高的值表示更紧急的激活需求。
*/
unsigned ready;
/**
* 设置过滤器将在其输出链接上分配的额外硬件帧数量,
* 供后续过滤器或调用者使用。
*
* 某些硬件过滤器要求在开始过滤之前预先定义所有将用于
* 输出的帧。对于这类过滤器,用于输出的任何硬件帧池
* 必须是固定大小的。这里设置的额外帧数是在过滤器正常
* 运行所需的帧数之外的。
*
* 必须在配置包含此过滤器的图之前设置此字段。
*/
int extra_hw_frames;
};
/**
* 链接一端支持的格式/等列表。
*
* 此结构直接作为AVFilterLink的一部分,有两个副本:
* 一个用于源过滤器,一个用于目标过滤器。
*
* 这些列表用于协商实际要使用的格式,
* 选定后将加载到AVFilterLink的format和channel_layout成员中。
*/
typedef struct AVFilterFormatsConfig {
/**
* 支持的格式列表(像素或采样)。
*/
AVFilterFormats *formats;
/**
* 支持的采样率列表,仅用于音频。
*/
AVFilterFormats *samplerates;
/**
* 支持的声道布局列表,仅用于音频。
*/
AVFilterChannelLayouts *channel_layouts;
} AVFilterFormatsConfig;
/**
* 两个过滤器之间的链接。包含此链接存在的源过滤器和
* 目标过滤器之间的指针,以及涉及的pad索引。此外,
* 此链接还包含在过滤器之间协商和约定的参数,如
* 图像尺寸、格式等。
*
* 应用程序通常不应直接访问链接结构。
* 应使用buffersrc和buffersink API。
* 将来,对头文件的访问可能仅限于过滤器实现。
*/
struct AVFilterLink {
AVFilterContext *src; ///< 源过滤器
AVFilterPad *srcpad; ///< 源过滤器上的输出pad
AVFilterContext *dst; ///< 目标过滤器
AVFilterPad *dstpad; ///< 目标过滤器上的输入pad
enum AVMediaType type; ///< 过滤器媒体类型
/* 这些参数仅适用于视频 */
int w; ///< 约定的图像宽度
int h; ///< 约定的图像高度
AVRational sample_aspect_ratio; ///< 约定的采样宽高比
/* 这些参数仅适用于音频 */
#if FF_API_OLD_CHANNEL_LAYOUT
/**
* 当前缓冲区的声道布局(参见libavutil/channel_layout.h)
* @deprecated 使用ch_layout
*/
attribute_deprecated
uint64_t channel_layout;
#endif
int sample_rate; ///< 每秒采样数
int format; ///< 约定的媒体格式
/**
* 定义将通过此链接传递的帧/样本的PTS使用的时基。
* 在配置阶段,每个过滤器应该只改变输出时基,
* 而输入链接的时基被认为是一个不可改变的属性。
*/
AVRational time_base;
AVChannelLayout ch_layout; ///< 当前缓冲区的声道布局(参见libavutil/channel_layout.h)
/*****************************************************************
* 此行以下的所有字段都不是公共API的一部分。它们
* 不能在libavfilter外部使用,并且可以随意更改和
* 删除。
* 新的公共字段应该添加在上面。
*****************************************************************
*/
/**
* 输入过滤器支持的格式/等列表。
*/
AVFilterFormatsConfig incfg;
/**
* 输出过滤器支持的格式/等列表。
*/
AVFilterFormatsConfig outcfg;
/** 链接属性(尺寸等)的初始化阶段 */
enum {
AVLINK_UNINIT = 0, ///< 未开始
AVLINK_STARTINIT, ///< 已开始,但不完整
AVLINK_INIT ///< 完成
} init_state;
/**
* 过滤器所属的图。
*/
struct AVFilterGraph *graph;
/**
* 链接的当前时间戳,由最近的帧定义,
* 以链接time_base为单位。
*/
int64_t current_pts;
/**
* 链接的当前时间戳,由最近的帧定义,
* 以AV_TIME_BASE为单位。
*/
int64_t current_pts_us;
/**
* 在age数组中的索引。
*/
int age_index;
/**
* 链接上流的帧率,如果未知或可变则为1/0;
* 如果保持为0/0,将自动从源过滤器的第一个输入复制
* (如果存在)。
*
* 源应该设置为实际帧率的最佳估计。
* 如果源帧率未知或可变,设置为1/0。
* 过滤器应根据其功能在必要时更新它。
* 接收器可以使用它来设置默认输出帧率。
* 它类似于AVStream中的r_frame_rate字段。
*/
AVRational frame_rate;
/**
* 一次过滤的最小样本数。如果使用较少的样本调用
* filter_frame(),它将在fifo中累积它们。
* 过滤开始后不能更改此字段和相关字段。
* 如果为0,则忽略所有相关字段。
*/
int min_samples;
/**
* 一次过滤的最大样本数。如果使用更多样本调用
* filter_frame(),它将分割它们。
*/
int max_samples;
/**
* 通过链接发送的过去帧数。
*/
int64_t frame_count_in, frame_count_out;
/**
* 通过链接发送的过去样本数。
*/
int64_t sample_count_in, sample_count_out;
/**
* 指向FFFramePool结构的指针。
*/
void *frame_pool;
/**
* 如果当前在此过滤器的输出上需要一帧则为True。
* 当输出调用ff_request_frame()时设置,
* 当过滤一帧时清除。
*/
int frame_wanted_out;
/**
* 对于hwaccel像素格式,这应该是对描述帧的
* AVHWFramesContext的引用。
*/
AVBufferRef *hw_frames_ctx;
#ifndef FF_INTERNAL_FIELDS
/**
* 内部结构成员。
* 此限制以下的字段是供libavfilter内部使用的,
* 在任何情况下都不能被应用程序访问。
*/
char reserved[0xF000];
#else /* FF_INTERNAL_FIELDS */
/**
* 等待过滤的帧队列。
*/
FFFrameQueue fifo;
/**
* 如果设置,源过滤器目前无法生成帧。
* 目的是避免在同一链接上重复调用request_frame()方法。
*/
int frame_blocked_in;
/**
* 链接输入状态。
* 如果非零,所有filter_frame尝试都将以相应的代码失败。
*/
int status_in;
/**
* 输入状态更改的时间戳。
*/
int64_t status_in_pts;
/**
* 链接输出状态。
* 如果非零,所有request_frame尝试都将以相应的代码失败。
*/
int status_out;
#endif /* FF_INTERNAL_FIELDS */
};
/**
* 将两个过滤器链接在一起。
*
* @param src 源过滤器
* @param srcpad 源过滤器上输出pad的索引
* @param dst 目标过滤器
* @param dstpad 目标过滤器上输入pad的索引
* @return 成功时返回零
*/
int avfilter_link(AVFilterContext *src, unsigned srcpad,
AVFilterContext *dst, unsigned dstpad);
/**
* 释放*link中的链接,并将其指针设置为NULL。
*/
void avfilter_link_free(AVFilterLink **link);
/**
* 协商过滤器所有输入的媒体格式、尺寸等。
*
* @param filter 要为其输入协商属性的过滤器
* @return 成功协商时返回零
*/
int avfilter_config_links(AVFilterContext *filter);
#define AVFILTER_CMD_FLAG_ONE 1 ///< 一旦过滤器理解了命令就停止(例如对于target=all),自动优先考虑快速过滤器
#define AVFILTER_CMD_FLAG_FAST 2 ///< 仅在命令快速时执行(如支持硬件对比度调整的视频输出)
/**
* 使过滤器实例处理命令。
* 建议使用avfilter_graph_send_command()。
*/
int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags);
/**
* 遍历所有已注册的过滤器。
*
* @param opaque 一个指针,libavfilter将在其中存储迭代状态。必须
* 指向NULL以开始迭代。
*
* @return 下一个已注册的过滤器,如果迭代结束则返回NULL
*/
const AVFilter *av_filter_iterate(void **opaque);
/**
* 获取与给定名称匹配的过滤器定义。
*
* @param name 要查找的过滤器名称
* @return 如果有匹配的过滤器定义则返回该定义。
* 如果未找到则返回NULL。
*/
const AVFilter *avfilter_get_by_name(const char *name);
/**
* 使用提供的参数初始化过滤器。
*
* @param ctx 要初始化的未初始化的过滤器上下文
* @param args 用于初始化过滤器的选项。这必须是一个
* 以':'分隔的'key=value'形式的选项列表。
* 如果选项已通过AVOptions API直接设置或
* 没有需要设置的选项,则可以为NULL。
* @return 成功时返回0,失败时返回负的AVERROR
*/
int avfilter_init_str(AVFilterContext *ctx, const char *args);
/**
* 使用提供的选项字典初始化过滤器。
*
* @param ctx 要初始化的未初始化的过滤器上下文
* @param options 一个填充了此过滤器选项的AVDictionary。在
* 返回时,此参数将被销毁并替换为包含未找到
* 选项的字典。调用者必须释放此字典。
* 可以为NULL,则此函数等同于将第二个参数
* 设置为NULL的avfilter_init_str()。
* @return 成功时返回0,失败时返回负的AVERROR
*
* @note 此函数和avfilter_init_str()本质上做相同的事情,
* 区别在于传递选项的方式。由调用代码选择更合适的方式。
* 当过滤器不支持某些提供的选项时,这两个函数的行为也不同。
* 在这种情况下,avfilter_init_str()将失败,但此函数会将这些
* 额外选项保留在options AVDictionary中并继续正常执行。
*/
int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options);
/**
* 释放过滤器上下文。这也会从其过滤器图的过滤器列表中
* 移除该过滤器。
*
* @param filter 要释放的过滤器
*/
void avfilter_free(AVFilterContext *filter);
/**
* 在现有链接中间插入过滤器。
*
* @param link 要插入过滤器的链接
* @param filt 要插入的过滤器
* @param filt_srcpad_idx 要连接的过滤器输入pad
* @param filt_dstpad_idx 要连接的过滤器输出pad
* @return 成功时返回零
*/
int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
unsigned filt_srcpad_idx, unsigned filt_dstpad_idx);
/**
* @return AVFilterContext的AVClass。
*
* @see av_opt_find()。
*/
const AVClass *avfilter_get_class(void);
typedef struct AVFilterGraphInternal AVFilterGraphInternal;
/**
* 传递给@ref AVFilterGraph.execute回调的函数指针,
* 用于多次执行,可能并行执行。
*
* @param ctx 作业所属的过滤器上下文
* @param arg 从@ref AVFilterGraph.execute传递的不透明参数
* @param jobnr 正在执行的作业索引
* @param nb_jobs 作业总数
*
* @return 成功时返回0,错误时返回负的AVERROR
*/
typedef int (avfilter_action_func)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
/**
* 执行多个作业的函数,可能并行执行。
*
* @param ctx 作业所属的过滤器上下文
* @param func 要多次调用的函数
* @param arg 要传递给func的参数
* @param ret 大小为nb_jobs的数组,用于填充每次调用func的返回值
* @param nb_jobs 要执行的作业数
*
* @return 成功时返回0,错误时返回负的AVERROR
*/
typedef int (avfilter_execute_func)(AVFilterContext *ctx, avfilter_action_func *func,
void *arg, int *ret, int nb_jobs);
typedef struct AVFilterGraph {
const AVClass *av_class;
AVFilterContext **filters;
unsigned nb_filters;
char *scale_sws_opts; ///< 用于自动插入的scale过滤器的sws选项
/**
* 此图中过滤器允许的多线程类型。AVFILTER_THREAD_*标志的组合。
*
* 调用者可以在任何时候设置,该设置将应用于之后初始化的所有过滤器。
* 默认允许所有类型。
*
* 当此图中的过滤器被初始化时,此字段与AVFilterContext.thread_type
* 进行按位与运算以获得用于确定允许线程类型的最终掩码。即线程类型
* 需要在两处都设置才被允许。
*/
int thread_type;
/**
* 此图中过滤器使用的最大线程数。调用者可以在向过滤器图添加任何
* 过滤器之前设置。零(默认值)表示线程数自动确定。
*/
int nb_threads;
/**
* libavfilter内部使用的不透明对象。
*/
AVFilterGraphInternal *internal;
/**
* 不透明的用户数据。调用者可以设置为任意值,例如从@ref AVFilterGraph.execute
* 等回调中使用。libavfilter不会以任何方式触及此字段。
*/
void *opaque;
/**
* 调用者可以在分配图后立即设置此回调,并在添加任何过滤器之前,
* 以提供自定义的多线程实现。
*
* 如果设置,具有切片线程能力的过滤器将调用此回调以并行执行多个作业。
*
* 如果此字段未设置,libavfilter将使用其内部实现,根据平台和构建选项,
* 该实现可能是多线程的也可能不是。
*/
avfilter_execute_func *execute;
char *aresample_swr_opts; ///< 用于自动插入的aresample过滤器的swr选项,仅通过AVOptions访问
/**
* 私有字段
*
* 以下字段仅供内部使用。
* 它们的类型、偏移量、数量和语义可能在没有通知的情况下更改。
*/
AVFilterLink **sink_links;
int sink_links_count;
unsigned disable_auto_convert;
} AVFilterGraph;
/**
* 分配一个过滤器图。
*
* @return 成功时返回分配的过滤器图,否则返回NULL。
*/
AVFilterGraph *avfilter_graph_alloc(void);
/**
* 在过滤器图中创建新的过滤器实例。
*
* @param graph 新过滤器将使用的图
* @param filter 要创建实例的过滤器
* @param name 给新实例的名称(将被复制到AVFilterContext.name)。
* 调用者可以使用此参数来识别不同的过滤器,libavfilter本身
* 不为此参数分配语义。可以为NULL。
*
* @return 新创建的过滤器实例的上下文(注意它也可以直接通过
* AVFilterGraph.filters或avfilter_graph_get_filter()获取)
* 成功时返回,失败时返回NULL。
*/
AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
const AVFilter *filter,
const char *name);
/**
* 从图中获取由实例名称标识的过滤器实例。
*
* @param graph 要搜索的过滤器图。
* @param name 过滤器实例名称(在图中应该是唯一的)。
* @return 找到的过滤器实例的指针,如果找不到则返回NULL。
*/
AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name);
/**
* 在现有图中创建并添加过滤器实例。
* 过滤器实例从过滤器filt创建并使用参数args初始化。
* opaque当前被忽略。
*
* 如果成功,将在*filt_ctx中放入创建的过滤器实例的指针,
* 否则将*filt_ctx设置为NULL。
*
* @param name 给创建的过滤器实例的实例名称
* @param graph_ctx 过滤器图
* @return 失败时返回负的AVERROR错误代码,否则返回非负值
*/
int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt,
const char *name, const char *args, void *opaque,
AVFilterGraph *graph_ctx);
/**
* 启用或禁用图内的自动格式转换。
*
* 注意格式转换仍然可能发生在显式插入的scale和aresample过滤器中。
*
* @param flags AVFILTER_AUTO_CONVERT_*常量中的任何一个
*/
void avfilter_graph_set_auto_convert(AVFilterGraph *graph, unsigned flags);
enum {
AVFILTER_AUTO_CONVERT_ALL = 0, /**< 启用所有自动转换 */
AVFILTER_AUTO_CONVERT_NONE = -1, /**< 禁用所有自动转换 */
};
/**
* 检查有效性并配置图中的所有链接和格式。
*
* @param graphctx 过滤器图
* @param log_ctx 用于日志记录的上下文
* @return 成功时返回 >= 0,否则返回负的AVERROR代码
*/
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx);
/**
* 释放图,销毁其链接,并将*graph设置为NULL。
* 如果*graph为NULL,则不执行任何操作。
*/
void avfilter_graph_free(AVFilterGraph **graph);
/**
* 过滤器链的输入/输出的链表。
*
* 这主要用于avfilter_graph_parse() / avfilter_graph_parse2(),
* 在那里它用于在调用者之间通信图中包含的开放(未链接)输入和输出。
* 此结构为图中每个未连接的pad指定建立链接所需的过滤器上下文和pad索引。
*/
typedef struct AVFilterInOut {
/** 列表中此输入/输出的唯一名称 */
char *name;
/** 与此输入/输出关联的过滤器上下文 */
AVFilterContext *filter_ctx;
/** 用于链接的filt_ctx pad的索引 */
int pad_idx;
/** 列表中的下一个输入/输入,如果这是最后一个则为NULL */
struct AVFilterInOut *next;
} AVFilterInOut;
/**
* 分配单个AVFilterInOut条目。
* 必须使用avfilter_inout_free()释放。
* @return 成功时返回分配的AVFilterInOut,失败时返回NULL。
*/
AVFilterInOut *avfilter_inout_alloc(void);
/**
* 释放提供的AVFilterInOut列表并将*inout设置为NULL。
* 如果*inout为NULL,则不执行任何操作。
*/
void avfilter_inout_free(AVFilterInOut **inout);
/**
* 将由字符串描述的图添加到图中。
*
* @note 调用者必须提供输入和输出列表,
* 因此必须在调用函数之前知道这些列表。
*
* @note inputs参数描述已存在图部分的输入;
* 即从新创建部分的角度来看,它们是输出。
* 类似地,outputs参数描述现有过滤器的输出,
* 这些输出作为输入提供给解析的过滤器。
*
* @param graph 要链接解析的图上下文的过滤器图
* @param filters 要解析的字符串
* @param inputs 图的输入的链表
* @param outputs 图的输出的链表
* @return 成功时返回零,错误时返回负的AVERROR代码
*/
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
AVFilterInOut *inputs, AVFilterInOut *outputs,
void *log_ctx);
/**
* 将由字符串描述的图添加到图中。
*
* 在图过滤器描述中,如果未指定第一个过滤器的输入标签,
* 则假定为"in";如果未指定最后一个过滤器的输出标签,
* 则假定为"out"。
*
* @param graph 要链接解析的图上下文的过滤器图
* @param filters 要解析的字符串
* @param inputs 指向图输入链表的指针,可以为NULL。
* 如果非NULL,*inputs将更新为包含解析后的开放输入列表,
* 应使用avfilter_inout_free()释放。
* @param outputs 指向图输出链表的指针,可以为NULL。
* 如果非NULL,*outputs将更新为包含解析后的开放输出列表,
* 应使用avfilter_inout_free()释放。
* @return 成功时返回非负值,错误时返回负的AVERROR代码
*/
int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters,
AVFilterInOut **inputs, AVFilterInOut **outputs,
void *log_ctx);
/**
* 将由字符串描述的图添加到图中。
*
* @param[in] graph 要链接解析的图上下文的过滤器图
* @param[in] filters 要解析的字符串
* @param[out] inputs 解析的图的所有空闲(未链接)输入的链表将在此返回。
* 调用者必须使用avfilter_inout_free()释放它。
* @param[out] outputs 解析的图的所有空闲(未链接)输出的链表将在此返回。
* 调用者必须使用avfilter_inout_free()释放它。
* @return 成功时返回零,错误时返回负的AVERROR代码
*
* @note 此函数返回解析图后剩余未链接的输入和输出,
* 然后由调用者处理它们。
* @note 此函数完全不引用图的已存在部分,返回的inputs
* 参数将包含新解析的图部分的输入。类似地,outputs
* 参数将包含新创建过滤器的输出。
*/
int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
AVFilterInOut **inputs,
AVFilterInOut **outputs);
/**
* 过滤器输入或输出pad的参数。
*
* 由avfilter_graph_segment_parse()创建为AVFilterParams的子项。
* 在avfilter_graph_segment_free()中释放。
*/
typedef struct AVFilterPadParams {
/**
* 一个av_malloc()分配的包含pad标签的字符串。
*
* 调用者可以av_free()并设置为NULL,在这种情况下,此pad
* 在链接时将被视为未标记。
* 也可以替换为另一个av_malloc()分配的字符串。
*/
char *label;
} AVFilterPadParams;
/**
* 描述过滤器图中要创建的过滤器的参数。
*
* 由avfilter_graph_segment_parse()创建为AVFilterGraphSegment的子项。
* 在avfilter_graph_segment_free()中释放。
*/
typedef struct AVFilterParams {
/**
* 过滤器上下文。
*
* 由avfilter_graph_segment_create_filters()基于
* AVFilterParams.filter_name和instance_name创建。
*
* 调用者也可以手动创建过滤器上下文,然后他们应该
* av_free() filter_name并设置为NULL。这样的AVFilterParams实例
* 将被avfilter_graph_segment_create_filters()跳过。
*/
AVFilterContext *filter;
/**
* 要使用的AVFilter的名称。
*
* 一个由av_malloc()分配的字符串,由avfilter_graph_segment_parse()设置。将被
* avfilter_graph_segment_create_filters()传递给avfilter_get_by_name()。
*
* 调用者可以av_free()此字符串并替换为另一个或NULL。如果调用者手动创建
* 过滤器实例,此字符串必须设置为NULL。
*
* 当AVFilterParams.filter和AVFilterParams.filter_name都为NULL时,
* 此AVFilterParams实例将被avfilter_graph_segment_*()函数跳过。
*/
char *filter_name;
/**
* 用于此过滤器实例的名称。
*
* 一个由av_malloc()分配的字符串,可能由avfilter_graph_segment_parse()设置
* 或保留为NULL。调用者可以av_free()此字符串并替换为另一个或NULL。
*
* 将被avfilter_graph_segment_create_filters()使用 - 作为第三个参数
* 传递给avfilter_graph_alloc_filter(),然后释放并设置为NULL。
*/
char *instance_name;
/**
* 要应用于过滤器的选项。
*
* 由avfilter_graph_segment_parse()填充。之后可以由调用者自由修改。
*
* 将由avfilter_graph_segment_apply_opts()应用到过滤器,
* 等效于av_opt_set_dict2(filter, &opts, AV_OPT_SEARCH_CHILDREN),
* 即任何未应用的选项将保留在此字典中。
*/
AVDictionary *opts;
AVFilterPadParams **inputs;
unsigned nb_inputs;
AVFilterPadParams **outputs;
unsigned nb_outputs;
} AVFilterParams;
/**
* 过滤器链是过滤器规格的列表。
*
* 由avfilter_graph_segment_parse()创建为AVFilterGraphSegment的子项。
* 在avfilter_graph_segment_free()中释放。
*/
typedef struct AVFilterChain {
AVFilterParams **filters;
size_t nb_filters;
} AVFilterChain;
/**
* 过滤器图段的解析表示。
*
* 过滤器图段在概念上是过滤器链的列表,带有一些
* 补充信息(例如格式转换标志)。
*
* 由avfilter_graph_segment_parse()创建。必须使用
* avfilter_graph_segment_free()释放。
*/
typedef struct AVFilterGraphSegment {
/**
* 此段关联的过滤器图。
* 由avfilter_graph_segment_parse()设置。
*/
AVFilterGraph *graph;
/**
* 此段包含的过滤器链列表。
* 在avfilter_graph_segment_parse()中设置。
*/
AVFilterChain **chains;
size_t nb_chains;
/**
* 包含冒号分隔的键=值选项列表的字符串,
* 应用于此段中的所有scale过滤器。
*
* 可能由avfilter_graph_segment_parse()设置。
* 调用者可以使用av_free()释放此字符串,并用不同的
* av_malloc()分配的字符串替换它。
*/
char *scale_sws_opts;
} AVFilterGraphSegment;
/**
* 将文本过滤器图描述解析为中间形式。
*
* 此中间表示旨在由调用者按照AVFilterGraphSegment及其子项的
* 文档中所述进行修改,然后手动或使用其他avfilter_graph_segment_*()
* 函数应用到图中。有关应用AVFilterGraphSegment的规范方式,
* 请参见avfilter_graph_segment_apply()的文档。
*
* @param graph 解析段关联的过滤器图。仅用于日志和类似的辅助目的。
* 此函数不会实际修改图 - 解析结果会存储在seg中供进一步处理。
* @param graph_str 描述过滤器图段的字符串
* @param flags 保留供将来使用,调用者现在必须设置为0
* @param seg 成功时在此处写入新创建的AVFilterGraphSegment的指针。
* 图段由调用者拥有,必须在释放graph本身之前使用
* avfilter_graph_segment_free()释放。
*
* @retval "非负数" 成功
* @retval "负错误代码" 失败
*/
int avfilter_graph_segment_parse(AVFilterGraph *graph, const char *graph_str,
int flags, AVFilterGraphSegment **seg);
/**
* 创建图段中指定的过滤器。
*
* 遍历段中待创建的AVFilterParams并为它们创建新的过滤器实例。
* 待创建的参数是那些AVFilterParams.filter_name非NULL的参数
* (因此AVFilterParams.filter为NULL)。忽略所有其他AVFilterParams实例。
*
* 对于此函数创建的任何过滤器,相应的AVFilterParams.filter设置为
* 新创建的过滤器上下文,AVFilterParams.filter_name和
* AVFilterParams.instance_name被释放并设置为NULL。
*
* @param seg 要处理的过滤器图段
* @param flags 保留供将来使用,调用者现在必须设置为0
*
* @retval "非负数" 成功,所有待创建的过滤器都已成功创建
* @retval AVERROR_FILTER_NOT_FOUND 某些过滤器的名称不对应已知过滤器
* @retval "其他负错误代码" 其他失败
*
* @note 多次调用此函数是安全的,因为它是幂等的。
*/
int avfilter_graph_segment_create_filters(AVFilterGraphSegment *seg, int flags);
/**
* 将解析的选项应用于图段中的过滤器实例。
*
* 遍历图段中所有具有关联选项字典的过滤器实例,并使用
* av_opt_set_dict2(..., AV_OPT_SEARCH_CHILDREN)应用这些选项。
* AVFilterParams.opts被av_opt_set_dict2()输出的字典替换,
* 如果所有选项都成功应用,该字典应为空(NULL)。
*
* 如果任何选项未找到,此函数将继续处理所有其他过滤器,
* 最后返回AVERROR_OPTION_NOT_FOUND(除非发生其他错误)。
* 调用程序可以根据需要处理未应用的选项。
*
* 段中存在的任何待创建过滤器(参见avfilter_graph_segment_create_filters())
* 都将导致此函数失败。简单跳过没有关联过滤器上下文的AVFilterParams。
*
* @param seg 要处理的过滤器图段
* @param flags 保留供将来使用,调用者现在必须设置为0
*
* @retval "非负数" 成功,所有选项都已成功应用。
* @retval AVERROR_OPTION_NOT_FOUND 在过滤器中未找到某些选项
* @retval "其他负错误代码" 其他失败
*
* @note 多次调用此函数是安全的,因为它是幂等的。
*/
int avfilter_graph_segment_apply_opts(AVFilterGraphSegment *seg, int flags);
/**
* 初始化图段中的所有过滤器实例。
*
* 遍历图段中的所有过滤器实例,对尚未初始化的过滤器调用
* avfilter_init_dict(..., NULL)。
*
* 段中存在的任何待创建过滤器(参见avfilter_graph_segment_create_filters())
* 都将导致此函数失败。简单跳过没有关联过滤器上下文或其过滤器上下文
* 已初始化的AVFilterParams。
*
* @param seg 要处理的过滤器图段
* @param flags 保留供将来使用,调用者现在必须设置为0
*
* @retval "非负数" 成功,所有过滤器实例都已成功初始化
* @retval "负错误代码" 失败
*
* @note 多次调用此函数是安全的,因为它是幂等的。
*/
int avfilter_graph_segment_init(AVFilterGraphSegment *seg, int flags);
/**
* 链接图段中的过滤器。
*
* 遍历图段中的所有过滤器实例,并尝试链接所有未链接的输入和输出pad。
* 段中存在的任何待创建过滤器(参见avfilter_graph_segment_create_filters())
* 都将导致此函数失败。跳过禁用的过滤器和已链接的pad。
*
* 每个具有非NULL标签的相应AVFilterPadParams的过滤器输出pad都会:
* - 如果存在匹配标签的输入,则链接到该输入;
* - 否则导出到outputs链表中,保留标签。
* 未标记的输出会:
* - 如果存在,则链接到链中下一个未禁用过滤器中的第一个未链接未标记输入
* - 否则导出到outputs链表中,标签为NULL
*
* 类似地,未链接的输入pad会导出到inputs链表中。
*
* @param seg 要处理的过滤器图段
* @param flags 保留供将来使用,调用者现在必须设置为0
* @param[out] inputs 此图段中过滤器的所有空闲(未链接)输入的链表将在此返回。
* 调用者必须使用avfilter_inout_free()释放它。
* @param[out] outputs 此图段中过滤器的所有空闲(未链接)输出的链表将在此返回。
* 调用者必须使用avfilter_inout_free()释放它。
*
* @retval "非负数" 成功
* @retval "负错误代码" 失败
*
* @note 多次调用此函数是安全的,因为它是幂等的。
*/
int avfilter_graph_segment_link(AVFilterGraphSegment *seg, int flags,
AVFilterInOut **inputs,
AVFilterInOut **outputs);
/**
* 将图段中的所有过滤器/链接描述应用到关联的过滤器图。
*
* 此函数当前等效于按顺序调用以下函数:
* - avfilter_graph_segment_create_filters();
* - avfilter_graph_segment_apply_opts();
* - avfilter_graph_segment_init();
* - avfilter_graph_segment_link();
* 如果其中任何一个失败则失败。此列表将来可能会扩展。
*
* 由于上述函数是幂等的,调用者可以手动调用其中一些函数,
* 然后对过滤器图进行一些自定义处理,然后调用此函数完成其余工作。
*
* @param seg 要处理的过滤器图段
* @param flags 保留供将来使用,调用者现在必须设置为0
* @param[out] inputs 传递给avfilter_graph_segment_link()
* @param[out] outputs 传递给avfilter_graph_segment_link()
*
* @retval "非负数" 成功
* @retval "负错误代码" 失败
*
* @note 多次调用此函数是安全的,因为它是幂等的。
*/
int avfilter_graph_segment_apply(AVFilterGraphSegment *seg, int flags,
AVFilterInOut **inputs,
AVFilterInOut **outputs);
/**
* 释放提供的AVFilterGraphSegment及其关联的所有内容。
*
* @param seg 指向要释放的AVFilterGraphSegment的双重指针。退出此函数时
* 将向此指针写入NULL。
*
* @note
* 过滤器上下文(AVFilterParams.filter)由AVFilterGraph而不是
* AVFilterGraphSegment拥有,因此不会被释放。
*/
void avfilter_graph_segment_free(AVFilterGraphSegment **seg);
/**
* 向一个或多个过滤器实例发送命令。
*
* @param graph 过滤器图
* @param target 应该接收命令的过滤器
* "all"发送到所有过滤器
* 否则可以是过滤器或过滤器实例名称
* 这将把命令发送到所有匹配的过滤器。
* @param cmd 要发送的命令,为了处理简单所有命令必须只包含字母数字
* @param arg 命令的参数
* @param res 大小为res_size的缓冲区,过滤器可以在其中返回响应。
*
* @returns >=0表示成功,否则返回错误代码。
* 对于不支持的命令返回AVERROR(ENOSYS)
*/
int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags);
/**
* 为一个或多个过滤器实例排队命令。
*
* @param graph 过滤器图
* @param target 应该接收命令的过滤器
* "all"发送到所有过滤器
* 否则可以是过滤器或过滤器实例名称
* 这将把命令发送到所有匹配的过滤器。
* @param cmd 要发送的命令,为了处理简单所有命令必须只包含字母数字
* @param arg 命令的参数
* @param ts 应该向过滤器发送命令的时间
*
* @note 由于这在函数返回后执行命令,因此不提供来自过滤器的返回代码,
* 也不支持AVFILTER_CMD_FLAG_ONE。
*/
int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, int flags, double ts);
/**
* 将图转储为人类可读的字符串表示。
*
* @param graph 要转储的图
* @param options 格式化选项;当前被忽略
* @return 一个字符串,或在内存分配失败的情况下为NULL;
* 必须使用av_free释放该字符串
*/
char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
/**
* 在最旧的接收链接上请求一帧。
*
* 如果请求返回AVERROR_EOF,则尝试下一个。
*
* 注意此函数不是要作为过滤器图的唯一调度机制,
* 只是一个帮助在正常情况下以平衡方式耗尽过滤器图的便利函数。
*
* 还要注意AVERROR_EOF并不意味着在此过程中某些接收器上没有收到帧。
* 当有多个接收链接时,如果请求的链接返回EOF,这可能导致过滤器
* 刷新待处理帧,这些帧被发送到另一个接收链接,尽管未被请求。
*
* @return ff_request_frame()的返回值,
* 或如果所有链接都返回AVERROR_EOF则返回AVERROR_EOF
*/
int avfilter_graph_request_oldest(AVFilterGraph *graph);
/**
* @}
*/
#endif /* AVFILTER_AVFILTER_H */
buffersink.h
#ifndef AVFILTER_BUFFERSINK_H
#define AVFILTER_BUFFERSINK_H
/**
* @file
* @ingroup lavfi_buffersink
* 音视频内存缓冲区接收器API
*/
#include "avfilter.h"
/**
* @defgroup lavfi_buffersink 缓冲区接收器API
* @ingroup lavfi
* @{
*
* buffersink和abuffersink过滤器用于将过滤器图连接到应用程序。
* 它们有一个连接到图的单一输入,没有输出。
* 必须使用av_buffersink_get_frame()或av_buffersink_get_samples()来提取帧。
*
* 在配置期间由图协商的格式可以使用以下访问器函数获取:
* - av_buffersink_get_time_base(),
* - av_buffersink_get_format(),
* - av_buffersink_get_frame_rate(),
* - av_buffersink_get_w(),
* - av_buffersink_get_h(),
* - av_buffersink_get_sample_aspect_ratio(),
* - av_buffersink_get_channels(),
* - av_buffersink_get_ch_layout(),
* - av_buffersink_get_sample_rate().
*
* av_buffersink_get_ch_layout()返回的布局必须由调用者取消初始化。
*
* 可以通过使用带有AV_OPT_SEARCH_CHILDREN标志的av_opt_set()和相关函数来设置选项来约束格式。
* - pix_fmts (整数列表),
* - sample_fmts (整数列表),
* - sample_rates (整数列表),
* - ch_layouts (字符串),
* - channel_counts (整数列表),
* - all_channel_counts (布尔值)。
* 这些选项大多数是二进制类型,应该使用av_opt_set_int_list()或av_opt_set_bin()来设置。
* 如果未设置,则接受所有相应的格式。
*
* 作为特殊情况,如果未设置ch_layouts,则接受所有有效的通道布局,
* 除了UNSPEC布局(除非设置了all_channel_counts)。
*/
/**
* 从接收器获取经过过滤的数据帧并将其放入frame中。
*
* @param ctx 指向buffersink或abuffersink过滤器上下文的指针。
* @param frame 指向将填充数据的已分配帧的指针。
* 必须使用av_frame_unref() / av_frame_free()释放数据
* @param flags AV_BUFFERSINK_FLAG_*标志的组合
*
* @return 成功时返回 >= 0,失败时返回负的AVERROR代码。
*/
int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags);
/**
* 告诉av_buffersink_get_buffer_ref()读取视频/样本缓冲区引用,
* 但不从缓冲区中移除它。如果你只需要读取视频/样本缓冲区而不需要获取它,这很有用。
*/
#define AV_BUFFERSINK_FLAG_PEEK 1
/**
* 告诉av_buffersink_get_buffer_ref()不要从其输入请求帧。
* 如果已经缓冲了一帧,则读取它(并从缓冲区中移除),
* 但如果没有帧存在,则返回AVERROR(EAGAIN)。
*/
#define AV_BUFFERSINK_FLAG_NO_REQUEST 2
/**
* 为音频缓冲区接收器设置帧大小。
*
* 所有对av_buffersink_get_buffer_ref的调用将返回一个具有
* 指定数量样本的缓冲区,如果没有足够的样本则返回AVERROR(EAGAIN)。
* EOF时的最后一个缓冲区将用0填充。
*/
void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size);
/**
* @defgroup lavfi_buffersink_accessors 缓冲区接收器访问器
* 获取流的属性
* @{
*/
enum AVMediaType av_buffersink_get_type (const AVFilterContext *ctx);
AVRational av_buffersink_get_time_base (const AVFilterContext *ctx);
int av_buffersink_get_format (const AVFilterContext *ctx);
AVRational av_buffersink_get_frame_rate (const AVFilterContext *ctx);
int av_buffersink_get_w (const AVFilterContext *ctx);
int av_buffersink_get_h (const AVFilterContext *ctx);
AVRational av_buffersink_get_sample_aspect_ratio (const AVFilterContext *ctx);
int av_buffersink_get_channels (const AVFilterContext *ctx);
#if FF_API_OLD_CHANNEL_LAYOUT
attribute_deprecated
uint64_t av_buffersink_get_channel_layout (const AVFilterContext *ctx);
#endif
int av_buffersink_get_ch_layout (const AVFilterContext *ctx,
AVChannelLayout *ch_layout);
int av_buffersink_get_sample_rate (const AVFilterContext *ctx);
AVBufferRef * av_buffersink_get_hw_frames_ctx (const AVFilterContext *ctx);
/** @} */
/**
* 从接收器获取经过过滤的数据帧并将其放入frame中。
*
* @param ctx 指向buffersink或abuffersink AVFilter上下文的指针。
* @param frame 指向将填充数据的已分配帧的指针。
* 必须使用av_frame_unref() / av_frame_free()释放数据
*
* @return
* - >= 0 如果成功返回一帧。
* - AVERROR(EAGAIN) 如果此时没有可用帧;必须向过滤器图添加更多输入帧以获得更多输出。
* - AVERROR_EOF 如果此接收器将不再有更多输出帧。
* - 其他失败情况下的不同负AVERROR代码。
*/
int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
/**
* 与av_buffersink_get_frame()相同,但可以指定读取的样本数。
* 这个函数比av_buffersink_get_frame()效率低,因为它会复制数据。
*
* @param ctx 指向abuffersink AVFilter上下文的指针。
* @param frame 指向将填充数据的已分配帧的指针。
* 必须使用av_frame_unref() / av_frame_free()释放数据
* frame将包含恰好nb_samples个音频样本,除了在流结束时,
* 它可能包含少于nb_samples个样本。
*
* @return 返回代码与av_buffersink_get_frame()的含义相同。
*
* @warning 不要将此函数与av_buffersink_get_frame()混用。
* 对单个接收器只使用其中之一,不要同时使用两者。
*/
int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
/**
* @}
*/
#endif /* AVFILTER_BUFFERSINK_H */
buffersrc.h
#ifndef AVFILTER_BUFFERSRC_H
#define AVFILTER_BUFFERSRC_H
/**
* @file
* @ingroup lavfi_buffersrc
* 内存缓冲区源API。
*/
#include "avfilter.h"
/**
* @defgroup lavfi_buffersrc 缓冲区源API
* @ingroup lavfi
* @{
*/
enum {
/**
* 不检查格式变化。
*/
AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1,
/**
* 立即将帧推送到输出。
*/
AV_BUFFERSRC_FLAG_PUSH = 4,
/**
* 保持对帧的引用。
* 如果帧是引用计数的,则创建一个新的引用;
* 否则复制帧数据。
*/
AV_BUFFERSRC_FLAG_KEEP_REF = 8,
};
/**
* 获取失败请求的数量。
*
* 失败请求是指在缓冲区中没有帧时调用request_frame方法。
* 当添加一帧时,该数量会重置。
*/
unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src);
/**
* 此结构包含描述将传递给此过滤器的帧的参数。
*
* 应使用av_buffersrc_parameters_alloc()分配,并使用av_free()释放。
* 其中所有已分配的字段仍归调用者所有。
*/
typedef struct AVBufferSrcParameters {
/**
* 视频:像素格式,值对应于枚举AVPixelFormat
* 音频:采样格式,值对应于枚举AVSampleFormat
*/
int format;
/**
* 用于输入帧时间戳的时基。
*/
AVRational time_base;
/**
* 仅视频,输入帧的显示尺寸。
*/
int width, height;
/**
* 仅视频,采样(像素)宽高比。
*/
AVRational sample_aspect_ratio;
/**
* 仅视频,输入视频的帧率。此字段仅在输入流具有已知的恒定帧率时
* 才应设置为非零值,如果帧率是可变的或未知的,则应保持其初始值。
*/
AVRational frame_rate;
/**
* 仅适用于具有hwaccel像素格式的视频。这应该是对描述输入帧的
* AVHWFramesContext实例的引用。
*/
AVBufferRef *hw_frames_ctx;
/**
* 仅音频,音频采样率(每秒采样数)。
*/
int sample_rate;
#if FF_API_OLD_CHANNEL_LAYOUT
/**
* 仅音频,音频通道布局
* @deprecated 使用ch_layout
*/
attribute_deprecated
uint64_t channel_layout;
#endif
/**
* 仅音频,音频通道布局
*/
AVChannelLayout ch_layout;
} AVBufferSrcParameters;
/**
* 分配一个新的AVBufferSrcParameters实例。应由调用者使用av_free()释放。
*/
AVBufferSrcParameters *av_buffersrc_parameters_alloc(void);
/**
* 使用提供的参数初始化buffersrc或abuffersrc过滤器。
* 此函数可以多次调用,后面的调用会覆盖前面的调用。
* 某些参数也可以通过AVOptions设置,然后无论使用哪种方法,
* 最后使用的方法优先。
*
* @param ctx buffersrc或abuffersrc过滤器的实例
* @param param 流参数。稍后传递给此过滤器的帧必须符合这些参数。
* param中所有已分配的字段仍归调用者所有,libavfilter将在
* 必要时进行内部复制或引用。
* @return 成功返回0,失败返回负的AVERROR代码。
*/
int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *param);
/**
* 向缓冲区源添加一帧。
*
* @param ctx buffersrc过滤器的实例
* @param frame 要添加的帧。如果帧是引用计数的,此函数将创建一个新的引用。
* 否则将复制帧数据。
*
* @return 成功返回0,错误返回负的AVERROR
*
* 此函数等同于带有AV_BUFFERSRC_FLAG_KEEP_REF标志的av_buffersrc_add_frame_flags()。
*/
av_warn_unused_result
int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame);
/**
* 向缓冲区源添加一帧。
*
* @param ctx buffersrc过滤器的实例
* @param frame 要添加的帧。如果帧是引用计数的,此函数将获取引用的所有权
* 并重置帧。否则将复制帧数据。如果此函数返回错误,
* 输入帧不会被修改。
*
* @return 成功返回0,错误返回负的AVERROR。
*
* @note 此函数与av_buffersrc_write_frame()的区别在于
* av_buffersrc_write_frame()创建对输入帧的新引用,
* 而此函数获取传递给它的引用的所有权。
*
* 此函数等同于不带AV_BUFFERSRC_FLAG_KEEP_REF标志的av_buffersrc_add_frame_flags()。
*/
av_warn_unused_result
int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame);
/**
* 向缓冲区源添加一帧。
*
* 默认情况下,如果帧是引用计数的,此函数将获取引用的所有权并重置帧。
* 这可以使用标志来控制。
*
* 如果此函数返回错误,输入帧不会被修改。
*
* @param buffer_src 指向缓冲区源上下文的指针
* @param frame 一帧,或NULL表示EOF
* @param flags AV_BUFFERSRC_FLAG_*的组合
* @return 成功时返回 >= 0,失败时返回负的AVERROR代码
*/
av_warn_unused_result
int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src,
AVFrame *frame, int flags);
/**
* EOF后关闭缓冲区源。
*
* 这类似于向av_buffersrc_add_frame_flags()传递NULL,
* 不同之处在于它接受EOF的时间戳,即最后一帧结束的时间戳。
*/
int av_buffersrc_close(AVFilterContext *ctx, int64_t pts, unsigned flags);
/**
* @}
*/
#endif /* AVFILTER_BUFFERSRC_H */