1. ffmpeg anull 是个啥?
----------------------------------------
author: hjjdebug
date: 2023年 07月 13日 星期四 17:59:47 CST
----------------------------------------
当然是ffmpeg audio filter了,
$ ffmpeg -h filter=anull
给出了如下信息:
Filter anull
Pass the source unchanged to the output.
Inputs:
#0: default (audio)
Outputs:
#0: default (audio)
这些信息是怎么来的? 它实际上打印了anull 对象定义的一些信息.
anull 对象是一个全局对象,它的地址是通过avfilter_get_by_name()找到的.
其它的引脚等,都是找的定义的变量或函数.
因为它简单,所以才好分析.
2. 打开ffmpeg4.4/libavfilter/af_anull.c
这里就是其真身了, 非常简单.
static const AVFilterPad avfilter_af_anull_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
},
{ NULL }
};
static const AVFilterPad avfilter_af_anull_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
},
{ NULL }
};
AVFilter ff_af_anull = {
.name = "anull",
.description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
.inputs = avfilter_af_anull_inputs,
.outputs = avfilter_af_anull_outputs,
};
3. 关键是它是如何工作的?
3.1: 先分析一下 ffmpeg -h filter=anull 的执行过程.
因为命令行里有-h 选项,所以执行了 show_help()函数
由于参数是filter=anull, 从=号处分割,前为"filter", 后为"anull"
所以调用: show_help_filter("anull")
首先获取filter , 过程是枚举,这里忽略.拿到了AVFilter 对象的指针ff_af_anull, 在文件中定义的全局对象
const AVFilter *f = avfilter_get_by_name(name);
关键成员如下:
$9 = {
name = 0x7ffff65e9e38 "anull",
description = 0x7ffff65e9e40 "Pass the source unchanged to the output.",
inputs = 0x7ffff6673ee0
outputs = 0x7ffff6673f60
priv_class = 0x0,
flags = 0,
...
}
首先打印filter 名字 printf("Filter %s\n", f->name); //这就是 打印输出 "Filter anull" 的来历
然后打印filter 描述 printf(" %s\n", f->description); //这就是 打印输出 "Pass the source unchanged to the output."的来历
然后打印输入: printf(" Inputs:\n");
然后是每一个引脚的序号,名称,类型
int count = avfilter_pad_count(f->inputs);
for (i = 0; i < count; i++) {
printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i),
media_type_string(avfilter_pad_get_type(f->inputs, i)));
}
同理, 打印输出引脚信息:
printf(" Outputs:\n");
count = avfilter_pad_count(f->outputs);
for (i = 0; i < count; i++) {
printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i),
media_type_string(avfilter_pad_get_type(f->outputs, i)));
}
我们挖地三尺,继续看看下一层.
3.1.1: count = avfilter_pad_count(f->inputs);
int avfilter_pad_count(const AVFilterPad *pads)
{
int count;
for (count = 0; pads->name; count++)
pads++;
return count;
}
我们看到,代码里只定义了一个输入脚,所以count 返回1, 同理输出也一样.
3.1.2: avfilter_pad_get_name(f->inputs,i)
#define media_type_string av_get_media_type_string
const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx)
{
return pads[pad_idx].name; //给了pads 指针,又给了idx,当然可以返回name, 这个指针对anull而言必然是文件中定义的地址.
}
enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx)
{
return pads[pad_idx].type;
}
const char *av_get_media_type_string(enum AVMediaType media_type)
{
switch (media_type) {
case AVMEDIA_TYPE_VIDEO: return "video";
case AVMEDIA_TYPE_AUDIO: return "audio";
case AVMEDIA_TYPE_DATA: return "data";
case AVMEDIA_TYPE_SUBTITLE: return "subtitle";
case AVMEDIA_TYPE_ATTACHMENT: return "attachment";
default: return NULL;
}
}
至此对 ffmpeg -h filter=anull 分析完毕!
3.2 anull filter 是如何工作的?
那需要分析一下如下命令是如何工作的.
ffmpeg -y -i /opt/test/test.ts -af anull 1.ts