input-selector adding a 3rd source to the switch.py example

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

input-selector adding a 3rd source to the switch.py example

Brian Quandt
I'm still a bit new to the concepts of gstreamer from a coding perspective, but am trying to learn from within some python testing.

My goal is to take the demo script "switch.py" and augment it to add a 3rd item to switch to after the pipeline has started (ie via interaction with the UI/user).  Think of having a user be able to enter a new streaming source to pull from to add to their list of items they can switch back and forth.

Things work great when I'm using videotestsrc as my sources (ie if I change my attached code to use videotestsrc instead of uridecodebin's).   For clarity, if I make my dynmaically added uridecodebin a videotestsrc, this works without a problem.

But if I set my user added src to be uridecodebin (as in the attached code) which is added to the pipeline after the startup of the pipeline, playback get's wonky, ie stuffer playback in 3rd uridecode, which also results in stuffer playback on my original items.

I think this has something to do with clocking, which I'm still trying to comprehend how or what gstreamer wants to be done.

Attached below is the modified "switch.py" code

-- Brian



#!/usr/bin/env python
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4

import pygtk
pygtk.require('2.0')

import sys

import gobject
gobject.threads_init()

import pygst
pygst.require('0.10')
import gst
import gst.interfaces
import gtk
gtk.gdk.threads_init()

class SwitchTest:
    def __init__(self, videowidget):
        self.playing = False
        pipestr = ('uridecodebin uri=http://localhost:8000/p1.ogg ! queue ! s.sink0'
                   ' videotestsrc name=blah ! queue ! s.sink1'
                   ' input-selector sync-streams=true name=s ! autovideosink ' )
#theoraenc quality=1 ! oggmux ! shout2send ip=localhost port=8000 password=hackme mount=mytest.ogg ')
        self.pipeline = gst.parse_launch(pipestr)
        self.videowidget = videowidget

        bus = self.pipeline.get_bus()
        bus.enable_sync_message_emission()
        bus.add_signal_watch()
        bus.connect('sync-message::element', self.on_sync_message)
        bus.connect('message', self.on_message)

    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        if message.structure.get_name() == 'prepare-xwindow-id':
            # Sync with the X server before giving the X-id to the sink
            gtk.gdk.threads_enter()
            gtk.gdk.display_get_default().sync()
            self.videowidget.set_sink(message.src)
            message.src.set_property('force-aspect-ratio', True)
            gtk.gdk.threads_leave()
           
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            print "Error: %s" % err, debug
            if self.on_eos:
                self.on_eos()
            self.playing = False
        elif t == gst.MESSAGE_EOS:
            if self.on_eos:
                self.on_eos()
            self.playing = False

    def play(self):
        self.playing = True
        gst.info("playing player")
        self.pipeline.set_state(gst.STATE_PLAYING)
       
    def stop(self):
        self.pipeline.set_state(gst.STATE_NULL)
        gst.info("stopped player")
        self.playing = False

    def get_state(self, timeout=1):
        return self.pipeline.get_state(timeout=timeout)

    def is_playing(self):
        return self.playing
   
    def switch(self, padname):
        switch = self.pipeline.get_by_name('s')
        stop_time = switch.emit('block')
        newpad = switch.get_static_pad(padname)
        start_time = newpad.get_property('running-time')
   
        print stop_time
        print start_time
       
        gst.warning('stop time = %d' % (stop_time,))
        gst.warning('stop time = %s' % (gst.TIME_ARGS(stop_time),))

        gst.warning('start time = %d' % (start_time,))
        gst.warning('start time = %s' % (gst.TIME_ARGS(start_time),))

        gst.warning('switching from %r to %r'
                    % (switch.get_property('active-pad'), padname))
        switch.emit('switch', newpad, stop_time, start_time)

class VideoWidget(gtk.DrawingArea):
    def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.imagesink = None
        self.unset_flags(gtk.DOUBLE_BUFFERED)

    def do_expose_event(self, event):
        if self.imagesink:
            self.imagesink.expose()
            return False
        else:
            return True

    def set_sink(self, sink):
        assert self.window.xid
        self.imagesink = sink
        self.imagesink.set_xwindow_id(self.window.xid)

