Search code examples
cimage-processingffmpeglibav

Overlay filter in LibAV/FFMpeg returns strange (tripled) frame in C


I tried to make a program, which merges two frames. I use LibAV (libav-win32-20140428) under Windows 7 64 and Visual Studio 2013. But the result is quite odd.

http://oi58.tinypic.com/rcobnm.jpg

The filter which was used is Overlay. When I change the graph, to the one, that uses only one stream and add FADE effect, everything works like a charm. But OVERLAY and eg. DRAWBOX give me strange distortion (three frames on one and black and white effect). Here is the code:

static int init_filter_graph(AVFilterGraph **pGraph, AVFilterContext **pSrc1, AVFilterContext **pSink)
{
    AVFilterGraph* tFilterGraph;
    AVFilterContext* tBufferContext1;
    AVFilter* tBuffer1;
    AVFilterContext* tColorContext;
    AVFilter* tColor;
    AVFilterContext* tOverlayContext;
    AVFilter* tOverlay;
    AVFilterContext* tBufferSinkContext;
    AVFilter* tBufferSink;

    int tError;

    /* Create a new filtergraph, which will contain all the filters. */
    tFilterGraph = avfilter_graph_alloc();

    if (!tFilterGraph) {
        return -1;
    }

    { // BUFFER FILTER 1
        tBuffer1 = avfilter_get_by_name("buffer");
        if (!tBuffer1) {
            return -1;
        }
        tBufferContext1 = avfilter_graph_alloc_filter(tFilterGraph, tBuffer1, "src1");
        if (!tBufferContext1) {
            return -1;
        }

        av_dict_set(&tOptionsDict, "width", "320", 0);
        av_dict_set(&tOptionsDict, "height", "240", 0);
        av_dict_set(&tOptionsDict, "pix_fmt", "bgr24", 0);
        av_dict_set(&tOptionsDict, "time_base", "1/25", 0);
        av_dict_set(&tOptionsDict, "sar", "1", 0);
        tError = avfilter_init_dict(tBufferContext1, &tOptionsDict);
        av_dict_free(&tOptionsDict);
        if (tError < 0) {
            return tError;
        }
    }

    { // COLOR FILTER
        tColor = avfilter_get_by_name("color");
        if (!tColor) {
            return -1;
        }
        tColorContext = avfilter_graph_alloc_filter(tFilterGraph, tColor, "color");
        if (!tColorContext) {
            return -1;
        }

        av_dict_set(&tOptionsDict, "color", "white", 0);
        av_dict_set(&tOptionsDict, "size", "20x120", 0);
        av_dict_set(&tOptionsDict, "framerate", "1/25", 0);
        tError = avfilter_init_dict(tColorContext, &tOptionsDict);
        av_dict_free(&tOptionsDict);
        if (tError < 0) {
            return tError;
        }
    }

    { // OVERLAY FILTER
        tOverlay = avfilter_get_by_name("overlay");
        if (!tOverlay) {
            return -1;
        }
        tOverlayContext = avfilter_graph_alloc_filter(tFilterGraph, tOverlay, "overlay");
        if (!tOverlayContext) {
            return -1;
        }

        av_dict_set(&tOptionsDict, "x", "0", 0);
        av_dict_set(&tOptionsDict, "y", "0", 0);
        av_dict_set(&tOptionsDict, "main_w", "120", 0);
        av_dict_set(&tOptionsDict, "main_h", "140", 0);
        av_dict_set(&tOptionsDict, "overlay_w", "320", 0);
        av_dict_set(&tOptionsDict, "overlay_h", "240", 0);
        tError = avfilter_init_dict(tOverlayContext, &tOptionsDict);
        av_dict_free(&tOptionsDict);
        if (tError < 0) {
            return tError;
        }
    }

    { // BUFFERSINK FILTER
        tBufferSink = avfilter_get_by_name("buffersink");
        if (!tBufferSink) {
            return -1;
        }

        tBufferSinkContext = avfilter_graph_alloc_filter(tFilterGraph, tBufferSink, "sink");
        if (!tBufferSinkContext) {
            return -1;
        }

        tError = avfilter_init_str(tBufferSinkContext, NULL);
        if (tError < 0) {
            return tError;
        }
    }

    // Linking graph
    tError = avfilter_link(tBufferContext1, 0, tOverlayContext, 0);
    if (tError >= 0) {
        tError = avfilter_link(tColorContext, 0, tOverlayContext, 1);
    }
    if (tError >= 0) {
        tError = avfilter_link(tOverlayContext, 0, tBufferSinkContext, 0);
    }
    if (tError < 0) {
        return tError;
    }

    tError = avfilter_graph_config(tFilterGraph, NULL);
    if (tError < 0) {
        return tError;
    }

    *pGraph = tFilterGraph;
    *pSrc1 = tBufferContext1;
    *pSink = tBufferSinkContext;

    return 0;
}

What do you think is the reason?


Solution

  • I got a hint from Luca Barbato at LibAV's mailing list:

    Can you try to reproduce that with avconv? From the image looks like you are getting a pixel format you are not really expecting.

    lu

    And I discovered, that I need to use Format Filter, to keep the pixels' format the same. So I added:

    { // FORMAT FILTER
        tFormat = avfilter_get_by_name("format");
        if (!tFormat) {
            // Could not find the tFormat filter.
            return -1;
        }
    
        tFormatContext = avfilter_graph_alloc_filter(tFilterGraph, tFormat, "format");
        if (!tFormatContext) {
            // Could not allocate the tFormat instance.
            return -1;
        }
    
        av_dict_set(&tOptionsDict, "pix_fmts", "bgr24", 0);
        tError = avfilter_init_dict(tFormatContext, &tOptionsDict);
        av_dict_free(&tOptionsDict);
        if (tError < 0) {
            // Could not initialize the tFormat filter.
            return tError;
        }
    }
    

    in init_filter_graph function.

    And now my filter graph looks like this:

    tError = avfilter_link(tBufferContext1, 0, tOverlayContext, 0);
    if (tError >= 0)
    {
        tError = avfilter_link(tColorContext, 0, tOverlayContext, 1);
    }
    if (tError >= 0)
    {
        tError = avfilter_link(tOverlayContext, 0, tFormatContext, 0);
    }
    if (tError >= 0)
    {
        tError = avfilter_link(tFormatContext, 0, tBufferSinkContext, 0);
    }
    if (tError < 0) { // Error connecting filters.
        return tError;
    }
    

    The distortion is gone and color is back!

    enter image description here