# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# INFO: run the following command in a terminal before launching libre-streamer to get a error log.
-# GST_DEBUG=3,python:5,gnl*:5 ./libre-streamer.py | tee -a log 2>&1
+# GST_DEBUG=4,python:5,gnl*:5 ./libre-streamer.py | tee -a log 2>&1
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
__author__ = 'David Testé'
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
+gi.require_version('Gst', '1.0')
from gi.repository import Gst
from gi.repository import GdkX11
from gi.repository import GstVideo
def __init__(self):
self.multimedia_file=""
- # Create the global pipeline (might wanna use a general bin instead)
self.pipel = self.constructpipeline()
# Create the GUI
self.win = Gtk.Window()
bus.connect("message", self.on_message)
# Used for connecting video to your application.
bus.connect("sync-message::element", self.on_sync_message)
- # Connect the rtpdepay signal
+ # Connect the rtpjpegdepay signal
self.videosrc.connect("pad-added", self.on_pad_added_to_rtspsrc)
- if self.decodebin:
- self.decodebin.connect("pad-added", self.on_pad_added_to_decodebin)
-## elif self.jpegdec:
-## self.jpegdec.connect("pad-added", self.on_pad_added_to_jpegdec)
+
def on_pad_added_to_rtspsrc(self, rtspsrc, pad):
-## if self.decodebin:
-## sinkpad = self.decodebin.get_static_pad('sink')
-## elif self.rtpjpegdepay:
-## sinkpad = self.rtpjpegdepay.get_static_pad('sink')
sinkpad = self.queuev_1.get_static_pad('sink')
pad.link(sinkpad)
print('[DEBUG] rtspsrc LINKED')
- def on_pad_added_to_decodebin(self, decodebin, pad):
- screen_sinkpad = self.screensink.get_static_pad('sink')
- pad.link(screen_sinkpad)
- print('[DEBUG] decodebin LINKED')
-
def on_pad_added_to_jpegdec(self, jpegdec, pad):
screen_sinkpad = self.screensink.get_static_pad('sink')
pad.link(screen_sinkpad)
print('[DEBUG] decodebin LINKED')
+
+ def connect_tee(self, tee_element, input_element, output_element_1, output_element_2):
+ """Links input and outputs of a given Gst 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)
+ print('[DEBUG] Elements linked to tee')
+ else:
+ print('[ERROR] Couldn\'t link the tee. Element(s) probably not in the pipeline ')
def constructpipeline (self):
"""Add and link elements in a GStreamer pipeline"""
#---------------------------------------------------------------------------
self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc')
self.vorbisenc = Gst.ElementFactory.make('vorbisenc', 'vorbisenc')
-## scaling_caps = Gst.Caps('video/x-raw, width=640, height=360')
+ self.oggmux = Gst.ElementFactory.make('oggmux', 'oggmux')
self.scaling = Gst.ElementFactory.make('videoscale', 'scaling')
+## scaling_caps = Gst.caps_from_string('video/x-raw, width=640, height=360')
+## self.scaling.set_property('width', 640)
+## self.scaling.set_property('height', 360)
+## self.scalefilter = Gst.ElementFactory.make('capsfilter')
+## self.scalefilter.set_property('caps', scaling_caps)
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('sharpness', 7)
self.webmmux = Gst.ElementFactory.make('webmmux', 'webmmux')
self.webmmux.set_property('streamable', True)
-
- self.tee_streamvideo = Gst.ElementFactory.make('tee', 'tee_streamvideo')
+
+ self.tee_videodecoded = Gst.ElementFactory.make('tee', 'tee_videodecoded')
+ self.tee_streamfull = Gst.ElementFactory.make('tee', 'tee_streamfull')
self.tee_streamaudio = Gst.ElementFactory.make('tee', 'tee_streamaudio')
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.queuev_5 = Gst.ElementFactory.make('queue', 'queuev_5')
+ self.queuev_6 = Gst.ElementFactory.make('queue', 'queuev_6')
+ self.queuev_7 = Gst.ElementFactory.make('queue', 'queuev_7')
+ self.queuem_1 = Gst.ElementFactory.make('queue', 'queuem_1')
+ self.queuem_2 = Gst.ElementFactory.make('queue', 'queuem_2')
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')
-
+
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', '')
+ 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', '')
+ self.icecastsink_stream.set_property('password', 'thahw3Wiez')
#---------------------------------------------------------------------------
# Add the elements to the pipeline.
- # Test of the first two lines of quidam's pipeline:
+ # + Raw video and screen monitoring feed:
self.streampipe.add(self.videosrc)
-## self.streampipe.add(self.decodebin)
self.streampipe.add(self.queuev_1)
self.streampipe.add(self.rtpjpegdepay)
self.streampipe.add(self.queuev_2)
self.streampipe.add(self.queuev_3)
self.streampipe.add(self.mkvmux)
self.streampipe.add(self.queuev_4)
+## self.streampipe.add(self.tee_videodecoded)
self.streampipe.add(self.disksink_rawvideo)
self.streampipe.add(self.screensink)
-
+ # + Audio feed:
+ self.streampipe.add(self.audiosrc)
+ self.streampipe.add(self.queuea_1)
+ self.streampipe.add(self.vorbisenc)
+ self.streampipe.add(self.tee_streamaudio)
+ self.streampipe.add(self.queuea_2)
+ self.streampipe.add(self.oggmux)
+ self.streampipe.add(self.queuea_3)
+ self.streampipe.add(self.disksink_audio)
+ self.streampipe.add(self.queuea_4)
+ self.streampipe.add(self.icecastsink_audio)
+ # + Stream (audio and video) feed:
+ """
+ self.streampipe.add(self.queuev_6)
+ self.streampipe.add(self.scaling)
+ self.streampipe.add(self.scalefilter)
+ self.streampipe.add(self.vp8enc)
+ self.streampipe.add(self.queuev_5)
+ self.streampipe.add(self.webmmux)
+ self.streampipe.add(self.tee_streamfull)
+ self.streampipe.add(self.queuev_7)
+ self.streampipe.add(self.queuem_1)
+ self.streampipe.add(self.queuem_2)
+ self.streampipe.add(self.disksink_stream)
+## self.streampipe.add(self.icecastsink_stream)
+ """
+
# Link the elements in the pipeline.
-## self.videosrc.link(self.decodebin)
+ # + Raw video and screen monitoring feed:
self.queuev_1.link(self.rtpjpegdepay)
-## self.rtpjpegdepay.link(self.queuev_2)
-## self.rtpjpegdepay.link(self.jpegdec)
- self.rtpjpegdepay.link(self.tee_rawvideo)
-## self.queuev_2.link(self.jpegdec)
-## self.jpegdec.link(self.tee_rawvideo)
-## self.jpegdec.link(self.queuev_3)
- self.tee_rawvideo.link(self.queuev_2)
- self.tee_rawvideo.link(self.jpegdec)
-## self.tee_rawvideo.link(self.queuev_3)
+## self.rtpjpegdepay.link(self.tee_rawvideo)
+## self.tee_rawvideo.link(self.queuev_2)
+## self.tee_rawvideo.link(self.jpegdec)
+ 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.decodebin.link(self.screensink)
-## self.queuev_3.link(self.disksink_rawvideo)
+ """
+ self.connect_tee(self.tee_videodecoded,
+ self.jpegdec,
+ self.queuev_3,
+ self.queuev_6,)
+ """
self.jpegdec.link(self.queuev_3)
self.queuev_3.link(self.screensink)
+ # + Audio feed:
+ self.audiosrc.link(self.queuea_1)
+ self.queuea_1.link(self.vorbisenc)
+ self.vorbisenc.link(self.queuea_2)
+ self.vorbisenc.link(self.queuea_2)
+ 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)
+ # + Linking Stream (audio and video) feed:
+## self.queuev_6.link(self.scalefilter)
+## self.scalefilter.link(self.scaling)
+## self.scaling.link(self.vp8enc)
+ """
+ self.queuev_6.link(self.vp8enc)
+ self.vp8enc.link(self.queuev_7)
+ self.queuev_7.link(self.webmmux)
+ self.webmmux.link(self.queuem_1)
+## self.queuea_4.link(self.webmmux)
+ self.connect_tee(self.tee_streamfull,
+ self.webmmux,
+ self.queuem_1,
+ self.queuem_2,)
+## self.webmmux.link(self.queuem_1)
+## self.webmmux.link(self.queuem_2)
+ self.queuem_1.link(self.disksink_stream)
+## self.queuem_2.link(self.icecastsink_stream)
+ """
return self.streampipe
def on_message(self, bus, message):