FFMPEG のフィルターは 2 つを使用します。

前回の記事では、フィルターを使用するときに、さまざまなフィルターを手動で作成し、処理リンクに従って異なるフィルターを手動でリンクすることで、フィルター処理を理解するのに役立ちました。この記事では、パラメーター フォームを使用して、ffmpeg に自動的にフィルターを作成してリンクさせ、コードの量を減らすことができます。同時に、最初にパラメーター テストを使用し、次にパラメーターをコードに直接コピーすることもできます。使用するために。

準備する

ffme 4.4

MP4またはflv形式のビデオファイル

処理の流れ

ここで次のことを説明する必要があります。

まず第一に、フィルターグラフの構文を理解する必要があります。各フィルターには少なくとも 1 つの入力と出力があります。複数の入力と出力を持つフィルターの場合、どの入力と出力を他のフィルターとリンクするかを指定する方法を指定する必要があります。ラベル(次のコマンドなど)

[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]オーバーレイ=w[out]

上記の分割フィルターは、入力ビデオ フレームを 2 つの出力にコピーし、名前を [in_1] と [in_2] として指定します。[in_2] はオーバーレイ フィルターの 2 番目の入力として使用され、[in_1] はパッド フィルターによって次のように処理されます。オーバーレイへの最初の入力。

[in] と [out] の 2 つの名前はシステムのデフォルトです。自分で変更することもできます。

さて、上のフローチャートを見てみましょう。

/*
    和 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);

メソッド avfilter_graph_parse_ptr は、フィルター文字列内のフィルターを解析し、フィルターを作成してリンクします。その中で 2 つの AVFilterInOut 構造体が使用されています。次のように:

    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;

出力、入力はそれぞれフィルター コンテキストとピン名を指定します。ここに実際のバッファとバッファシンクがあります。

次に、 avfilter_graph_parse_ptr メソッドは、文字列内のフィルターの入力ピンを持つフィルターを出力にリンクし、出力ピンを持つフィルターを入力にリンクします。このようにして、バッファー フィルターとバッファーシンク フィルターがフィルター チェーン全体に追加され、完全なフィルター チェーンが形成されます。

バッファとバッファシンクを作成したとき、バッファの出力名が入力されるように、バッファシンクの入力名が出力されるように順序付けしました。

ここでパラメータ [in]....[out] を見てみましょう。実際には、パラメータを対応する名前にリンクすることです。

   
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;
    }

おすすめ

転載: blog.csdn.net/yunxiaobaobei/article/details/130447191