class SwitchWindow(gtk.Window):
    UPDATE_INTERVAL = 500
    def __init__(self):
        gtk.Window.__init__(self)
        self.set_default_size(410, 325)

        self.create_ui()
        self.player = SwitchTest(self.videowidget)
        self.populate_combobox()

        self.update_id = -1
        self.changed_id = -1
        self.seek_timeout_id = -1

        self.p_position = gst.CLOCK_TIME_NONE
        self.p_duration = gst.CLOCK_TIME_NONE

        def on_delete_event():
            self.player.stop()
            gtk.main_quit()
        self.connect('delete-event', lambda *x: on_delete_event())

    def load_file(self, location):
        self.player.set_location(location)
                                 
    def play(self):
        self.player.play()
       
    def populate_combobox(self):
        switch = self.player.pipeline.get_by_name('s')
        for i, pad in enumerate([p for p in switch.pads()
                                 if p.get_direction() == gst.PAD_SINK]):
            self.combobox.append_text(pad.get_name())
            if switch.get_property('active-pad') == pad.get_name():
                self.combobox.set_active(i)
        if self.combobox.get_active() == -1:
            self.combobox.set_active(0)

    def combobox_changed(self):
        model = self.combobox.get_model()
        row = model[self.combobox.get_active()]
        padname, = row
        self.player.switch(padname)

    def onPad(self,element, pad,target):
        #sinkpad = target.get_compatible_pad(pad, pad.get_caps())
        #print sinkpad
        #pad.link(sinkpad)
        caps = pad.get_caps()
        name = caps[0].get_name()
        #for now only like the video pad from uridecode
        if name == 'video/x-raw-yuv':
            tpad = target.get_pad('sink')
            if not tpad.is_linked():
                pad.link(tpad)
                print 'on_pad_added:', name

        return True

    def enter_callback(self, widget, entry):


        myuri = gst.element_factory_make("uridecodebin")
        myuri.set_property("uri","http://localhost:8000/p2.ogg")
        myuri.set_property("name","xyz")

        myq = gst.element_factory_make("queue")
        #myq.set_property("leaky","upstream")

        self.player.pipeline.add(myuri,myq)

        #link stuff up
        myuri.connect("pad-added",self.onPad,myq)

        # get the element in the bin who's name is 's', ie input-selector
        # then get the src pad on the queue element and use the below code
        # to connect stuff
        inputselectorelement = self.player.pipeline.get_by_name('s')
        myq.link(inputselectorelement)
        self.populate_combobox()

        myuri.set_state(gst.STATE_READY)
        myq.set_state(gst.STATE_READY)
       
        #For whatever reason when I hook this thing in, it plays weird, and throws
        # off tons of QOS dropped frames
        # guessing something with the element system clocks.   for some reason
        # when I add things to an active pipeline, they get their base_time set
        # to what the others are, and not when these new ones really started
        # so this is an attempt to address that, assuming this is the real problem
        print "clock testing"
        myclk = myuri.get_clock()
        print myclk.get_time()
        print myuri.get_base_time()
        print myclk.get_time() - myuri.get_base_time()
        xxx= myclk.get_time()
        myuri.set_base_time(xxx)
        myq.set_base_time(xxx)

        myuri.set_state(gst.STATE_PLAYING)
        myq.set_state(gst.STATE_PLAYING)

        print "clock checks"
        print 'videotestsrc base time'
        tel = self.player.pipeline.get_by_name('blah')
        print tel.get_base_time()
        print "myuri"
        print myuri.get_base_time()
        print "myq"
        print myq.get_base_time()

        #myqpadsrc = myq.get_pad('src')
        #ipadsink = inputselectorelement.get_pad('sink')
        #inputselectorelement.link_pads(myqpadsrc,inputselectorelement,ipadsink)


        entry_text = entry.get_text()
        print "Entry contents: %s\n" % entry_text

    def create_ui(self):
        vbox = gtk.VBox()
        self.add(vbox)

        self.videowidget = VideoWidget()
        vbox.pack_start(self.videowidget)
       
        hbox = gtk.HBox()
        vbox.pack_start(hbox, fill=False, expand=False)
       
        self.combobox = combobox = gtk.combo_box_new_text()
        combobox.show()
        hbox.pack_start(combobox)

        self.combobox.connect('changed',
                              lambda *x: self.combobox_changed())

        self.videowidget.connect_after('realize',
                                       lambda *x: self.play())
        entry = gtk.Entry()
        entry.set_max_length(50)
        entry.connect("activate", self.enter_callback, entry)
        entry.set_text("hello")
        entry.insert_text(" world", len(entry.get_text()))
        entry.select_region(0, len(entry.get_text()))
        hbox.pack_start(entry)
        entry.show()

def main(args):
    def usage():
        sys.stderr.write("usage: %s\n" % args[0])
        return 1

    # Need to register our derived widget types for implicit event
    # handlers to get called.
    gobject.type_register(SwitchWindow)
    gobject.type_register(VideoWidget)

    if len(args) != 1:
        return usage()

    w = SwitchWindow()
    w.show_all()
    gtk.main()
    return 0

if __name__ == '__main__':
    sys.exit(main(sys.argv))





_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: input-selector adding a 3rd source to the switch.py example

Stefan Sauer
On 08/05/2012 06:29 AM, Brian Quandt wrote:
I'm still a bit new to the concepts of gstreamer from a coding perspective, but am trying to learn from within some python testing.

