在Android NDK中使用Libavfilter库实现多输入过滤器图

在Android NDK中使用Libavfilter库实现多输入过滤器图,android,android-ndk,ffmpeg,Android,Android Ndk,Ffmpeg,我正在尝试为Android应用程序使用带有多个输入源的overlay过滤器。基本上,我想在静态图像上叠加多个视频源。 我已经查看了ffmpeg附带的示例,并在此基础上实现了我的代码,但事情似乎没有按预期进行 在ffmpeg过滤示例中,似乎只有一个视频输入。我必须处理多个视频输入,我不确定我的解决方案是否正确。我试图找到其他的例子,但似乎这是唯一的一个 这是我的密码: AVFilterContext**InputContext; AVFilterContext*输出上下文; AVFilterGra

我正在尝试为Android应用程序使用带有多个输入源的
overlay
过滤器。基本上,我想在静态图像上叠加多个视频源。 我已经查看了ffmpeg附带的示例,并在此基础上实现了我的代码,但事情似乎没有按预期进行

在ffmpeg过滤示例中,似乎只有一个视频输入。我必须处理多个视频输入,我不确定我的解决方案是否正确。我试图找到其他的例子,但似乎这是唯一的一个

这是我的密码:

AVFilterContext**InputContext;
AVFilterContext*输出上下文;
AVFilterGraph*图;
int initFilters(AVFrame*bgFrame,int inputCount,AVCodecContext**codeccontext,char*过滤器)
{
int i;
返回码;
char-args[512];
字符名[9];
AVFilterInOut**graphInputs=NULL;
AVFilterInOut*Graphhoutput=NULL;
AVFilter*bufferSrc=AVFilter_get_by_name(“buffer”);
AVFilter*bufferSink=AVFilter_get_by_name(“bufferSink”);
graph=avfilter_graph_alloc();
if(图==NULL)
返回-1;
//分配投入
graphInputs=av_calloc(inputCount+1,sizeof(AVFilterInOut*);
用于(i=0;i宽度,bgFrame->高度,bgFrame->格式);
returnCode=avfilter\u graph\u create\u filter(&inputContexts[0],bufferSrc,“background”,args,NULL,graph);
如果(返回代码<0)
返回代码;
graphInputs[0]->filter_ctx=inputContexts[0];
graphInputs[0]->name=av_strdup(“背景”);
graphInputs[0]->next=graphInputs[1];
//分配其余的
对于(i=1;i宽度,codecCtx->高度,codecCtx->pix_fmt,
codecCtx->time\u base.num,codecCtx->time\u base.den,
codecCtx->sample\u aspect\u ratio.num,codecCtx->sample\u aspect\u ratio.den);
snprintf(名称,sizeof(名称),“视频”,i);
returnCode=avfilter\u graph\u create\u filter(&inputContexts[i],bufferSrc,name,args,NULL,graph);
如果(返回代码<0)
返回代码;
graphInputs[i]>filter_ctx=inputContexts[i];
图形输入[i]->name=av_strdup(name);
图形输入[i]>pad_idx=0;
如果(i<输入计数)
{
graphInputs[i]>next=graphInputs[i+1];
}
其他的
{
graphInputs[i]>next=NULL;
}
}
//分配产出
graphhoutput=avfilter_inout_alloc();
returnCode=avfilter\u graph\u create\u filter(&outputContext,bufferSink,“out”,NULL,NULL,graph);
如果(返回代码<0)
返回代码;
graphhoutput->filter\u ctx=outputContext;
graphhoutput->name=av_strdup(“out”);
graphhoutput->next=NULL;
图形输出->pad_idx=0;
returnCode=avfilter\u graph\u parse\u ptr(graph、filters、graphInputs和graphOutput,NULL);
如果(返回代码<0)
返回代码;
returnCode=avfilter\u graph\u config(图形,NULL);
返回代码;
返回0;
}
函数的
filters
参数被传递到
avfilter\u graph\u parse\u ptr
,它可以如下所示:
[background]scale=512x512[base];[video_1]比例=256x256[tmp_1];[base][tmp_1]overlay=0:0[out]

调用
avfilter\u graph\u config
后,调用中断,并显示警告:
输出pad“default”,其中缓冲区的筛选器实例“background”的类型video未连接到任何目标
,并且错误
参数无效

我做得不对的是什么

