--- /dev/null
+#!/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