searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

ffmpeg滤镜流程解析--创建滤镜上下文

2023-09-27 12:18:37
34
0
创建滤镜使用的是avfilter_graph_create_filter函数,函数里主要是调用了avfilter_graph_alloc_filter和avfilter_init_str
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph);

int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt,
                                 const char *name, const char *args, void *opaque,
                                 AVFilterGraph *graph_ctx)
{
    int ret;
    *filt_ctx = avfilter_graph_alloc_filter(graph_ctx, filt, name);
    if (!*filt_ctx)
        return AVERROR(ENOMEM);

    //根据参数,初始化上下文
    ret = avfilter_init_str(*filt_ctx, args);
    if (ret < 0)
        goto fail;

    return 0;
fail:
    if (*filt_ctx)
        avfilter_free(*filt_ctx);
    *filt_ctx = NULL;
    return ret;
}
 
下面看看avfilter_graph_alloc_filter
AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
                                             const AVFilter *filter,
                                             const char *name)
{
    AVFilterContext **filters, *s;

    //多线程??暂时不管
    if (graph->thread_type && !graph->internal->thread_execute) {
        if (graph->execute) {
            graph->internal->thread_execute = graph->execute;
        } else {
            int ret = ff_graph_thread_init(graph);
            if (ret < 0) {
                av_log(graph, AV_LOG_ERROR, "Error initializing threading: %s.\n", av_err2str(ret));
                return NULL;
            }
        }
    }

    //给滤镜初始化一个滤镜上下文
    s = ff_filter_alloc(filter, name);
    if (!s)
        return NULL;

    //申请滤镜上下文数组,realloc,再之前的基础上扩展申请
    filters = av_realloc(graph->filters, sizeof(*filters) * (graph->nb_filters + 1));
    if (!filters) {
        avfilter_free(s);
        return NULL;
    }

    //将滤镜上下文数组赋值到图表
    graph->filters = filters;
    //将当前滤镜上下文保存到数组对应的索引下
    graph->filters[graph->nb_filters++] = s;

    //同时,将图表保存到当前滤镜上下文
    s->graph = graph;

    return s;
}
 
该函数主要是:
1、申请了滤镜当前上下文
2、扩展了滤镜上下文数据长度
3、将上下文数据保存到图表
4、当前上下文保存到上下文数组中
5、将图表保存到当前滤镜上下文
其中,申请上下文函数s = ff_filter_alloc(filter, name);
AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
{
    //当前滤镜上下文
    AVFilterContext *ret;
    int preinited = 0;

    //滤镜为空,退出
    if (!filter)
        return NULL;

    //给当前上下文申请内存
    ret = av_mallocz(sizeof(AVFilterContext));
    if (!ret)
        return NULL;

    ret->av_class = &avfilter_class;
    //保存当前滤镜
    ret->filter   = filter;
    //滤镜别名,如[in],[0:v]等
    ret->name     = inst_name ? av_strdup(inst_name) : NULL;
    if (filter->priv_size) {
        ret->priv     = av_mallocz(filter->priv_size);
        if (!ret->priv)
            goto err;
    }
    if (filter->preinit) {
        if (filter->preinit(ret) < 0)
            goto err;
        preinited = 1;
    }

    av_opt_set_defaults(ret);
    //将filter中的priv_class赋值给了上下文的priv
    if (filter->priv_class) {
        *(const AVClass**)ret->priv = filter->priv_class;
        av_opt_set_defaults(ret->priv);
    }

    ret->internal = av_mallocz(sizeof(*ret->internal));
    if (!ret->internal)
        goto err;
    ret->internal->execute = default_execute;

        //遍历filter->inputs,计算inputs的长度
    ret->nb_inputs = avfilter_pad_count(filter->inputs);
    //将filter->inputs拷贝到上下文的input_pads
    if (ret->nb_inputs ) {
        ret->input_pads   = av_malloc_array(ret->nb_inputs, sizeof(AVFilterPad));
        if (!ret->input_pads)
            goto err;
        memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->nb_inputs);
        ret->inputs       = av_mallocz_array(ret->nb_inputs, sizeof(AVFilterLink*));
        if (!ret->inputs)
            goto err;
    }

    //遍历filter->outputs,计算outputs的长度
    ret->nb_outputs = avfilter_pad_count(filter->outputs);
    //将filter->outputs拷贝到上下文的output_pads
    if (ret->nb_outputs) {
        ret->output_pads  = av_malloc_array(ret->nb_outputs, sizeof(AVFilterPad));
        if (!ret->output_pads)
            goto err;
        memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->nb_outputs);
        ret->outputs      = av_mallocz_array(ret->nb_outputs, sizeof(AVFilterLink*));
        if (!ret->outputs)
            goto err;
    }

    return ret;