My goal is to take the demo script "switch.py" and augment it to add a 3rd item to switch to after the pipeline has started (ie via interaction with the UI/user).  Think of having a user be able to enter a new streaming source to pull from to add to their list of items they can switch back and forth.

Things work great when I'm using videotestsrc as my sources (ie if I change my attached code to use videotestsrc instead of uridecodebin's).   For clarity, if I make my dynmaically added uridecodebin a videotestsrc, this works without a problem.

But if I set my user added src to be uridecodebin (as in the attached code) which is added to the pipeline after the startup of the pipeline, playback get's wonky, ie stuffer playback in 3rd uridecode, which also results in stuffer playback on my original items.

I think this has something to do with clocking, which I'm still trying to comprehend how or what gstreamer wants to be done.
The problem is that the newly added branch does not have any context. There are various workarounds that you can find in e.g. gst-plugins-base/tests/examples/dynamic. But as you can see, you can't really atomically set the base-time. It might work a little better by sticking your elements into a bin, then you only need to do the { paused, set_base_time, play } on the bin.

Stefan



Attached below is the modified "switch.py" code

-- Brian



#!/usr/bin/env python
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4

import pygtk
pygtk.require('2.0')

import sys

import gobject
gobject.threads_init()

import pygst
pygst.require('0.10')
import gst
import gst.interfaces
import gtk
gtk.gdk.threads_init()

class SwitchTest:
    def __init__(self, videowidget):
        self.playing = False
        pipestr = ('uridecodebin uri=http://localhost:8000/p1.ogg ! queue ! s.sink0'
                   ' videotestsrc name=blah ! queue ! s.sink1'
                   ' input-selector sync-streams=true name=s ! autovideosink ' )
#theoraenc quality=1 ! oggmux ! shout2send ip=localhost port=8000 password=hackme mount=mytest.ogg ')
        self.pipeline = gst.parse_launch(pipestr)
        self.videowidget = videowidget

        bus = self.pipeline.get_bus()
        bus.enable_sync_message_emission()
        bus.add_signal_watch()
        bus.connect('sync-message::element', self.on_sync_message)
        bus.connect('message', self.on_message)

    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        if message.structure.get_name() == 'prepare-xwindow-id':
            # Sync with the X server before giving the X-id to the sink
            gtk.gdk.threads_enter()
            gtk.gdk.display_get_default().sync()
            self.videowidget.set_sink(message.src)
            message.src.set_property('force-aspect-ratio', True)
            gtk.gdk.threads_leave()
           
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_ERROR:
            err, debug = message.parse_error()
            print "Error: %s" % err, debug
            if self.on_eos:
                self.on_eos()
            self.playing = False
        elif t == gst.MESSAGE_EOS:
            if self.on_eos:
                self.on_eos()
            self.playing = False

    def play(self):
        self.playing = True
        gst.info("playing player")
        self.pipeline.set_state(gst.STATE_PLAYING)
       
    def stop(self):
        self.pipeline.set_state(gst.STATE_NULL)
        gst.info("stopped player")
        self.playing = False

    def get_state(self, timeout=1):
        return self.pipeline.get_state(timeout=timeout)

    def is_playing(self):
        return self.playing
   
    def switch(self, padname):
        switch = self.pipeline.get_by_name('s')
        stop_time = switch.emit('block')
        newpad = switch.get_static_pad(padname)
        start_time = newpad.get_property('running-time')
   
        print stop_time
        print start_time
       
        gst.warning('stop time = %d' % (stop_time,))
        gst.warning('stop time = %s' % (gst.TIME_ARGS(stop_time),))

        gst.warning('start time = %d' % (start_time,))
        gst.warning('start time = %s' % (gst.TIME_ARGS(start_time),))

        gst.warning('switching from %r to %r'
                    % (switch.get_property('active-pad'), padname))
        switch.emit('switch', newpad, stop_time, start_time)

class VideoWidget(gtk.DrawingArea):
    def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.imagesink = None
        self.unset_flags(gtk.DOUBLE_BUFFERED)

    def do_expose_event(self, event):
        if self.imagesink:
            self.imagesink.expose()
            return False
        else:
            return True

    def set_sink(self, sink):
        assert self.window.xid
        self.imagesink = sink
        self.imagesink.set_xwindow_id(self.window.xid)

