New GUI for 2016 edition
authorDavid Testé <soonum@gnu.org>
Wed, 17 Feb 2016 21:41:04 +0000 (22:41 +0100)
committerDavid Testé <soonum@gnu.org>
Wed, 17 Feb 2016 21:41:04 +0000 (22:41 +0100)
Python implementation using GTK3.0 and Gst1.0 (still in debugging)

stream_2016/gstpipeline.py [new file with mode: 0755]
stream_2016/gstream_pipeline_by_quidam [new file with mode: 0644]
stream_2016/libre-streamer.py [new file with mode: 0755]

diff --git a/stream_2016/gstpipeline.py b/stream_2016/gstpipeline.py
new file mode 100755 (executable)
index 0000000..d789548
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3.4
+
+from gi.repository import Gst
+
+
+def constructpipeline (self):
+
+
+    """Add and link elements in a GStreamer pipeline"""
+
+    # Create the pipelines instance.
+    self.streampipe = Gst.Pipeline()
+    self.storepipe_hi = Gst.Pipeline()
+    self.storepipe_lo = Gst.Pipeline()
+
+    # Define pipeline elements.
+## The next line will NOT display the camera's video feed
+##    self.videosrc = Gst.ElementFactory.make('location', 'rtsp://192.168.48.2:554')
+    self.videosrc = Gst.ElementFactory.make('videotestsrc', 'source')
+
+    self.queue = Gst.ElementFactory.make('queue')
+
+##    self.oggstreamsink = Gst.ElementFactory.make()
+##    self.oggdisksink = Gst.ElementFactory.make()
+
+##    self.jpegdisksink = Gst.ElementFactory.make()
+
+    self.screensink = Gst.ElementFactory.make('sink', 'xvimagesink')
+    
+##    self.webmdisksink = Gst.ElementFactory.make()
+##    self.webmstreamsink = Gst.ElementFactory.make()
+    
+    # Add the elements to the pipeline.
+    self.streampipe.add(self.videosrc,
+                        self.queue,
+                        self.screensink,)
+
+    # Link the elements in the pipeline.
+
+constructpipeline()
+streampipe.set_state(Gst.State.PLAYING)
\ No newline at end of file
diff --git a/stream_2016/gstream_pipeline_by_quidam b/stream_2016/gstream_pipeline_by_quidam
new file mode 100644 (file)
index 0000000..d0655be
--- /dev/null
@@ -0,0 +1,25 @@
+Primary command (need to be enhanced):
+--------------------------------------
+One line = one pipeline
+
+gst-launch-1.0 -e rtspsrc location=rtsp://192.168.48.2:554 latency=100 ! queue ! rtpjpegdepay ! tee name=rawjpeg ! queue ! jpegdec max-errors=-1 ! tee name=rawvideo ! queue ! xvimagesink 
+rawjpeg. ! queue ! matroskamux name=mux 
+pulsesrc ! queue ! vorbisenc quality=0.3 ! tee name=oggaudio 
+pulsesrc ! queue ! flacenc ! queue ! queue ! mux. mux. ! queue ! filesink location=popo 
+rawvideo. ! videoscale ! video/x-raw, width=640, height=360 ! vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=2 sharpness=7 ! queue ! webmmux name=mux2 
+oggaudio. ! queue ! queue ! mux2. mux2. ! queue ! tee name=streamlo ! queue ! filesink location=popo2 
+oggaudio. ! queue ! oggmux ! queue ! tee name=streamaudio ! queue ! filesink location=popo4 
+streamlo. ! queue ! shout2send ip=live.fsf.org port=80 mount=testlo.ogv password=icecastfsf1 
+streamaudio. ! queue ! shout2send ip=live.fsf.org port=80 mount=testaudio.ogv password=icecastfsf1 
+
+##
+## TODO: Investigate double queues and double mux.
+##
+
+Lightened command (to do CPU load benchmarking):
+Do changes here and merge it with the primary command
+-----------------------------------------------------
+gst-launch-1.0 -e rtspsrc location=rtsp://192.168.48.2:554 latency=100 ! queue ! rtpjpegdepay !  queue ! jpegdec max-errors=-1 ! tee name=rawvideo ! queue ! xvimagesink 
+pulsesrc ! queue ! vorbisenc quality=0.3 ! tee name=oggaudio 
+rawvideo. ! vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=2 sharpness=7 ! queue ! webmmux name=mux2 
+oggaudio. ! queue ! queue ! mux2. mux2. ! queue ! tee name=streamlo ! queue ! filesink location=popo2
diff --git a/stream_2016/libre-streamer.py b/stream_2016/libre-streamer.py
new file mode 100755 (executable)
index 0000000..1ac1bc1
--- /dev/null
@@ -0,0 +1,161 @@
+#!/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é
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# TODO list:
+# ----------
+#    - Create a module for the pipeline construction section to clarify the code
+#    - Create a module for the network configuration (ifconfig, stream server,etc)
+#    - Generate a log file during runtime. (e.g. this will let you know if the network configuration
+#      and the pipeline construction went well (or not))
+#    - Add an input source choice for the user (camera on IP or webcam)
+#    - Add a VU-meter to check if audio feed is emitting signal
+#    - Investigate this error (at stream launching during prototyping phase):
+#        (libre-streamer.py:7856): Gdk-ERROR **: The program 'libre-streamer.py' received an X Window System error.
+#        This probably reflects a bug in the program.
+#        The error was 'BadIDChoice (invalid resource ID chosen for this connection)'.
+#        (Details: serial 592 error_code 14 request_code 1 (core protocol) minor_code 0)
+#    - Add the FSF logo (need to do some pixel art) as an application icon
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+import sys
+
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+from gi.repository import Gst
+from gi.repository import GdkX11
+from gi.repository import GstVideo
+
+##import networkinit
+##import gstpipeline
+
+
+class Streamgui(object):
+
+
+    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()
+        self.win.set_title("Libre-Streamer")
+        self.win.connect("delete_event",
+                         lambda w,e: Gtk.main_quit())
+        vbox = Gtk.VBox(False, 0)
+        hbox = Gtk.HBox(False, 0)
+        self.load_file = Gtk.FileChooserButton("Choose Audio File")
+        self.stream_button = Gtk.Button("Stream")
+        self.videowidget = Gtk.DrawingArea()
+        self.videowidget.set_size_request(600, 400)
+        self.load_file.connect("selection-changed", self.on_file_selected)
+        self.stream_button.connect("clicked", self.on_stream_clicked)
+
+        hbox.pack_start(self.stream_button, False, True, 0)
+        vbox.pack_start(self.load_file, False, True, 0)
+        vbox.pack_start(self.videowidget, True, True, 0)
+        vbox.pack_start(hbox, False, True, 0)
+        self.win.add(vbox)
+        self.win.set_position(Gtk.WindowPosition.CENTER)
+        self.win.show_all()
+
+        bus = self.pipel.get_bus()
+        bus.add_signal_watch()
+        bus.enable_sync_message_emission()
+        # Used to get messages that GStreamer emits.
+        bus.connect("message", self.on_message)
+        # Used for connecting video to your application.
+        bus.connect("sync-message::element", self.on_sync_message)
+
+    def constructpipeline (self):
+
+        """Add and link elements in a GStreamer pipeline"""
+
+        # Create the pipelines instance.
+        self.streampipe = Gst.Pipeline()
+##        self.storepipe_hi = Gst.Pipeline()
+##        self.storepipe_lo = Gst.Pipeline()
+
+        # Define pipeline elements.
+        ## The next line WILL NOT display the camera's video feed
+        ##    self.videosrc = Gst.ElementFactory.make('location', 'rtsp://192.168.48.2:554')
+        self.videosrc = Gst.ElementFactory.make('videotestsrc', 'source')
+        self.queue = Gst.ElementFactory.make('queue')
+        ##    self.oggstreamsink = Gst.ElementFactory.make()
+        ##    self.oggdisksink = Gst.ElementFactory.make()
+
+        ##    self.jpegdisksink = Gst.ElementFactory.make()
+
+        self.screensink = Gst.ElementFactory.make('xvimagesink', 'rawfeed')
+    
+        ##    self.webmdisksink = Gst.ElementFactory.make()
+        ##    self.webmstreamsink = Gst.ElementFactory.make()
+    
+        # Add the elements to the pipeline.
+        self.streampipe.add(self.videosrc)
+        self.streampipe.add(self.queue)
+        self.streampipe.add(self.screensink)
+        # Link the elements in the pipeline.
+        self.videosrc.link(self.queue)
+        self.queue.link(self.screensink)
+
+        return self.streampipe
+
+    def on_message(self, bus, message):
+
+        t = message.type
+        if t == Gst.MessageType.EOS:
+            self.player.set_state(Gst.State.NULL)
+        elif t == Gst.MessageType.ERROR:
+            self.player.set_state(Gst.State.NULL)
+            err, debug = message.parse_error()
+            print ("Error: %s" % err, debug)
+
+    def on_sync_message(self, bus, message):
+
+        if message.get_structure().get_name() == 'prepare-window-handle':
+            imagesink = message.src
+            imagesink.set_property('force-aspect-ratio', True)
+            imagesink.set_window_handle(self.videowidget.get_property('window').get_xid())
+            
+
+    # USE THAT FUNCTION TO GET THE SOURCE CHOICE (ELPHEL OR WEBCAM)        
+    def on_file_selected(self, widget):
+
+        self.multimedia_file = self.load_file.get_filename()
+
+    def on_stream_clicked(self, widget):
+
+        # Put here the script to launch streaming and start recording
+##        self.streampipe.uri_construct('rtsp', '://192.168.48.2:554')
+        labelname = self.stream_button.get_label()
+        if labelname == 'Stream':
+            self.pipel.set_state(Gst.State.PLAYING)
+            self.stream_button.set_label('ON AIR')
+        elif labelname == 'ON AIR':
+            self.pipel.set_state(Gst.State.NULL)
+            self.stream_button.set_label('Stream')
+
+
+if __name__ == "__main__":
+    Gst.init()
+    Streamgui()
+    Gtk.main()
\ No newline at end of file