El filtro en FFMPEG usa dos

En el artículo anterior, cuando usamos filtros, creamos manualmente varios filtros y luego vinculamos manualmente diferentes filtros de acuerdo con el enlace de procesamiento, lo que nos ayudó a comprender el proceso de filtrado. En este artículo, usamos el formulario de parámetros para permitir que ffmpeg cree y vincule automáticamente los filtros para nosotros, lo que puede reducir la cantidad de código. Al mismo tiempo, podemos usar primero la prueba de parámetros y luego copiar directamente los parámetros en el código. para usar.

Preparar

ffme 4.4

Un archivo de video en formato MP4 o flv

flujo de procesamiento

Aquí tenemos que explicar:

En primer lugar, debemos comprender la sintaxis del gráfico de filtro. Cada filtro tiene al menos una entrada y una salida. Para un filtro con múltiples entradas y salidas, cómo especificar qué entrada y salida vincular con otros filtros, por lo que debe especificar un etiqueta, como el siguiente comando

[in]escala=iw/2:ih/2[in_tmp];[in_tmp]split=2[in_1][in_2];[in_1]pad=iw*2:ih*2:color=amarillo[a];[ a][en_2]superposición=w[fuera]

El filtro dividido anterior copia el cuadro de video de entrada en 2 salidas y especifica los nombres como [in_1] y [in_2], [in_2] se usa como la segunda entrada del filtro de superposición, y [in_1] es procesado por el filtro de almohadilla como la primera entrada a la superposición.

Los dos nombres [in] y [out] son ​​los predeterminados del sistema. También puede modificarlo usted mismo.

Bueno, veamos el diagrama de flujo de arriba.

/*
    和 avfilter_graph_parse 类似。不同的是 inputs 和 outputs 参数,即做输入参数,也做输出参数。
        在函数返回时,它们将会保存 graph 中所有的处于 open 状态的 pad。返回的 inout 应该使用 avfilter_inout_free() 释放掉。
    
    注意:在字符串描述的 graph 中,第一个 filter 的输入如果没有被一个字符串标识,默认其标识为"in",最后一个 filter 的输出如果没有被标识,默认为"output"。
    
    intpus:作为输入参数是,用于保存已经存在的graph的open inputs,可以为NULL。
        作为输出参数,用于保存这个parse函数之后,仍然处于open的inputs,当然如果传入为NULL,则并不输出。
    outputs:同上。
*/
int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters,
                             AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx);

El método avfilter_graph_parse_ptr analiza los filtros en la cadena de filtros, crea filtros y los vincula. En él se utilizan dos estructuras AVFilterInOut. como sigue:

    AVFilterInOut* outputs = avfilter_inout_alloc();
    AVFilterInOut* inputs = avfilter_inout_alloc();    

    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx = 0;
    outputs->next = NULL;

    inputs->name = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;

las salidas y las entradas especifican respectivamente un contexto de filtro y un nombre de pin. Aquí está realmente el búfer y el receptor de búfer.

Luego, el método avfilter_graph_parse_ptr vinculará el filtro con el pin de entrada del filtro en la cadena a las salidas, y el filtro con el pin de salida a las entradas. De esta manera, los filtros buffer y buffersink se agregan a toda la cadena de filtros, formando una cadena de filtros completa.

Cuando creamos buffer y buffersink, ordenamos que el nombre de salida del buffer estuviera dentro y el nombre de entrada de buffersink fuera.

Aquí nos fijamos en los parámetros [in]......[out], de hecho, es para vincularlos con los nombres correspondientes.

   
const char* filter_descr = "[in]scale=iw/2:ih/2[in_tmp];[in_tmp]split=2[in_1][in_2];[in_1]pad=iw*2:ih*2:color=yellow[a];[a][in_2]overlay=w[out]";

 char args[512];
    int ret = 0;
    const AVFilter* buffersrc = avfilter_get_by_name("buffer");//预缓存帧数据。用于输入
    const AVFilter* buffersink = avfilter_get_by_name("buffersink");//缓冲视频帧,并使它们可用于过滤器图形的末尾。用于输出
    AVFilterInOut* outputs = avfilter_inout_alloc();
    AVFilterInOut* inputs = avfilter_inout_alloc();
    AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;
    enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };//注意输入的格式类型pix_fmts[0]

    filter_graph = avfilter_graph_alloc();
    if (!outputs || !inputs || !filter_graph) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /* buffer video source: the decoded frames from the decoder will be inserted here. */
    snprintf(args, sizeof(args),
        "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
        dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
        time_base.num, time_base.den,
        dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);

    //创建和初始化过滤器实例并将其添加到现有图形中。【输入】
    ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
        args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
        goto end;
    }

    //创建和初始化过滤器实例并将其添加到现有图形中。【输出】
    /* buffer video sink: to terminate the filter chain. */
    ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
        NULL, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
        goto end;
    }

    //给buffersink_ctx设置参数
    ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
        AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
        goto end;
    }

    /*
     * Set the endpoints for the filter graph. The filter_graph will
     * be linked to the graph described by filters_descr.
     */

  
    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx = 0;
    outputs->next = NULL;


    inputs->name = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;

    //将字符串描述的图形添加到图形中。
    if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "Error avfilter_graph_parse_ptr\n");
        goto end;
    }

    //检查AVFilterGraph有效性
    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Error avfilter_graph_config\n");
        goto end;
    }

Supongo que te gusta

Origin blog.csdn.net/yunxiaobaobei/article/details/130447191
Recomendado
Clasificación