Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prebuffer an incoming network stream with gstreamer?

I'm using gstreamer to stream audio over the network. My goal is seemingly simple: Prebuffer the incoming stream up to a certain time/byte threshold and then start playing it. I might be overlooking a really simple feature of gstreamer, but so far, I haven't been able to find a way to do that.

My (simplified) pipeline looks like this: udpsrc -> alsasink. So far all my attempts at achieving my goal have been using a queue element in between:

  1. Add a queue element in between.
  2. Use the min-threshold-time property. This actually works but the problem is, that it makes all the incoming data spend the specified minimum amount of time in the queue, rather than just the beginning, which is not what I want.
  3. To work around the previous problem, I tried to have the queue notify my code when data enters the audio sink for the first time, thinking that this is the time to unset the min-time property that I set earlier, and thus, achieving the "prebuffering" behavior.

Here's is a rough equivalent of the code I tried:

def remove_thresh(pad, info, queue):
    pad.remove_data_probe(probe_id)
    queue.set_property("min-threshold-time", 0)

queue.set_property("min-threshold-time", delay)
queue.set_property("max-size-time", delay * 2)
probe_id = audiosink.get_pad("sink").add_data_probe(remove_thresh, queue)

This doesn't work for two reasons:

  1. My callback gets called way earlier than the delay variable I provided.
  2. After it gets called, all of the data that was stored in the queue is lost. the playback starts as if the queue weren't there at all.

I think I have a fundamental misunderstanding of how this thing works. Does anyone know what I'm doing wrong, or alternatively, can provide a (possibly) better way to do this? I'm using python here, but any solution in any language is welcome.

Thanks.

like image 720
Nir Avatar asked Apr 21 '13 19:04

Nir


1 Answers

Buffering has already been implemented in GStreamer. Some elements, like the queue, are capable of building this buffer and post bus messages regarding the buffer level (the state of the queue).

An application wanting to have more network resilience, then, should listen to these messages and pause playback if the buffer level is not high enough (usually, whenever it is below 100%).

So, all you have to do is set the pipeline to the PAUSED state while the queue is buffering. In your case, you only want to buffer once, so use any logic for this (maybe set flag variables to pause the pipeline only the first time).

  1. Set the "max-size-bytes" property of the queue to the value you want.
  2. Either listen to the "overrun" signal to notify you when the buffer becomes full or use gst_message_parse_buffering () to find the buffering level.
  3. Once your buffer is full, set the pipeline to PLAYING state and then ignore all further buffering messages.

Finally, for a complete streaming example, you can refer to this tutorial: https://gstreamer.freedesktop.org/documentation/tutorials/basic/streaming.html The code is in C, but the walkthroughs should help you with you want.

like image 63
rubndsouza Avatar answered Oct 20 '22 08:10

rubndsouza