#!/usr/bin/env python
# Attempting to dynamically switch between input sources

# GdkX11 to get access to xid, GstVideo to get access to set_window_handle
import gi, signal, time
gi.require_version('Gtk', '3.0')
gi.require_version('Gst', '1.0')
gi.require_version('GstVideo', '1.0')
from gi.repository import Gtk, Gst, GdkX11, GstVideo

stream1="rtmp://matuku.hig.no/live/planet.stream"

class Main:
    def __init__(self):

        # Create gui bits and bobs

        self.mainwindow = Gtk.Builder()
        self.mainwindow.add_from_file("example5.glade")

        signals = {
            "on_input1_clicked" : self.SetInput1,
            "on_input2_clicked" : self.SetInput2,
            "on_input3_clicked" : self.SetInput3,
            "on_input4_clicked" : self.SetInput4,
            "on_input5_clicked" : self.SetInput5,
            "on_input6_clicked" : self.SetInput6,
            "on_quit_clicked" : self.OnQuit,
        }

        self.mainwindow.connect_signals(signals)

        # Create GStreamer bits and bobs

        # Initiate Gstreamer
        Gst.init(None)

        # Some capabilities we want to share between different elements
        jpegcaps = Gst.Caps.from_string("image/jpeg,width=1280,height=720,framerate=30/1")
        xrawcaps = Gst.Caps.from_string("video/x-raw,width=1280,height=720,framerate=30/1")

        # Set up the pipeline
        self.pipeline = Gst.Pipeline()

        # Add elements

        # src1
        self.src1 = Gst.ElementFactory.make("v4l2src", "src1")
        self.src1.set_property("device", "/dev/video0")
        self.src1caps = Gst.ElementFactory.make("capsfilter", "src1caps")
        self.src1caps.set_property("caps", jpegcaps)
        self.src1dec = Gst.ElementFactory.make("decodebin", "src1dec")

        # src2
        self.src2 = Gst.ElementFactory.make("videotestsrc", "src2")
        self.src2.set_property("pattern", "ball")
        self.src2caps = Gst.ElementFactory.make("capsfilter", "src2caps")
        self.src2caps.set_property("caps", xrawcaps)
        self.src2dec = Gst.ElementFactory.make("decodebin", "src2dec")

        # src3
        self.src3 = Gst.ElementFactory.make("rtmpsrc", "src3")
        self.src3.set_property("location", stream1)
        self.src3caps = Gst.ElementFactory.make("capsfilter", "src3caps")
        self.src3caps.set_property("caps", xrawcaps)
        self.src3dec = Gst.ElementFactory.make("decodebin", "src3dec")
        self.src3crop = Gst.ElementFactory.make("aspectratiocrop", "src3crop")
        self.src3crop.set_property("aspect-ratio", Gst.Fraction(16, 9))
        self.src3crop.set_property("message-forward", True)
        self.src3croppad = self.src3crop.get_static_pad("sink")
        self.src3scale = Gst.ElementFactory.make("videoscale")
        self.src3scalecaps = Gst.ElementFactory.make("capsfilter", "src3scalecaps")
        self.src3scalecaps.set_property("caps", Gst.Caps.from_string("width=1280,height=720"))

        # Video mix
        self.videomix = Gst.ElementFactory.make("videomixer", "videomix")
        self.src1pad = self.videomix.get_request_pad("sink_1")
        self.src1pad.set_property("zorder", 3)
        self.src2pad = self.videomix.get_request_pad("sink_2")
        self.src2pad.set_property("zorder", 2)
        self.src3pad = self.videomix.get_request_pad("sink_3")
        self.src3pad.set_property("zorder", 1)

        # Add main videosink
        self.videosink = Gst.ElementFactory.make("xvimagesink", "videosink")
        self.videosink.set_property("sync", False)

        # Add initial elements to the pipeline
        self.pipeline.add(self.src1)
        self.pipeline.add(self.src1caps)
        self.pipeline.add(self.src1dec)
        self.src1dec.connect("pad-added", self.OnPadAdded, self.src1pad, self.videomix)

        self.pipeline.add(self.src2)
        self.pipeline.add(self.src2caps)
        self.pipeline.add(self.src2dec)
        self.src2dec.connect("pad-added", self.OnPadAdded, self.src2pad, self.videomix)

        self.pipeline.add(self.src3)
        self.pipeline.add(self.src3dec)
        self.src3dec.connect("pad-added", self.OnPadAdded, self.src3croppad, self.src3crop)
        self.pipeline.add(self.src3crop)
        self.pipeline.add(self.src3scale)
        self.pipeline.add(self.src3scalecaps)

        self.pipeline.add(self.videomix)
        self.pipeline.add(self.videosink)

        # Link the initial pipeline
        if not self.src1.link(self.src1caps):
            print("Failed to link src1 to src1caps")
        if not self.src1caps.link(self.src1dec):
            print("Failed to link src1caps to src1dec")
        if not self.videomix.link(self.videosink):
            print("Failed to link videomix to videosink")

        if not self.src2.link(self.src2caps):
            print("Failed to link src2 to src2caps")
        if not self.src2caps.link(self.src2dec):
            print("Failed to link src2caps to src2dec")

        if not self.src3.link(self.src3dec):
            print("Failed to link src3 to src3dec")
        if not self.src3crop.link(self.src3scale):
            print("Failed to link src3crop to src3scale")
        if not self.src3scale.link(self.src3scalecaps):
            print("Failed to link src3scale to src3scalecaps")
        if not self.src3scalecaps.link_pads("src", self.videomix, "sink_3"):
            print("Failed to link src3scalecaps to videomix")

        # Set up a bus to our pipeline to get notified when the video is ready
        self.bus = self.pipeline.get_bus()
        self.bus.enable_sync_message_emission()
        self.bus.connect("sync-message::element", self.OnSyncElement)

        # Summon the window and connect the window's close button to quit
        self.window = self.mainwindow.get_object("mainwindow")
        self.window.connect("delete-event", Gtk.main_quit)
        self.window.show_all()

        # Get window ID of the viewport widget from the GUI
        self.win_id = self.mainwindow.get_object("viewport_main").get_window().get_xid()

        # Play!
        print(self.pipeline.set_state(Gst.State.READY))
        print(self.pipeline.set_state(Gst.State.PLAYING))
        self.pipeline.get_state


    # When we get a message that video is ready to display, set the
    # correct window id to hook it to our viewport
    def OnSyncElement(self, bus, message):
        if message.get_structure().get_name() == "prepare-window-handle":
            print("prepare-window-handle")
            message.src.set_window_handle(self.win_id)

    def OnPadAdded(self, element, pad, sink, target):
        print("Dynamic pad for " + element.name + " added, linking to " + target.name)
        print(sink.name)
        pad.link(sink)
        element.link(target)

    def SetInput1(self, widget):
        print("Switch to input 1")
        self.src1pad.set_property("zorder", 3)
        self.src2pad.set_property("zorder", 2)
        self.src3pad.set_property("zorder", 1)

    def SetInput2(self, widget):
        print("Switch to input 2")
        self.src1pad.set_property("zorder", 2)
        self.src2pad.set_property("zorder", 3)
        self.src3pad.set_property("zorder", 1)

    def SetInput3(self, widget):
        print("Switch to input 3")
        self.src1pad.set_property("zorder", 1)
        self.src2pad.set_property("zorder", 2)
        self.src3pad.set_property("zorder", 3)

    def SetInput4(self, widget):
        print("Switch to input 4")

    def SetInput5(self, widget):
        print("Switch to input 5")

    def SetInput6(self, widget):
        print("Switch to input 6")

    def OnQuit(self, widget):
        print("quit")
        Gtk.main_quit()

    # Workaround to get Ctrl+C to terminate from command line
    # ref: https://bugzilla.gnome.org/show_bug.cgi?id=622084#c12
    signal.signal(signal.SIGINT, signal.SIG_DFL)

start = Main()
Gtk.main()
