Я пытался сделать программу для запуска некоторых камер через 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);, то я больше не вижу увеличения использования памяти.





Изменения состояния являются асинхронными. Вы генерируете больше запросов на изменение состояния, чем конвейер может обработать, поэтому, скорее всего, ваша очередь сообщений будет заполнена этими запросами.
Дождитесь завершения изменения состояния, прежде чем пытаться изменить его снова. Проверьте шину на предмет изменения состояния, передаваемого из конвейера.
РЕДАКТИРОВАТЬ, пример:
#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() блокируется до тех пор, пока не получит успех или неудачу. С этим добавлением я все еще вижу такое же быстрое увеличение использования памяти.
gst_element_get_state() вернет `GST_STATE_CHANGE_ASYNC` в случае изменения асинхронного состояния. Я пробовал с простым циклом сообщений из шины - при колоритности это устранило увеличение памяти.
Не могли бы вы поделиться своим кодом цикла сообщений? Это очень помогло бы с пониманием. Когда я запускаю код в описании gst_element_get_state() каждый раз возвращает GST_STATE_CHANGE_SUCCESS
Да, я ошибся, возвращаемое значение другое, но, к сожалению, это не так просто. Я обновил пост с примером. Однако нормальный способ - иметь правильный цикл выполнения и функцию обратного вызова шины. Также следует проанализировать это сообщение, о каком изменении состояния было сообщено. Хотя я надеюсь, этого должно хватить для примера.
На самом деле, не уверен, что ваш подход тоже работает. Возможно, главная причина в том, что у вас нет кода, выполняющего очередь сообщений шины, позволяющую ей бесконечно расти.
Я думаю ты прав. Я попробовал ваш код, и он, конечно, работает хорошо. Затем я попробовал свой старый код, но добавил gst_bus_set_flushing(bus, true) между изменениями состояния, что также устранило увеличение памяти. Огромное спасибо за помощь.
Реализуйте какое-нибудь условие остановки и запустите его с помощью valgrind, чтобы увидеть, действительно ли есть утечка памяти, или вы просто продолжаете накапливать ресурсы, не теряя их ссылок.