Утечка памяти Gstreamer при переключении между состояниями

Я пытался сделать программу для запуска некоторых камер через gstreamer. Программа начинается с настройки конвейера, а затем переключается между состояниями PLAYING или PAUSED в зависимости от ввода пользователя. Я заметил, что после запуска этой программы некоторое время использование памяти для программы будет постепенно увеличиваться с течением времени. Попробовав много разных вещей, я смог воспроизвести проблему с очень маленькой программой-примером:

#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);, то я больше не вижу увеличения использования памяти.

Реализуйте какое-нибудь условие остановки и запустите его с помощью valgrind, чтобы увидеть, действительно ли есть утечка памяти, или вы просто продолжаете накапливать ресурсы, не теряя их ссылок.

pptaszni 24.07.2023 13:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Изменения состояния являются асинхронными. Вы генерируете больше запросов на изменение состояния, чем конвейер может обработать, поэтому, скорее всего, ваша очередь сообщений будет заполнена этими запросами.

Дождитесь завершения изменения состояния, прежде чем пытаться изменить его снова. Проверьте шину на предмет изменения состояния, передаваемого из конвейера.

РЕДАКТИРОВАТЬ, пример:

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

Я добавил gst_element_get_state() и проверку успеха в блок кода в описании. Насколько я понимаю, gst_element_get_state() блокируется до тех пор, пока не получит успех или неудачу. С этим добавлением я все еще вижу такое же быстрое увеличение использования памяти.

Rasmus 25.07.2023 10:17
gst_element_get_state() вернет `GST_STATE_CHANGE_ASYNC` в случае изменения асинхронного состояния. Я пробовал с простым циклом сообщений из шины - при колоритности это устранило увеличение памяти.
Florian Zwoch 25.07.2023 12:42

Не могли бы вы поделиться своим кодом цикла сообщений? Это очень помогло бы с пониманием. Когда я запускаю код в описании gst_element_get_state() каждый раз возвращает GST_STATE_CHANGE_SUCCESS

Rasmus 25.07.2023 12:57

Да, я ошибся, возвращаемое значение другое, но, к сожалению, это не так просто. Я обновил пост с примером. Однако нормальный способ - иметь правильный цикл выполнения и функцию обратного вызова шины. Также следует проанализировать это сообщение, о каком изменении состояния было сообщено. Хотя я надеюсь, этого должно хватить для примера.

Florian Zwoch 25.07.2023 13:33

На самом деле, не уверен, что ваш подход тоже работает. Возможно, главная причина в том, что у вас нет кода, выполняющего очередь сообщений шины, позволяющую ей бесконечно расти.

Florian Zwoch 25.07.2023 13:51

Я думаю ты прав. Я попробовал ваш код, и он, конечно, работает хорошо. Затем я попробовал свой старый код, но добавил gst_bus_set_flushing(bus, true) между изменениями состояния, что также устранило увеличение памяти. Огромное спасибо за помощь.

Rasmus 25.07.2023 14:02

Другие вопросы по теме