import gobject
gobject.threads_init()
import pygst
pygst.require('0.10')
import gst

class AyFiltersBin(gst.Bin):
    __gstdetails__ = ('AyFiltersBin', 'Filter', \
                      'Custom aylook filter element', 'Luca Ognibene')

    __gsttemplates__ = (
        gst.PadTemplate("sink",
                        gst.PAD_SRC,
                        gst.PAD_ALWAYS,
                        gst.caps_new_any()),
        gst.PadTemplate("src%d",
                        gst.PAD_SRC,
                        gst.PAD_REQUEST,
                        gst.caps_new_any())
        )

    def __init__(self):
        gst.Bin.__init__(self)
        
        self._first_el = gst.element_factory_make("typefind", "first-queue")
        self.add(self._first_el)
        self._sinkpad = gst.GhostPad("sink", self._first_el.get_pad('sink'))
        self._sinkpad.set_active(True)
        self.add_pad(self._sinkpad)
        
        self._tee_main = gst.element_factory_make("tee", "tee-main")
        self.add(self._tee_main)
        self._first_el.link(self._tee_main)

        self._pads = {}

    ## Overrides
    def do_request_new_pad(self, templ, name):

        if self._pads.has_key(name):
            return self._pads[name]

        gh = gst.ghost_pad_new_notarget(name, gst.PAD_SRC)
        gh.set_active(True)
        self.add_pad(gh)
        self._pads[name] = gh
        gh.set_link_function(self._linkf)
        #gh.connect('linked', self._linked)

        return gh

    def _linkf(self, pad, peer):
        print "LINK FUNCTION"
        self._linked(pad, peer)
        print "ret ok"
        return gst.PAD_LINK_OK

    def _linked(self, pad, peer):
        print "LINKED", pad

        bin = gst.parse_bin_from_description("queue2 ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity ! identity", True)
        (ret, cur, pend) = self.get_state()
        src = self._tee_main.get_request_pad('src0')        
        if cur == gst.STATE_PLAYING:
            print "BLOCKING"
            src.set_blocked(True)
        self.add(bin)

        print "link src"
        src.link(bin.get_pad('sink'))
        
        pad.set_target(bin.get_pad('src'))
        print "go to play"
        bin.set_state(gst.STATE_PLAYING)
        if cur == gst.STATE_PLAYING:
            print "unblock"
            src.set_blocked(False)
            print "create"
        print "ret"
        

gobject.type_register(AyFiltersBin)
gst.element_register(AyFiltersBin, "ayfiltersbin", gst.RANK_MARGINAL)

if __name__ == '__main__':
    
    class Test:
        def __init__(self):
            self.last_bin = None
            
        def test_bus_event(self, bus, message):
            t = message.type
            obj = message.src
            if t == gst.MESSAGE_EOS:
                print "MESSAGE EOS"
            elif t == gst.MESSAGE_ERROR:
                err, debug = message.parse_error()
                print "MESSAGE Error: %s" % err, debug
            elif t == gst.MESSAGE_WARNING:
                err, debug = message.parse_warning()
                print "MESSAGE Warning: %s" % err, debug
            elif t == gst.MESSAGE_STATE_CHANGED:
                old, new, pend = message.parse_state_changed()
                old = gst.element_state_get_name(old)
                new = gst.element_state_get_name(new)
                pend = gst.element_state_get_name(pend)
                #if new == "PLAYING":
                if False:
                    print "Object %s changed state from %s to %s [%s]" % (obj.get_name(),old,new,pend)
                    if obj.get_name().startswith('bin'):
                        if self.last_bin != None:
                            print self.last_bin
                            ret = self.last_bin.set_state(gst.STATE_PLAYING)
                            print ret
            else:
                print message.type
            return True
    
        def test_stop(self, loop):
            print "Test stop"
            loop.stop()
            return False

        def _probe_sink(self, pad, buffer):
            if self.pads.has_key(pad) == False:
                print "BUFFER ON", pad
            self.pads[pad] = True
            return True

        def test_request(self, name, pipe, el):
            print "Test", name
            pad = el.get_request_pad(name)
            bin = gst.parse_bin_from_description("queue ! fakesink name=f", True)
            f = bin.get_by_name('f')
            f.get_pad('sink').add_buffer_probe(self._probe_sink)
            print "create", bin
            pipe.add(bin)
            ret = bin.set_state(gst.STATE_READY)
            print "set state", ret
            ret = pad.link(bin.get_pad('sink'))
            print "link", int(ret)
            ret = bin.set_state(gst.STATE_PLAYING)
            print "set state2", ret            
            self.last_bin = bin
            return False

        def do(self):
            self.pads = {}
            bin = "videotestsrc ! video/x-raw-yuv,framerate=20/1 ! ayfiltersbin name=f f.src0 ! queue ! fakesink"
            bin = gst.parse_launch(bin)
            bin.get_bus().add_watch(self.test_bus_event)
            bin.set_state(gst.STATE_PLAYING)
            f = bin.get_by_name("f")
            n = 5000
            for p in ['src1', 'src2', 'src3', 'src4']:
                gobject.timeout_add(n, self.test_request, p, bin, f)
                n += 5000                
            l = gobject.MainLoop()
            try:
                l.run()
            except:
                pass
            bin.set_state(gst.STATE_NULL)
    
    t = Test()
    t.do()