err:
    if (preinited)
        filter->uninit(ret);
    av_freep(&ret->inputs);
    av_freep(&ret->input_pads);
    ret->nb_inputs = 0;
    av_freep(&ret->outputs);
    av_freep(&ret->output_pads);
    ret->nb_outputs = 0;
    av_freep(&ret->priv);
    av_freep(&ret->internal);
    av_free(ret);
    return NULL;
}
 
这个函数主要是:
1、申请上下文内存
2、存储当前滤镜到滤镜上下文
3、将filter中的priv_class赋值给了上下文的priv
4、将filter->inputs拷贝到上下文的input_pads
5、将filter->outputs拷贝到上下文的output_pads
 
总结下来,创建滤镜上下文的流程为:
1、申请了滤镜当前上下文
  • 申请上下文内存
  • 存储当前滤镜到滤镜上下文
  • 将filter中的priv_class赋值给了上下文的priv
  • 将filter->inputs拷贝到上下文的input_pads
  • 将filter->outputs拷贝到上下文的output_pads
2、扩展了滤镜上下文数组长度
3、将上下文数组保存到图表
4、当前上下文保存到上下文数组中
5、将图表保存到当前滤镜上下文
申请滤镜当前上下文
filter_ctx->filter = filter
filter_ctx->priv = filter->priv_class
filter_ctx->input_pads = filter->inputs
filter_ctx->output_pads = filter->outputs
将上下文保存到图表
graph->filters[graph->nb_filters++] = filter_ctx
将图表保存到当前滤镜上下文
filter_ctx->graph = graph;
 
创建完上下文后,则开始对上下文进行初始化:ret = avfilter_init_str(*filt_ctx, args);该函数主要是调用了:process_options和avfilter_init_dict;process_options主要是设置参数到滤镜,
具体是设置到了滤镜的priv_class中和滤镜上下文中的class中;
avfilter_init_dict主要是调用filter的init,init_opaque,和init_dict函数
    
if (ctx->filter->priv_class) {
        ret = av_opt_set_dict2(ctx->priv, options, AV_OPT_SEARCH_CHILDREN);
        if (ret < 0) {
            av_log(ctx, AV_LOG_ERROR, "Error applying options to the filter.\n");
            return ret;
        }
    }

    if (ctx->filter->init_opaque)
        ret = ctx->filter->init_opaque(ctx, NULL);
    else if (ctx->filter->init)
        ret = ctx->filter->init(ctx);
    else if (ctx->filter->init_dict)
        ret = ctx->filter->init_dict(ctx, options);
0条评论
作者已关闭评论
y****n
4文章数
0粉丝数
y****n
4 文章 | 0 粉丝
原创

ffmpeg滤镜流程解析--创建滤镜上下文

2023-09-27 12:18:37
34
0
创建滤镜使用的是avfilter_graph_create_filter函数,函数里主要是调用了avfilter_graph_alloc_filter和avfilter_init_str
ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph);

int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt,
                                 const char *name, const char *args, void *opaque,
                                 AVFilterGraph *graph_ctx)
{
    int ret;
    *filt_ctx = avfilter_graph_alloc_filter(graph_ctx, filt, name);
    if (!*filt_ctx)
        return AVERROR(ENOMEM);

    //根据参数,初始化上下文
    ret = avfilter_init_str(*filt_ctx, args);
    if (ret < 0)
        goto fail;

    return 0;
fail:
    if (*filt_ctx)
        avfilter_free(*filt_ctx);
    *filt_ctx = NULL;
    return ret;
}
 
下面看看avfilter_graph_alloc_filter
AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
                                             const AVFilter *filter,
                                             const char *name)
{
    AVFilterContext **filters, *s;

    //多线程??暂时不管
    if (graph->thread_type && !graph->internal->thread_execute) {
        if (graph->execute) {
            graph->internal->thread_execute = graph->execute;
        } else {
            int ret = ff_graph_thread_init(graph);
            if (ret < 0) {
                av_log(graph, AV_LOG_ERROR, "Error initializing threading: %s.\n", av_err2str(ret));
                return NULL;
            }
        }
    }

    //给滤镜初始化一个滤镜上下文
    s = ff_filter_alloc(filter, name);
    if (!s)
        return NULL;

    //申请滤镜上下文数组,realloc,再之前的基础上扩展申请
    filters = av_realloc(graph->filters, sizeof(*filters) * (graph->nb_filters + 1));
    if (!filters) {
        avfilter_free(s);
        return NULL;
    }

    //将滤镜上下文数组赋值到图表
    graph->filters = filters;
    //将当前滤镜上下文保存到数组对应的索引下
    graph->filters[graph->nb_filters++] = s;

    //同时,将图表保存到当前滤镜上下文
    s->graph = graph;

    return s;
}
 