编辑:我发现了两个问题:

  • 看起来
    avfilter\u graph\u parse\u ptr
    的描述有点模糊。
    outputs
    参数表示图形的当前输出列表,在我的例子中,它是
    graphInputs
    变量,因为这些是来自
    缓冲区的输出。
    inputs
    参数表示图形当前输入的列表,在这种情况下,这是
    graphhoutput
    变量,因为它表示
    buffersink
    过滤器的输入

  • 我用
    scale
    过滤器和单个输入进行了一些测试。似乎
    avfilter\u graph\u parse\u ptr
    所需的
    AVFilterInOut
    结构的名称需要是
    in
    。我尝试过不同的版本:
    in_1
    in_link_1
    。它们都不起作用,我也没有找到任何与此相关的文档


  • 因此,问题仍然存在。如何实现具有多个输入的过滤图?

    我找到了一个简单的解决方案。 这涉及到用
    avfilter\u graph\u parse2
    替换
    avfilter\u graph\u parse2
    并将
    buffer
    buffersink
    过滤器添加到
    avfilter\u parse2
    过滤器
    参数中

    因此,在一个背景图像和一个输入视频的简单情况下,
    filters
    参数的值应该如下所示:

    buffer=video\u size=1024x768:pix\u fmt=2:time\u base=1/25:pixel\u aspect=3937/3937[in\u 1];缓冲区=视频大小=1920x1080:pix\u fmt=0:time\u base=1/180000:pixel\u aspect=0/1[英寸2];[in_1][in_2]叠加=0:0[结果];[结果]缓冲接收器

    avfilter\u graph\u parse2将建立所有图形连接并初始化所有过滤器。输入缓冲区和输出缓冲区的过滤器上下文可以在末尾从图形本身检索。这些用于从过滤器图中添加/获取帧

    代码的简化版本如下所示:

    AVFilterContext **inputContexts;
    AVFilterContext *outputContext;
    AVFilterGraph *graph;
    
    int initFilters(AVFrame *bgFrame, int inputCount, AVCodecContext **codecContexts)
    {
        int i;
        int returnCode;
        char filters[1024];
        AVFilterInOut *gis = NULL;
        AVFilterInOut *gos = NULL;
    
        graph = avfilter_graph_alloc();
        if(graph == NULL)
        {
            printf("Cannot allocate filter graph.");        
            return -1;
        }
    
        //build the filters string here
        // ...
    
        returnCode = avfilter_graph_parse2(graph, filters, &gis, &gos);
        if(returnCode < 0)
        {
            cs_printAVError("Cannot parse graph.", returnCode);
            return returnCode;
        }
    
        returnCode = avfilter_graph_config(graph, NULL);
        if(returnCode < 0)
        {
            cs_printAVError("Cannot configure graph.", returnCode);
            return returnCode;
        }
    
        //get the filter contexts from the graph here
    
        return 0;
    }
    
    [0:v]pad=1008:734:144:0:black[pad];[pad][1:v]overlay=0:576[out]
    
    AVFilterContext**InputContext;
    AVFilterContext*输出上下文;
    AVFilterGraph*图;
    int initFilters(AVFrame*bgFrame,int inputCount,AVCodecContext**codeccontext)
    {
    int i;
    返回码;
    炭纤维
    
    ffmpeg -i first.mp4 -i second.mp4 -filter_complex "[0:v]pad=1008:734:144:0:black[pad];[pad][1:v]overlay=0:576[out]" -map "[out]" -map 0:a output.mp4
    
        filterGraph = avfilter_graph_alloc();
        NULLC(filterGraph);
    
        bufferSink = avfilter_get_by_name("buffersink");
        NULLC(bufferSink);
        filterInput = avfilter_inout_alloc();
        AVBufferSinkParams* buffersinkParams = av_buffersink_params_alloc();
        buffersinkParams->pixel_fmts = pixelFormats;
    
        FFMPEGHRC(avfilter_graph_create_filter(&bufferSinkContext, bufferSink, "out", NULL, buffersinkParams, filterGraph));
    
        av_free(buffersinkParams);
    
        filterInput->name = av_strdup("out");
        filterInput->filter_ctx = bufferSinkContext;
        filterInput->pad_idx = 0;
        filterInput->next = NULL;
    
        filterOutputs = new AVFilterInOut*[inputFiles.size()];
        ZeroMemory(filterOutputs, sizeof(AVFilterInOut*) * inputFiles.size());
        bufferSourceContext = new AVFilterContext*[inputFiles.size()];
        ZeroMemory(bufferSourceContext, sizeof(AVFilterContext*) * inputFiles.size());
    
        for (i = inputFiles.size() - 1; i >= 0 ; i--)
        {
            snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", 
                videoCodecContext[i]->width, videoCodecContext[i]->height, videoCodecContext[i]->pix_fmt, videoCodecContext[i]->time_base.num, videoCodecContext[i]->time_base.den, videoCodecContext[i]->sample_aspect_ratio.num, videoCodecContext[i]->sample_aspect_ratio.den);
    
            filterOutputs[i] = avfilter_inout_alloc();
            NULLC(filterOutputs[i]);
            bufferSource = avfilter_get_by_name("buffer");
            NULLC(bufferSource);
            sprintf(args2, outputTemplate, i);
            FFMPEGHRC(avfilter_graph_create_filter(&bufferSourceContext[i], bufferSource, "in", args, NULL, filterGraph));
    
            filterOutputs[i]->name = av_strdup(args2);
            filterOutputs[i]->filter_ctx = bufferSourceContext[i];
            filterOutputs[i]->pad_idx = 0;
            filterOutputs[i]->next = i < inputFiles.size() - 1 ? filterOutputs[i + 1] : NULL;
        }
    
        FFMPEGHRC(avfilter_graph_parse_ptr(filterGraph, description, &filterInput, filterOutputs, NULL));
        FFMPEGHRC(avfilter_graph_config(filterGraph, NULL));