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