2
votes

I'd like to loop a file using GStreamer.

    Gst.Element playbin = Gst.ElementFactory.make ("uridecodebin", null);

I do this by adding a probe to the playbin's src pad, and listen for EOS messages. Whenever one comes, I repeat the stream by seeking back to the beginning.

    Gst.Pad srcpad = playbin.get_request_pad("src_%u");

    srcpad.add_probe(Gst.PadProbeType.EVENT_DOWNSTREAM, (pad, info) => {
        Gst.Event? event = info.get_event();

        if (event != null)
        {
            if (event.type == Gst.EventType.EOS
            ||  event.type == Gst.EventType.SEGMENT_DONE)
            {
                var element = pad.get_parent_element();
                element.seek(1.0, Gst.Format.TIME, Gst.SeekFlags.SEGMENT, Gst.SeekType.SET, 0, Gst.SeekType.NONE, 0);
                return Gst.PadProbeReturn.HANDLED;
            }
        }

        return Gst.PadProbeReturn.OK;
    });

However, when I catch the EOS and seek back to the beginning, I get this error:

wavparse gstwavparse.c:2195:gst_wavparse_stream_data:<wavparse0> Error pushing on srcpad wavparse0:src, reason eos, is linked? = 1

How do I get my playbin element back out of the EOS state so that it can play from the place I seeked to?

I'd like to avoid listening to the pipeline bus because it's quite a complex application and the playbin is quite a few Bins deep.

1

1 Answers

0
votes

Admittedly, my testing was performed with python, rather than C but I see no reason why the logic should be different.

Set the player's pipeline state to Gst.State.NULL, wait for a tenth of a second or so for the pipeline to reach that state, then simply play it again, as if starting from scratch after loading it. Normally, by simply setting the pipeline state to Gst.State.PLAYING.

Note:
As far as I'm aware, only local files can be pre-rolled i.e. do the seek and then play, thus if the file is not local you must play and then seek. Always wait for the pipeline to reach the desired state, before the next operation.
To pre-roll a local file, set the pipeline state to paused, then perform the seek, finally set it to playing, always waiting for the previous operation to finish before moving on to the next.