Reliable way to pause/play a pipeline with webcam streaming and tee?

So I am trying to create an application based on GStreamer + GTK to scan QR code. My pipeline is like this:

                                         +--[ queue ] -- [ glsinkbin sink=gtkglsink]
                                       /
V4l2Src ------ [ tee ] +
                                       \
                                         +--[ queue ] -- [ videoconvert ] -- [ video/x-raw,format=GRAY8 ] -- [ appsink ]

The UI is like this:

So, it has Play/Pause button, so that, after one detection is made, I can try another one.

The problem is that:

  • In daytime, with enough light, after I click Pause, I click Play, the video still freezes.
  • In night time, when room lights are off, when I click Pause, the video still plays.

I guess there are somethings with the multi-thread nature of GStreamer, but cannot figure out where and how to fix.

Could someone help?

It’s not clear to me what your goal here is when pausing. Do you want to pause the whole pipeline or only the branch with the appsink? And why?

The problem in your application however is probably the following: You’re setting the play_sink to READY state as the first step, and afterwards the source to PAUSED state. What will happen here in most cases is that the play_sink will receive another frame in between and then the sink will return an error (FLUSHING), which will silently shut down the whole pipeline. The opposite problem happens when unpausing: you first start the source and then the play_sink, which would likely let a frame pass through to the play_sink before it can actually accept a frame, leading to the same situation as before.

Depending on what the goal here is, changing only the source state or the whole pipeline state is more likely what you want to do. Or maybe you simply want to ignore new frames in the appsink callback and keep everything running?

1 Like

I just want to pause video, but trying many ways, because I haven’t found a way which is working yet.

First, I tried to make the whole pipeline PAUSED, but the line of code

self.gst_pipeline.set_state(Gst.State.PAUSED)

just block and the next code couldn’t be run.

That is why now I’m trying to pause just some elements in the pipeline (that is why the code looks so messy).

Thanks, I modified my code to change state of only the source, and it works!

That’s curious. Unless you call that from the on_new_webcam_sample() callback this shouldn’t really block for a considerable amount of time. Can you get a backtrace of all threads when it’s stuck there?

Oh, I called it from inside on_new_webcam_sample() callback. So that made the code block.
Could you please explain why calling from that callback made the code block?

That callback is called from the “streaming thread”, which is the thread where data processing happens. Changing the pipeline state from that thread generally causes deadlocks. In your case setting the state would wait for media processing to finish, i.e. for the streaming thread to become idle… but as you are calling it from inside the streaming thread it’s basically waiting for itself.

The solution would be to do this from the application thread or from some thread pool. You could use pipeline.call_async() for example for this.

1 Like