gst_element_set_state blocks when setting GST_STATE_NULL when using vaapisink and QWidget

Nirbheek Chauhan nirbheek.chauhan at gmail.com
Tue Nov 9 21:58:15 UTC 2021


Hi Viljar,

You should probably dig into the `gdb` backtrace output and see if
there's a deadlock, and if so where.

Install debug symbols, run your test program. When it deadlocks,
attach gdb to it using `gdb -p <pid>` and check the output of "bt
full". Look for any mutexes that are locked or are waiting for a lock.
If a mutex is owned by a thread and another thread is waiting forever
trying to lock it, that is a deadlock.

Analyzing the owners of various locked mutexes and threads that are
trying to lock the same mutexes will tell you what's happening.

Cheers,
Nirbheek

On Tue, Nov 9, 2021 at 5:00 PM Viljar Hera via gstreamer-devel
<gstreamer-devel at lists.freedesktop.org> wrote:
>
> Oops,
>
> switch (gst_element_set_state(pipeline, GST_STATE_PLAYING)) // <- blocks indefinitely
>
> that comment landed on wrong place, should be:
>
>
> switch (gst_element_set_state(pipelines[i], GST_STATE_NULL)) // <- blocks indefinitely
>
>
> Kontakt meistrimees--- via gstreamer-devel (<gstreamer-devel at lists.freedesktop.org>) kirjutas kuupäeval T, 9. november 2021 kell 11:55:
>>
>>
>> I prepared a simple test program that I could reproduce the issue. I have tested with latest stable version of GStreamer 1.18.5, using radeonsi driver, but it will probably happen with Intel drivers as well.
>> Increasing the number of  pipeline-s will increase the chance of getting one of them stuck on teardown.
>>
>> I'm considering opening a bugreport, but I want a second opinion before I do. Maybe I'm missing something here.
>>
>> #include <QApplication>
>>
>> #include <QDebug>
>>
>> #include <QWidget>
>>
>> #include <QGridLayout>
>>
>>
>> #include <gst/gst.h>
>>
>> #include <gst/video/videooverlay.h>
>>
>>
>> int main(int argc, char *argv[])
>>
>> {
>>
>>   gst_init(0, 0);
>>
>>
>>   QApplication app(argc, argv);
>>
>>   app.connect(&app, &QApplication::lastWindowClosed, &app, &QApplication::quit);
>>
>>
>>   // We will arrenge videoWidgets into the colums and rows
>>
>>   QWidget mainWidget;
>>
>>   QGridLayout *layout = new QGridLayout;
>>
>>   layout->setHorizontalSpacing(0);
>>
>>   mainWidget.setLayout(layout);
>>
>>
>>   int streamCount = 9;
>>
>>   int rowCount = 3;
>>
>>   int colCount = streamCount % rowCount == 0 ? streamCount / rowCount : streamCount / rowCount + 1;
>>
>>
>>   const char *pipelineStr = "videotestsrc ! vaapisink name=\"thesink\"";
>>
>>   QVector<GstElement *> pipelines;
>>
>>
>>   for (int i = 0; i < streamCount; ++i)
>>
>>   {
>>
>>     GError *error = NULL;
>>
>>     GstElement *pipeline = gst_parse_launch(pipelineStr, &error);
>>
>>
>>     if (error) {
>>
>>       qInfo() << "Error: " << error->message;
>>
>>       g_clear_error(&error);
>>
>>     }
>>
>>
>>     if (!pipeline) {
>>
>>       qInfo() << "Unable to create pipeline";
>>
>>       continue;
>>
>>     }
>>
>>
>>     GstElement *sink = gst_bin_get_by_name(GST_BIN(pipeline), "thesink");
>>
>>
>>     if (!sink)
>>
>>     {
>>
>>       qInfo() << "Failed to get vaapisink element";
>>
>>       continue;
>>
>>     }
>>
>>
>>     QWidget *videoWidget = new QWidget();
>>
>>     layout->addWidget(videoWidget, i / colCount, i % colCount);
>>
>>
>>     if (sink)
>>
>>     {
>>
>>       gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink), videoWidget->winId());
>>
>>       g_object_unref(sink);
>>
>>     }
>>
>>
>>     switch (gst_element_set_state(pipeline, GST_STATE_PLAYING)) // <- blocks indefinitely
>>
>>     {
>>
>>     case GST_STATE_CHANGE_FAILURE:
>>
>>       qInfo() << "Failed to start pipeline" << i;
>>
>>       break;
>>
>>     case GST_STATE_CHANGE_SUCCESS:
>>
>>       qInfo() << "Pipeline" << i << "started";
>>
>>       break;
>>
>>     case GST_STATE_CHANGE_ASYNC:
>>
>>       qInfo() << "Pipeline" << i << "is starting";
>>
>>       break;
>>
>>     case GST_STATE_CHANGE_NO_PREROLL:
>>
>>       qInfo() << "Pipeline" << i << "started, but no data yet";
>>
>>       break;
>>
>>     default:
>>
>>        qInfo() << "Unknown value";
>>
>>       break;
>>
>>     }
>>
>>
>>     pipelines.append(pipeline);
>>
>>   }
>>
>>
>>   mainWidget.resize(1280, 720);
>>
>>   mainWidget.showMaximized();
>>
>>
>>   int ret = app.exec();
>>
>>
>>   qInfo() << "Terminating";
>>
>>   mainWidget.hide();
>>
>>
>>   for (int i = 0; i < pipelines.size(); ++i) {
>>
>>     qInfo() << "Stopping pipeline" << i;
>>
>>     switch (gst_element_set_state(pipelines[i], GST_STATE_NULL))
>>
>>     {
>>
>>     case GST_STATE_CHANGE_FAILURE:
>>
>>       qInfo() << "Failed to stop pipeline" << i;
>>
>>       break;
>>
>>     case GST_STATE_CHANGE_SUCCESS:
>>
>>       qInfo() << "Pipeline" << i << "stopped";
>>
>>       break;
>>
>>     case GST_STATE_CHANGE_ASYNC:
>>
>>       qInfo() << "Pipeline" << i << "is stopping";
>>
>>       break;
>>
>>     case GST_STATE_CHANGE_NO_PREROLL:
>>
>>       qInfo() << "Preroll" << i;
>>
>>       break;
>>
>>     default:
>>
>>        qInfo() << "Unknown value";
>>
>>       break;
>>
>>     }
>>
>>
>>     g_object_unref(pipelines[i]);
>>
>>   }
>>
>>
>>   return ret;
>>
>> }
>>
>>
>> If someone could confirm the issue I would open a bug report.
>>
>>


More information about the gstreamer-devel mailing list