201410 22
Ffmpeg1.0 Filter format流程分析
Ffmpeg –y – i vga.3gp –vcodec libx264 –an –strict -2 merge.3gp
Filter爲: buffer->null->format->ffbuffersink
第三行的 query_formats位於avfilter\avfiltergraph.c文件裏,主要代碼如下:
static intquery_formats(AVFilterGraph *graph, AVClass *log_ctx)
{
AVFilterFormats* a,*b;
int i, j,ret;
charfilt_args[128];
AVFilterFormats *formats;
AVFilterChannelLayouts *chlayouts;
AVFilterFormats *samplerates;
intscaler_count = 0, resampler_count = 0;
//下面這個奇怪的循環是一個臨時解決方案,目的是讓buffer filter(souce) 的query_formats函數先被調用。Filter鏈: buffer->null->format->ffbuffersink,但是在內存裏卻是:graph->filters[0]=null, graph->filters[1]=buffer,graph->filters[2]= ffbuffersink, graph->filters[3]= format.
for (j = 0; j< 2; j++) {
/* ask all thesub-filters for their supported media formats */
for (i = 0;i < graph->filter_count; i++) {
/* Callquery_formats on sources first.
This is a temporary workaround foramerge,
until format renegociation isimplemented. */
if(!graph->filters[i]->nb_inputs == j)
continue;
if(graph->filters[i]->filter->query_formats)
ret =filter_query_formats(graph->filters[i]); //會調用avfiltergraph.c文件的filter_query_formats函數
else
ret =ff_default_query_formats(graph->filters[i]);//會調用ff_set_common_formats(ctx, ff_all_formats(type)),將所有formt都設置到in_formats或者out_formats,如果有的話
if (ret< 0)
returnret;
}
}
/* go through andmerge as many format lists as possible */
for (i = 0;i < graph->filter_count; i++) {
AVFilterContext *filter =graph->filters[i];
for (j= 0; j < filter->nb_inputs; j++) {
AVFilterLink *link = filter->inputs[j];
intconvert_needed = 0;
if(!link)
continue;
if(link->in_formats != link->out_formats &&
!ff_merge_formats(link->in_formats,
link->out_formats)) //合併filter,見下面具體函數
convert_needed = 1;
if(link->type == AVMEDIA_TYPE_AUDIO) {
if(link->in_channel_layouts != link->out_channel_layouts &&
!ff_merge_channel_layouts(link->in_channel_layouts,
link->out_channel_layouts))
convert_needed = 1;
if(link->in_samplerates != link->out_samplerates &&
!ff_merge_samplerates(link->in_samplerates,
link->out_samplerates))
convert_needed = 1;
}
if(convert_needed) {//格式需要轉換,插入新的filter
AVFilterContext *convert;
AVFilter *filter;
AVFilterLink *inlink, *outlink;
charscale_args[256];
charinst_name[30];
/*couldn't merge format lists. auto-insert conversion filter */
switch(link->type) {
caseAVMEDIA_TYPE_VIDEO:
if(!(filter = avfilter_get_by_name("scale"))){
av_log(log_ctx, AV_LOG_ERROR, "'scale' filter "
"not present, cannot convert pixel formats.\n");
return AVERROR(EINVAL);
}
snprintf(inst_name, sizeof(inst_name), "auto-insertedscaler %d",
scaler_count++);
snprintf(scale_args, sizeof(scale_args), "0:0:%s",graph->scale_sws_opts);
if((ret = avfilter_graph_create_filter(&convert, filter,
inst_name, scale_args, NULL,
graph)) < 0)
return ret;
break;
caseAVMEDIA_TYPE_AUDIO:
if(!(filter = avfilter_get_by_name("aresample"))){
av_log(log_ctx,AV_LOG_ERROR, "'aresample' filter "
"not present, cannot convert audio formats.\n");
returnAVERROR(EINVAL);
}
snprintf(inst_name, sizeof(inst_name), "auto-insertedresampler %d",
resampler_count++);
if((ret = avfilter_graph_create_filter(&convert, filter,
inst_name, NULL, NULL, graph)) < 0)
return ret;
break;
default:
returnAVERROR(EINVAL);
}
if((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0)
returnret;
filter_query_formats(convert);
inlink = convert->inputs[0];
outlink =convert->outputs[0];
av_log(NULL, AV_LOG_INFO, "inlink->in_formats->format_count =%d\n",inlink->in_formats->format_count);
av_log(NULL, AV_LOG_INFO, "inlink->out_formats->format_count =%d\n",inlink->out_formats->format_count);
av_log(NULL, AV_LOG_INFO, "outlink->in_formats->format_count =%d\n",outlink->in_formats->format_count);
av_log(NULL, AV_LOG_INFO, "outlink->out_formats->format_count=%d\n",outlink->out_formats->format_count);
a = ff_merge_formats(inlink->in_formats, inlink->out_formats);
b =ff_merge_formats(outlink->in_formats, outlink->out_formats);
if(!a ||
!b)
ret |= AVERROR(ENOSYS);
if(inlink->type == AVMEDIA_TYPE_AUDIO &&
(!ff_merge_samplerates(inlink->in_samplerates,
inlink->out_samplerates) ||
!ff_merge_channel_layouts(inlink->in_channel_layouts,
inlink->out_channel_layouts)))
ret |= AVERROR(ENOSYS);
if(outlink->type == AVMEDIA_TYPE_AUDIO &&
(!ff_merge_samplerates(outlink->in_samplerates,
outlink->out_samplerates) ||
!ff_merge_channel_layouts(outlink->in_channel_layouts,
outlink->out_channel_layouts)))
ret |= AVERROR(ENOSYS);
if(ret < 0) {
av_log(log_ctx,AV_LOG_ERROR,
"Impossible to convert between the formats supportedby the filter "
"'%s' and the filter '%s'\n",link->src->name, link->dst->name);
returnret;
}
}
}
}
return 0;
}
avfiltergraph.c文件的filter_query_formats函數:
static intfilter_query_formats(AVFilterContext *ctx)
{
int ret;
AVFilterFormats *formats;
AVFilterChannelLayouts *chlayouts;
AVFilterFormats *samplerates;
enumAVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :
ctx->outputs&& ctx->outputs[0] ? ctx->outputs[0]->type :
AVMEDIA_TYPE_VIDEO;
if ((ret =ctx->filter->query_formats(ctx)) < 0) //會調用buffersrc.c/vf_format/文件的query_formats函數
returnret;
formats = ff_all_formats(type);
if(!formats)
returnAVERROR(ENOMEM);
ff_set_common_formats(ctx, formats);
if (type ==AVMEDIA_TYPE_AUDIO) {
samplerates = ff_all_samplerates();
if(!samplerates)
returnAVERROR(ENOMEM);
ff_set_common_samplerates(ctx,samplerates);
chlayouts = ff_all_channel_layouts();
if(!chlayouts)
returnAVERROR(ENOMEM);
ff_set_common_channel_layouts(ctx,chlayouts);
}
return 0;
}
buffersrc.c文件的query_formats函數:
static intquery_formats(AVFilterContext *ctx)
{
BufferSourceContext *c = ctx->priv;
AVFilterChannelLayouts *channel_layouts =NULL;
AVFilterFormats *formats = NULL;
AVFilterFormats *samplerates = NULL;
switch(ctx->outputs[0]->type) {
caseAVMEDIA_TYPE_VIDEO:
ff_add_format(&formats,c->pix_fmt);//生成新的AVFilterFormats* 對象
ff_set_common_formats(ctx, formats);//設置AVFilterContext的in_formats或者out_formats指向formats,並將formats->refs[f->refcount-1] = &ctx->in_formats,表示formats已經被in_formats引用了。
break;
caseAVMEDIA_TYPE_AUDIO:
ff_add_format(&formats, c->sample_fmt);
ff_set_common_formats(ctx, formats);
ff_add_format(&samplerates, c->sample_rate);
ff_set_common_samplerates(ctx,samplerates);
ff_add_channel_layout(&channel_layouts, c->channel_layout);
ff_set_common_channel_layouts(ctx,channel_layouts);
break;
default:
returnAVERROR(EINVAL);
}
return 0;
}
avfiltergraph.c文件query_formats函數調用 !ff_merge_formats(link->in_formats,link->out_formats)) 時,in_formats/ out_formats內容如下,結合AVFilterFormats的原型,可見:
struct AVFilterFormats {
unsignedformat_count; ///< number of formats
int*formats; ///< list of media formats
unsignedrefcount; ///< number of references to this list
structAVFilterFormats ***refs;///< references to thislist
};
Refs是指向AVFilterFormats **的指針,其大小是動態分配的,大小由refcount決定。Reft[i] 就是link->in_formats的地址,表示link->in_format引用了formats。合併前,link->in_format/link->out_format的值是不同的。
AVFilterFormats*ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b)
{
AVFilterFormats *ret = NULL;
if (a == b)
returna;
//MERGE_FORMATS(ret,a, b, formats, format_count, AVFilterFormats, fail);
ret = MERGE_FORMATS1(ret, a, b);
if(NULL== ret)
gotofail;
return ret;
fail:
if (ret) {
av_freep(&ret->refs);
av_freep(&ret->formats);
}
av_freep(&ret);
returnNULL;
}
AVFilterFormats*MERGE_FORMATS1(AVFilterFormats* ret, AVFilterFormats* a, AVFilterFormats*b)
{
int i, j, k= 0, count = FFMIN(a->format_count, b->format_count);
if (!(ret =av_mallocz(sizeof(*ret))))
returnNULL;
if (count){
if(!(ret->formats = av_malloc(sizeof(*ret->formats)* count)))
returnNULL;
for (i= 0; i < a->format_count; i++)
for(j = 0; j < b->format_count; j++)
if(a->formats[i] == b->formats[j]) {
if(k>= FFMIN(a->format_count, b->format_count)){
av_log(0, AV_LOG_ERROR,"Duplicate formats in avfilter_merge_formats()detected\n");
av_free(ret->formats);
av_free(ret);
return NULL;
}
ret->formats[k++] =a->formats[i];//將相同的format提前出來,賦值到新的ret
}
}
ret->format_count = k;
/* check thatthere was at least one common format */
if(!ret->format_count)
{
av_log(NULL, AV_LOG_INFO, "MERGE_FORMATS:ret->nb=%d\n",ret->format_count);
returnNULL;
}
MERGE_REF1(ret, a); //將新的ret和a的ref合併
MERGE_REF1(ret, b);
returnret;
}
void MERGE_REF1(AVFilterFormats* ret,AVFilterFormats* a)
{
AVFilterFormats ***tmp;
int i;
//分配新的refs
if (!(tmp =av_realloc(ret->refs,
sizeof(*tmp) * (ret->refcount + a->refcount))))
return;
ret->refs = tmp;
for (i = 0;i < a->refcount; i ++) {
ret->refs[ret->refcount] =a->refs[i]; //將老的引用的地址賦值給新的,一般也就是&link->in_format /&link->out_format
*ret->refs[ret->refcount++] =ret; //引用指向新的 AVFilterFormats*,一般也就是link->in_format /link->out_format有了新值
}
av_freep(&a->refs);
av_freep(&a->formats);
av_freep(&a);
}
所以,執行完成後,link->in_format /link->out_format值相等了,並且發生了變化: