Full pipeline working and placed in an other module
[libre-streamer.git] / stream_2016 / gstconf.py
diff --git a/stream_2016/gstconf.py b/stream_2016/gstconf.py
new file mode 100755 (executable)
index 0000000..ce9f0a7
--- /dev/null
@@ -0,0 +1,305 @@
+#!/usr/bin/env python3.4
+
+# This file is part of Libre-Streamer.
+#
+# Libre-Streamer is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Libre-Streamer is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Libre-Streamer.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright (c) 2016 David Testé
+
+import gi
+from gi.repository import Gst
+from gi.repository import GstVideo
+
+class New_user_pipeline():
+    
+    def __init__(self):
+        self.user_pipeline = self.create_gstreamer_pipeline()
+        
+    def create_video_sources(self):
+        """Create video inputs from various sources."""
+        self.videosrc = Gst.ElementFactory.make('rtspsrc', 'videosrc')
+        self.videosrc.set_property('location', 'rtsp://192.168.48.2:554')
+        self.videosrc.set_property('latency', 0)
+        
+    def create_audio_sources(self):
+        """Create audio inputs from various sources."""
+        self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc')
+##        self.videosrc.set_property('latency', 0)
+
+    def create_pipeline_callbacks(self):
+        """Callbacks to connect dynamically created pads."""
+        self.videosrc.connect("pad-added", self.on_pad_added_to_rtspsrc)
+
+    def on_pad_added_to_rtspsrc(self, rtspsrc, pad):
+        """Connect the dynamic 'src'pad of an RTSP source."""
+        sinkpad = self.queuev_1.get_static_pad('sink')
+        pad.link(sinkpad)
+
+    def create_filesink(self):
+        """Create storable output elements."""
+        self.disksink_rawvideo = Gst.ElementFactory.make('filesink')
+        #[TO DO]: File location has to be defined 
+        self.disksink_rawvideo.set_property('location', 'popo_rawvideo')
+        self.disksink_audio = Gst.ElementFactory.make('filesink')
+        self.disksink_audio.set_property('location', 'popo_audio')
+        self.disksink_stream = Gst.ElementFactory.make('filesink')
+        self.disksink_stream.set_property('location', 'popo_stream')
+        
+    def create_streamsink(self):
+        """Create streamable output elements."""
+        # To local screen:
+        self.screensink = Gst.ElementFactory.make('xvimagesink', 'screensink')
+        # To icecast server:
+        self.icecastsink_audio = Gst.ElementFactory.make('shout2send', 'icecastsink_audio')
+## Configuration should be written on a file locally to keep safe private addresses
+        self.icecastsink_audio.set_property('ip', 'live2.fsf.org')
+        self.icecastsink_audio.set_property('port', 80)
+        self.icecastsink_audio.set_property('mount', 'testaudio.ogv')
+        self.icecastsink_audio.set_property('password', 'thahw3Wiez')
+        self.icecastsink_stream = Gst.ElementFactory.make('shout2send', 'icecastsink_stream')
+        self.icecastsink_stream.set_property('ip', 'live2.fsf.org')
+        self.icecastsink_stream.set_property('port', 80)
+        self.icecastsink_stream.set_property('mount', 'teststream.ogv')
+        self.icecastsink_stream.set_property('password', 'thahw3Wiez')
+
+    def create_payloader_elements(self):
+        pass
+        
+    def create_depayloader_elements(self):
+        self.rtpjpegdepay = Gst.ElementFactory.make('rtpjpegdepay', 'rtpjpegdepay')
+        
+    def create_encoder_elements(self):
+        # Audio encoders:
+        self.vorbisenc = Gst.ElementFactory.make('vorbisenc', 'vorbisenc')
+        # Video encoders:
+        self.vp8enc = Gst.ElementFactory.make('vp8enc', 'vp8enc')
+        self.vp8enc.set_property('min_quantizer', 1)
+        self.vp8enc.set_property('max_quantizer', 13)
+        self.vp8enc.set_property('cpu-used', 5)
+        self.vp8enc.set_property('deadline', 42000)
+        self.vp8enc.set_property('threads', 2)
+        self.vp8enc.set_property('sharpness', 7)
+
+    def create_decoder_elements(self):
+        self.jpegdec = Gst.ElementFactory.make('jpegdec', 'jpegdec')
+        self.jpegdec.set_property('max-errors', -1)
+
+    def create_muxer_elements(self):
+        self.oggmux = Gst.ElementFactory.make('oggmux', 'oggmux')
+        self.mkvmux = Gst.ElementFactory.make('matroskamux', 'mkvmux')
+        self.webmmux = Gst.ElementFactory.make('webmmux', 'webmmux')
+        self.webmmux.set_property('streamable', True)
+        
+    def create_demuxer_elements(self):
+        pass
+
+    def create_filtering_elements(self):
+        self.scaling = Gst.ElementFactory.make('videoscale', 'scaling')
+        caps = Gst.caps_from_string('video/x-raw, width=(int)640, height=(int)360')
+        self.capsfilter = Gst.ElementFactory.make('capsfilter', 'capsfilter')
+        self.capsfilter.set_property('caps', caps)
+        
+    def create_tee_elements(self):
+        """Create tee elements to divide feeds."""
+        self.tee_rawvideo = Gst.ElementFactory.make('tee', 'tee_rawvideo')
+        self.tee_videodecoded = Gst.ElementFactory.make('tee', 'tee_videodecoded')
+        self.tee_streamfull = Gst.ElementFactory.make('tee', 'tee_streamfull')
+        self.tee_rawaudio = Gst.ElementFactory.make('tee', 'tee_rawaudio')
+        self.tee_streamaudio = Gst.ElementFactory.make('tee', 'tee_streamaudio')
+
+    def connect_tee(self,
+                    tee_element,
+                    input_element,
+                    output_element_1,
+                    output_element_2,):
+        """Links input and outputs of a given tee element."""
+        # Find a way to check if the element given are in the pipeline
+        # then pass the result to the 'if' statement.
+        ##        argcheck = [True for arg in locals() if arg in 'the_list_of_elements_added']
+        ##        print('[DEBUG] ArgList check: ', argcheck)
+        ##        if False not in argcheck
+        if True:
+            input_element.link(tee_element)
+            tee_element.link(output_element_1)
+            tee_element.link(output_element_2)
+        else:
+            print('[ERROR] Couldn\'t link the tee. Element(s) probably not in the pipeline ')
+
+    def create_queues(self):
+        # For video feed:
+        self.queuev_1 = Gst.ElementFactory.make('queue', 'queuev_1')
+        self.queuev_2 = Gst.ElementFactory.make('queue', 'queuev_2')
+        self.queuev_3 = Gst.ElementFactory.make('queue', 'queuev_3')
+        self.queuev_4 = Gst.ElementFactory.make('queue', 'queuev_4')
+        self.queuev_5 = Gst.ElementFactory.make('queue', 'queuev_5')
+        self.queuev_6 = Gst.ElementFactory.make('queue', 'queuev_6')
+        # For audio feed:
+        self.queuea_1 = Gst.ElementFactory.make('queue', 'queuea_1')
+        self.queuea_2 = Gst.ElementFactory.make('queue', 'queuea_2')
+        self.queuea_3 = Gst.ElementFactory.make('queue', 'queuea_3')
+        self.queuea_4 = Gst.ElementFactory.make('queue', 'queuea_4')
+        self.queuea_5 = Gst.ElementFactory.make('queue', 'queuea_5')
+        # For audio+video muxer:
+        self.queuem_1 = Gst.ElementFactory.make('queue', 'queuem_1')
+        self.queuem_2 = Gst.ElementFactory.make('queue', 'queuem_2')
+
+    def create_pipeline_elements(self):
+        print('Pipeline creation state: creating elements... ', end='')
+        # Inputs elements:
+        self.create_video_sources()
+        self.create_audio_sources()
+        # Middle elements:
+        self.create_payloader_elements()
+        self.create_depayloader_elements()
+        self.create_encoder_elements()
+        self.create_decoder_elements()
+        self.create_muxer_elements()
+        self.create_filtering_elements()
+        self.create_tee_elements()
+        self.create_queues()
+        # Output elements:
+        self.create_filesink()
+        self.create_streamsink()
+        print('created')
+    
+
+    def add_elements_to_pipeline(self):
+        print('Pipeline creation state: adding elements... ', end='')
+        # Inputs elements:
+        self.streampipe.add(self.videosrc)
+        self.streampipe.add(self.audiosrc)
+        # Middle elements:
+        self.streampipe.add(self.rtpjpegdepay)
+        self.streampipe.add(self.jpegdec)
+        self.streampipe.add(self.tee_rawvideo)
+        self.streampipe.add(self.mkvmux)
+        self.streampipe.add(self.vorbisenc)
+        self.streampipe.add(self.oggmux)
+        self.streampipe.add(self.scaling)
+        self.streampipe.add(self.capsfilter)
+        self.streampipe.add(self.vp8enc)
+        self.streampipe.add(self.webmmux)
+        self.streampipe.add(self.tee_rawaudio)
+        self.streampipe.add(self.tee_streamaudio)
+        self.streampipe.add(self.tee_videodecoded)
+        self.streampipe.add(self.tee_streamfull)
+        self.streampipe.add(self.queuev_1)
+        self.streampipe.add(self.queuev_2)
+        self.streampipe.add(self.queuev_3)
+        self.streampipe.add(self.queuev_4)
+        self.streampipe.add(self.queuev_5)
+        self.streampipe.add(self.queuev_6)
+        self.streampipe.add(self.queuea_1)
+        self.streampipe.add(self.queuea_2)
+        self.streampipe.add(self.queuea_3)
+        self.streampipe.add(self.queuea_4)
+        self.streampipe.add(self.queuea_5)
+        self.streampipe.add(self.queuem_1)
+        self.streampipe.add(self.queuem_2)
+        # Outputs elements:
+        self.streampipe.add(self.screensink)
+        self.streampipe.add(self.disksink_rawvideo)
+        self.streampipe.add(self.disksink_audio)
+        self.streampipe.add(self.disksink_stream)
+        self.streampipe.add(self.icecastsink_audio)
+        self.streampipe.add(self.icecastsink_stream)
+        print('added')
+        
+    def link_pipeline_elements(self):
+        """Link all elements with static pads."""
+        print('Pipeline creation state: linking elements... ', end='')
+        # Video feed:
+        self.queuev_1.link(self.rtpjpegdepay)
+        self.connect_tee(self.tee_rawvideo,
+                         self.rtpjpegdepay,
+                         self.queuev_2,
+                         self.jpegdec,)
+        self.queuev_2.link(self.mkvmux)
+        self.mkvmux.link(self.queuev_4)
+        self.queuev_4.link(self.disksink_rawvideo)
+        self.connect_tee(self.tee_videodecoded,
+                         self.jpegdec,
+                         self.queuev_3,
+                         self.scaling,)
+        self.queuev_3.link(self.screensink)
+        # Audio feed:
+        self.audiosrc.link(self.queuea_1)
+        self.queuea_1.link(self.vorbisenc)
+        self.connect_tee(self.tee_rawaudio,
+                         self.vorbisenc,
+                         self.queuea_2,
+                         self.queuea_5,)
+        self.queuea_2.link(self.oggmux)
+        self.connect_tee(self.tee_streamaudio,
+                         self.oggmux,
+                         self.queuea_3,
+                         self.queuea_4,)
+        self.queuea_3.link(self.disksink_audio)
+        self.queuea_4.link(self.icecastsink_audio)
+        self.queuea_5.link(self.webmmux)
+        # Stream (audio+video) feed:
+        self.scaling.link(self.capsfilter)
+        self.capsfilter.link(self.vp8enc)
+        self.vp8enc.link(self.queuev_6)
+        self.queuev_6.link(self.webmmux)
+        self.connect_tee(self.tee_streamfull,
+                         self.webmmux,
+                         self.queuem_1,
+                         self.queuem_2,)
+        self.queuem_1.link(self.disksink_stream)
+        self.queuem_2.link(self.icecastsink_stream)
+        print('linked')
+
+    def create_gstreamer_pipeline(self):
+        # New empty pipeline:
+        self.streampipe = Gst.Pipeline()
+        # Setting-up:
+        self.create_pipeline_elements()
+        self.add_elements_to_pipeline()
+        self.link_pipeline_elements()
+        self.create_pipeline_callbacks()
+
+        global bus
+        bus = self.streampipe.get_bus()
+        bus.add_signal_watch()
+        bus.enable_sync_message_emission()
+        # Used to get messages that GStreamer emits.
+        bus.connect("message", self.on_message)
+
+        print('Pipeline creation state: successfully done.')
+        return self.streampipe
+        
+    def on_message(self, bus, message):
+        t = message.type
+        if t == Gst.MessageType.EOS:
+            self.pipeol.set_state(Gst.State.NULL)
+            self.stream_button.set_label('Stream')
+        elif t == Gst.MessageType.ERROR:
+            err, debug = message.parse_error()
+            print ("Error: %s" % err, debug)
+            self.pipel.set_state(Gst.State.NULL)
+            self.stream_button.set_label('Stream')
+
+    def stream_play(self):
+        self.streampipe.set_state(Gst.State.PLAYING)
+        
+    def stream_stop(self):
+        self.streampipe.set_state(Gst.State.NULL)
+
+    def get_stream_state(self):
+        print(self.streampipe.get_state(self))
+##        return self.streampipe.get_state()
+
+def get_gstreamer_bus():
+    return bus