该函数主要是:
1、申请了滤镜当前上下文
2、扩展了滤镜上下文数据长度
3、将上下文数据保存到图表
4、当前上下文保存到上下文数组中
5、将图表保存到当前滤镜上下文
其中,申请上下文函数s = ff_filter_alloc(filter, name);
AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
{
    //当前滤镜上下文
    AVFilterContext *ret;
    int preinited = 0;

    //滤镜为空,退出
    if (!filter)
        return NULL;

    //给当前上下文申请内存
    ret = av_mallocz(sizeof(AVFilterContext));
    if (!ret)
        return NULL;

    ret->av_class = &avfilter_class;
    //保存当前滤镜
    ret->filter   = filter;
    //滤镜别名,如[in],[0:v]等
    ret->name     = inst_name ? av_strdup(inst_name) : NULL;
    if (filter->priv_size) {
        ret->priv     = av_mallocz(filter->priv_size);
        if (!ret->priv)
            goto err;
    }
    if (filter->preinit) {
        if (filter->preinit(ret) < 0)
            goto err;
        preinited = 1;
    }

    av_opt_set_defaults(ret);
    //将filter中的priv_class赋值给了上下文的priv
    if (filter->priv_class) {
        *(const AVClass**)ret->priv = filter->priv_class;
        av_opt_set_defaults(ret->priv);
    }

    ret->internal = av_mallocz(sizeof(*ret->internal));
    if (!ret->internal)
        goto err;
    ret->internal->execute = default_execute;

        //遍历filter->inputs,计算inputs的长度
    ret->nb_inputs = avfilter_pad_count(filter->inputs);
    //将filter->inputs拷贝到上下文的input_pads
    if (ret->nb_inputs ) {
        ret->input_pads   = av_malloc_array(ret->nb_inputs, sizeof(AVFilterPad));
        if (!ret->input_pads)
            goto err;
        memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->nb_inputs);
        ret->inputs       = av_mallocz_array(ret->nb_inputs, sizeof(AVFilterLink*));
        if (!ret->inputs)
            goto err;
    }

    //遍历filter->outputs,计算outputs的长度
    ret->nb_outputs = avfilter_pad_count(filter->outputs);
    //将filter->outputs拷贝到上下文的output_pads
    if (ret->nb_outputs) {
        ret->output_pads  = av_malloc_array(ret->nb_outputs, sizeof(AVFilterPad));
        if (!ret->output_pads)
            goto err;
        memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->nb_outputs);
        ret->outputs      = av_mallocz_array(ret->nb_outputs, sizeof(AVFilterLink*));
        if (!ret->outputs)
            goto err;
    }

    return ret;

err:
    if (preinited)
        filter->uninit(ret);
    av_freep(&ret->inputs);
    av_freep(&ret->input_pads);
    ret->nb_inputs = 0;
    av_freep(&ret->outputs);
    av_freep(&ret->output_pads);
    ret->nb_outputs = 0;
    av_freep(&ret->priv);
    av_freep(&ret->internal);
    av_free(ret);
    return NULL;
}
 
这个函数主要是:
1、申请上下文内存
2、存储当前滤镜到滤镜上下文
3、将filter中的priv_class赋值给了上下文的priv
4、将filter->inputs拷贝到上下文的input_pads
5、将filter->outputs拷贝到上下文的output_pads
 
总结下来,创建滤镜上下文的流程为:
1、申请了滤镜当前上下文
  • 申请上下文内存
  • 存储当前滤镜到滤镜上下文
  • 将filter中的priv_class赋值给了上下文的priv
  • 将filter->inputs拷贝到上下文的input_pads
  • 将filter->outputs拷贝到上下文的output_pads
2、扩展了滤镜上下文数组长度
3、将上下文数组保存到图表
4、当前上下文保存到上下文数组中
5、将图表保存到当前滤镜上下文
申请滤镜当前上下文
filter_ctx->filter = filter
filter_ctx->priv = filter->priv_class
filter_ctx->input_pads = filter->inputs
filter_ctx->output_pads = filter->outputs
将上下文保存到图表
graph->filters[graph->nb_filters++] = filter_ctx
将图表保存到当前滤镜上下文
filter_ctx->graph = graph;
 
创建完上下文后,则开始对上下文进行初始化:ret = avfilter_init_str(*filt_ctx, args);该函数主要是调用了:process_options和avfilter_init_dict;process_options主要是设置参数到滤镜,
具体是设置到了滤镜的priv_class中和滤镜上下文中的class中;
avfilter_init_dict主要是调用filter的init,init_opaque,和init_dict函数
    
if (ctx->filter->priv_class) {
        ret = av_opt_set_dict2(ctx->priv, options, AV_OPT_SEARCH_CHILDREN);
        if (ret < 0) {
            av_log(ctx, AV_LOG_ERROR, "Error applying options to the filter.\n");
            return ret;
        }
    }

    if (ctx->filter->init_opaque)
        ret = ctx->filter->init_opaque(ctx, NULL);
    else if (ctx->filter->init)
        ret = ctx->filter->init(ctx);
    else if (ctx->filter->init_dict)
        ret = ctx->filter->init_dict(ctx, options);
文章来自个人专栏
流媒体
4 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0