X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=stream_2016%2Fgstconf.py;fp=stream_2016%2Fgstconf.py;h=ce9f0a7733d1a4764b988e78bcd53adca27a8b46;hb=669383aa834b12e70a3496966f8630af1066bebb;hp=0000000000000000000000000000000000000000;hpb=3a030c1f1a623ab7f6e4f807f929d6b7d709123b;p=libre-streamer.git diff --git a/stream_2016/gstconf.py b/stream_2016/gstconf.py new file mode 100755 index 0000000..ce9f0a7 --- /dev/null +++ b/stream_2016/gstconf.py @@ -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 . +# +# 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