Ffmpeg 1.0 Filter format流程分析

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值相等了,並且發生了變化:




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章