class SwitchWindow(gtk.Window):
    UPDATE_INTERVAL = 500
    def __init__(self):
        gtk.Window.__init__(self)
        self.set_default_size(410, 325)

        self.create_ui()
        self.player = SwitchTest(self.videowidget)
        self.populate_combobox()

        self.update_id = -1
        self.changed_id = -1
        self.seek_timeout_id = -1

        self.p_position = gst.CLOCK_TIME_NONE
        self.p_duration = gst.CLOCK_TIME_NONE

        def on_delete_event():
            self.player.stop()
            gtk.main_quit()
        self.connect('delete-event', lambda *x: on_delete_event())

    def load_file(self, location):
        self.player.set_location(location)
                                 
    def play(self):
        self.player.play()
       
    def populate_combobox(self):
        switch = self.player.pipeline.get_by_name('s')
        for i, pad in enumerate([p for p in switch.pads()
                                 if p.get_direction() == gst.PAD_SINK]):
            self.combobox.append_text(pad.get_name())
            if switch.get_property('active-pad') == pad.get_name():
                self.combobox.set_active(i)
        if self.combobox.get_active() == -1:
            self.combobox.set_active(0)

    def combobox_changed(self):
        model = self.combobox.get_model()
        row = model[self.combobox.get_active()]
        padname, = row
        self.player.switch(padname)

    def onPad(self,element, pad,target):
        #sinkpad = target.get_compatible_pad(pad, pad.get_caps())
        #print sinkpad
        #pad.link(sinkpad)
        caps = pad.get_caps()
        name = caps[0].get_name()
        #for now only like the video pad from uridecode
        if name == 'video/x-raw-yuv':
            tpad = target.get_pad('sink')
            if not tpad.is_linked():
                pad.link(tpad)
                print 'on_pad_added:', name

        return True

    def enter_callback(self, widget, entry):


        myuri = gst.element_factory_make("uridecodebin")
        myuri.set_property("uri","http://localhost:8000/p2.ogg")
        myuri.set_property("name","xyz")

        myq = gst.element_factory_make("queue")
        #myq.set_property("leaky","upstream")

        self.player.pipeline.add(myuri,myq)

        #link stuff up
        myuri.connect("pad-added",self.onPad,myq)

        # get the element in the bin who's name is 's', ie input-selector
        # then get the src pad on the queue element and use the below code
        # to connect stuff
        inputselectorelement = self.player.pipeline.get_by_name('s')
        myq.link(inputselectorelement)
        self.populate_combobox()

        myuri.set_state(gst.STATE_READY)
        myq.set_state(gst.STATE_READY)
       
        #For whatever reason when I hook this thing in, it plays weird, and throws
        # off tons of QOS dropped frames
        # guessing something with the element system clocks.   for some reason
        # when I add things to an active pipeline, they get their base_time set
        # to what the others are, and not when these new ones really started
        # so this is an attempt to address that, assuming this is the real problem
        print "clock testing"
        myclk = myuri.get_clock()
        print myclk.get_time()
        print myuri.get_base_time()
        print myclk.get_time() - myuri.get_base_time()
        xxx= myclk.get_time()
        myuri.set_base_time(xxx)
        myq.set_base_time(xxx)

        myuri.set_state(gst.STATE_PLAYING)
        myq.set_state(gst.STATE_PLAYING)

        print "clock checks"
        print 'videotestsrc base time'
        tel = self.player.pipeline.get_by_name('blah')
        print tel.get_base_time()
        print "myuri"
        print myuri.get_base_time()
        print "myq"
        print myq.get_base_time()

        #myqpadsrc = myq.get_pad('src')
        #ipadsink = inputselectorelement.get_pad('sink')
        #inputselectorelement.link_pads(myqpadsrc,inputselectorelement,ipadsink)


        entry_text = entry.get_text()
        print "Entry contents: %s\n" % entry_text

    def create_ui(self):
        vbox = gtk.VBox()
        self.add(vbox)

        self.videowidget = VideoWidget()
        vbox.pack_start(self.videowidget)
       
        hbox = gtk.HBox()
        vbox.pack_start(hbox, fill=False, expand=False)
       
        self.combobox = combobox = gtk.combo_box_new_text()
        combobox.show()
        hbox.pack_start(combobox)

        self.combobox.connect('changed',
                              lambda *x: self.combobox_changed())

        self.videowidget.connect_after('realize',
                                       lambda *x: self.play())
        entry = gtk.Entry()
        entry.set_max_length(50)
        entry.connect("activate", self.enter_callback, entry)
        entry.set_text("hello")
        entry.insert_text(" world", len(entry.get_text()))
        entry.select_region(0, len(entry.get_text()))
        hbox.pack_start(entry)
        entry.show()

def main(args):
    def usage():
        sys.stderr.write("usage: %s\n" % args[0])
        return 1

    # Need to register our derived widget types for implicit event
    # handlers to get called.
    gobject.type_register(SwitchWindow)
    gobject.type_register(VideoWidget)

    if len(args) != 1:
        return usage()

    w = SwitchWindow()
    w.show_all()
    gtk.main()
    return 0

if __name__ == '__main__':
    sys.exit(main(sys.argv))






_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel


_______________________________________________
gstreamer-devel mailing list
[hidden email]
http://lists.freedesktop.org/mailman/listinfo/gstreamer-devel