Gstreamer在切换状态时存在内存泄漏。

huangapple go评论96阅读模式
英文:

Gstreamer memory leak when switching between states

问题

我一直在尝试制作一个通过gstreamer运行一些摄像头的程序。程序首先设置管道,然后根据用户输入在播放或暂停状态之间切换。
我注意到在运行这个程序一段时间后,程序的内存使用会逐渐增加。经过尝试了很多不同的方法,我能够使用一个非常小的示例程序复制出这个问题:

#include <gst/gst.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
    gst_init(&argc, &argv);
    GError* err = NULL;

    std::string pipeline_str = "fakesrc ! fakesink sync = false ";

    GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &err);
    gst_element_set_state(pipeline, GST_STATE_READY);
    gst_element_get_state(pipeline, NULL, NULL, 4000000000ll);

    for (;;)
    {
        gst_element_set_state(pipeline, GST_STATE_PAUSED);
        GstStateChangeReturn result = gst_element_get_state(pipeline, NULL, NULL, 4000000000ll);
        if (result != GST_STATE_CHANGE_SUCCESS){
            std::cout << "error" << std::endl;
            break;
        }      
        usleep(100);

        gst_element_set_state(pipeline, GST_STATE_PLAYING);
        result = gst_element_get_state(pipeline, NULL, NULL, 4000000000ll);
        if (result != GST_STATE_CHANGE_SUCCESS){
            std::cout << "error" << std::endl;
            break;
        }
        usleep(100);
    }

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(pipeline);

    return 0;
}

运行这个程序,我可以看到使用htop时内存使用量增加得相当快。所以在切换状态时似乎出现了问题?有人遇到过类似的问题吗?

更新

下面的被接受的答案有效。但似乎问题一直存在于未清空总线。如果我使用GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));获取总线,然后在每次循环中使用gst_bus_set_flushing(bus, TRUE);刷新总线,那么我就不再看到内存使用量增加了。

英文:

I've been trying to make a program for running some cameras through gstreamer. The program starts by setting up the pipeline and then switches between PLAYING or PAUSED states depending on the user input.
I notices after running this program for a while, that the memory use for the program would slowly increase over time. After trying a lot of different things I was able to reproduce the problem with a very small example program:

#include &lt;gst/gst.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;

int main(int argc, char* argv[])
{
    gst_init(&amp;argc, &amp;argv);
    GError* err = NULL;

    std::string pipeline_str = &quot;fakesrc ! fakesink sync = false &quot;;

    GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &amp;err);
    gst_element_set_state(pipeline, GST_STATE_READY);
    gst_element_get_state(pipeline, NULL, NULL, 4000000000ll);

    for (;;)
    {
        gst_element_set_state(pipeline, GST_STATE_PAUSED);
        GstStateChangeReturn result = gst_element_get_state(pipeline, NULL, NULL, 4000000000ll);
        if (result != GST_STATE_CHANGE_SUCCESS){
            std::cout &lt;&lt; &quot;error&quot; &lt;&lt; std::endl;
            break;
        }      
        usleep(100);

        gst_element_set_state(pipeline, GST_STATE_PLAYING);
        result = gst_element_get_state(pipeline, NULL, NULL, 4000000000ll);
        if (result != GST_STATE_CHANGE_SUCCESS){
            std::cout &lt;&lt; &quot;error&quot; &lt;&lt; std::endl;
            break;
        }
        usleep(100);
    }

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(pipeline);

    return 0;
}

Running this I can see the memory usage increase quite fast using htop. So it seems to me the problem happens when switching between states? Has anyone had similar issues?

Update

The accepted answer below works. But it seems the issue all along was not emptying the bus. If I get the bus with GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); and then flush the bus every loop with gst_bus_set_flushing(bus, TRUE);, then I don't see a rise in memory use anymore.

答案1

得分: 2

状态更改是异步的。您正在生成比管道能处理的状态更改请求更多,因此很可能您的消息队列会被这些请求堆积。

在尝试再次更改状态之前,请等待状态更改完成。检查总线以查看从管道中发出的状态更改。

编辑,示例:

#include <gst/gst.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
    gst_init(&argc, &argv);
    GError* err = NULL;

    std::string pipeline_str = "videotestsrc ! fakesink sync=false";

    GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &err);

    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));

    gst_element_set_state(pipeline, GST_STATE_READY);

    for (;;)
    {
        GstMessage* msg = gst_bus_timed_pop_filtered(bus, -1, GST_MESSAGE_STATE_CHANGED);
        if (msg->src == GST_OBJECT(pipeline))
        {
            gst_message_unref(msg);
            break;
        }
        gst_message_unref(msg);
    }

    for (;;)
    {
        gst_element_set_state(pipeline, GST_STATE_PAUSED);

        for (;;)
        {
            GstMessage* msg = gst_bus_timed_pop_filtered(bus, -1, GST_MESSAGE_STATE_CHANGED);
            if (msg->src == GST_OBJECT(pipeline))
            {
                gst_message_unref(msg);
                break;
            }
            gst_message_unref(msg);
        }

        gst_element_set_state(pipeline, GST_STATE_PLAYING);

        for (;;)
        {
            GstMessage* msg = gst_bus_timed_pop_filtered(bus, -1, GST_MESSAGE_STATE_CHANGED);
            if (msg->src == GST_OBJECT(pipeline))
            {
                gst_message_unref(msg);
                break;
            }
            gst_message_unref(msg);
        }
    }

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(bus);
    gst_object_unref(pipeline);

    return 0;
}
英文:

State changes are async. You are generating more state change requests than the pipeline can handle, so most likely your message queue gets build up by those requests.

Wait for the state changes to complete before trying to change it again. Check the bus for the state change emitted from the pipeline.

EDIT, Example:

#include &lt;gst/gst.h&gt;
#include &lt;stdio.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;

int main(int argc, char* argv[])
{
    gst_init(&amp;argc, &amp;argv);
    GError* err = NULL;

    std::string pipeline_str = &quot;videotestsrc ! fakesink sync=false&quot;;

    GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &amp;err);

    GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));

    gst_element_set_state(pipeline, GST_STATE_READY);

    for (;;)
    {
        GstMessage* msg = gst_bus_timed_pop_filtered(bus, -1, GST_MESSAGE_STATE_CHANGED);
        if (msg-&gt;src == GST_OBJECT(pipeline))
        {
            gst_message_unref(msg);
            break;
        }
        gst_message_unref(msg);
    }

    for (;;)
    {
        gst_element_set_state(pipeline, GST_STATE_PAUSED);

        for (;;)
        {
            GstMessage* msg = gst_bus_timed_pop_filtered(bus, -1, GST_MESSAGE_STATE_CHANGED);
            if (msg-&gt;src == GST_OBJECT(pipeline))
            {
                gst_message_unref(msg);
                break;
            }
            gst_message_unref(msg);
        }

        gst_element_set_state(pipeline, GST_STATE_PLAYING);

        for (;;)
        {
            GstMessage* msg = gst_bus_timed_pop_filtered(bus, -1, GST_MESSAGE_STATE_CHANGED);
            if (msg-&gt;src == GST_OBJECT(pipeline))
            {
                gst_message_unref(msg);
                break;
            }
            gst_message_unref(msg);
        }
    }

    gst_element_set_state(pipeline, GST_STATE_NULL);

    gst_object_unref(bus);
    gst_object_unref(pipeline);

    return 0;
}

huangapple
  • 本文由 发表于 2023年7月24日 18:40:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753673.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定