Commit | Line | Data |
---|---|---|
6fdd41d9 DT |
1 | #!/usr/bin/env python3.4 |
2 | ||
3 | # This file is part of Libre-Streamer. | |
4 | # | |
5 | # Libre-Streamer is free software: you can redistribute it and/or modify | |
6 | # it under the terms of the GNU General Public License as published by | |
7 | # the Free Software Foundation, either version 3 of the License, or | |
8 | # (at your option) any later version. | |
9 | # | |
10 | # Libre-Streamer is distributed in the hope that it will be useful, | |
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | # GNU General Public License for more details. | |
14 | # | |
15 | # You should have received a copy of the GNU General Public License | |
16 | # along with Libre-Streamer. If not, see <http://www.gnu.org/licenses/>. | |
17 | # | |
18 | # Copyright (c) 2016 David Testé | |
19 | ||
20 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
21 | # TODO list: | |
22 | # ---------- | |
23 | # - Create a module for the pipeline construction section to clarify the code | |
24 | # - Create a module for the network configuration (ifconfig, stream server,etc) | |
25 | # - Generate a log file during runtime. (e.g. this will let you know if the network configuration | |
26 | # and the pipeline construction went well (or not)) | |
27 | # - Add an input source choice for the user (camera on IP or webcam) | |
28 | # - Add a VU-meter to check if audio feed is emitting signal | |
29 | # - Investigate this error (at stream launching during prototyping phase): | |
30 | # (libre-streamer.py:7856): Gdk-ERROR **: The program 'libre-streamer.py' received an X Window System error. | |
31 | # This probably reflects a bug in the program. | |
32 | # The error was 'BadIDChoice (invalid resource ID chosen for this connection)'. | |
33 | # (Details: serial 592 error_code 14 request_code 1 (core protocol) minor_code 0) | |
34 | # - Add the FSF logo (need to do some pixel art) as an application icon | |
35 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
36 | ||
37 | import sys | |
38 | ||
39 | import gi | |
40 | gi.require_version('Gtk', '3.0') | |
41 | from gi.repository import Gtk | |
42 | from gi.repository import Gst | |
43 | from gi.repository import GdkX11 | |
44 | from gi.repository import GstVideo | |
45 | ||
46 | ##import networkinit | |
47 | ##import gstpipeline | |
48 | ||
49 | ||
50 | class Streamgui(object): | |
51 | ||
52 | ||
53 | def __init__(self): | |
54 | ||
55 | self.multimedia_file="" | |
56 | # Create the global pipeline (might wanna use a general bin instead) | |
57 | self.pipel = self.constructpipeline() | |
58 | # Create the GUI | |
59 | self.win = Gtk.Window() | |
60 | self.win.set_title("Libre-Streamer") | |
61 | self.win.connect("delete_event", | |
62 | lambda w,e: Gtk.main_quit()) | |
63 | vbox = Gtk.VBox(False, 0) | |
64 | hbox = Gtk.HBox(False, 0) | |
65 | self.load_file = Gtk.FileChooserButton("Choose Audio File") | |
66 | self.stream_button = Gtk.Button("Stream") | |
67 | self.videowidget = Gtk.DrawingArea() | |
68 | self.videowidget.set_size_request(600, 400) | |
69 | self.load_file.connect("selection-changed", self.on_file_selected) | |
70 | self.stream_button.connect("clicked", self.on_stream_clicked) | |
71 | ||
72 | hbox.pack_start(self.stream_button, False, True, 0) | |
73 | vbox.pack_start(self.load_file, False, True, 0) | |
74 | vbox.pack_start(self.videowidget, True, True, 0) | |
75 | vbox.pack_start(hbox, False, True, 0) | |
76 | self.win.add(vbox) | |
77 | self.win.set_position(Gtk.WindowPosition.CENTER) | |
78 | self.win.show_all() | |
79 | ||
80 | bus = self.pipel.get_bus() | |
81 | bus.add_signal_watch() | |
82 | bus.enable_sync_message_emission() | |
83 | # Used to get messages that GStreamer emits. | |
84 | bus.connect("message", self.on_message) | |
85 | # Used for connecting video to your application. | |
86 | bus.connect("sync-message::element", self.on_sync_message) | |
87 | ||
88 | def constructpipeline (self): | |
89 | ||
90 | """Add and link elements in a GStreamer pipeline""" | |
91 | ||
92 | # Create the pipelines instance. | |
93 | self.streampipe = Gst.Pipeline() | |
94 | ## self.storepipe_hi = Gst.Pipeline() | |
95 | ## self.storepipe_lo = Gst.Pipeline() | |
96 | ||
97 | # Define pipeline elements. | |
98 | ## The next line WILL NOT display the camera's video feed | |
99 | ## self.videosrc = Gst.ElementFactory.make('location', 'rtsp://192.168.48.2:554') | |
100 | self.videosrc = Gst.ElementFactory.make('videotestsrc', 'source') | |
101 | self.queue = Gst.ElementFactory.make('queue') | |
102 | ## self.oggstreamsink = Gst.ElementFactory.make() | |
103 | ## self.oggdisksink = Gst.ElementFactory.make() | |
104 | ||
105 | ## self.jpegdisksink = Gst.ElementFactory.make() | |
106 | ||
107 | self.screensink = Gst.ElementFactory.make('xvimagesink', 'rawfeed') | |
108 | ||
109 | ## self.webmdisksink = Gst.ElementFactory.make() | |
110 | ## self.webmstreamsink = Gst.ElementFactory.make() | |
111 | ||
112 | # Add the elements to the pipeline. | |
113 | self.streampipe.add(self.videosrc) | |
114 | self.streampipe.add(self.queue) | |
115 | self.streampipe.add(self.screensink) | |
116 | # Link the elements in the pipeline. | |
117 | self.videosrc.link(self.queue) | |
118 | self.queue.link(self.screensink) | |
119 | ||
120 | return self.streampipe | |
121 | ||
122 | def on_message(self, bus, message): | |
123 | ||
124 | t = message.type | |
125 | if t == Gst.MessageType.EOS: | |
126 | self.player.set_state(Gst.State.NULL) | |
127 | elif t == Gst.MessageType.ERROR: | |
128 | self.player.set_state(Gst.State.NULL) | |
129 | err, debug = message.parse_error() | |
130 | print ("Error: %s" % err, debug) | |
131 | ||
132 | def on_sync_message(self, bus, message): | |
133 | ||
134 | if message.get_structure().get_name() == 'prepare-window-handle': | |
135 | imagesink = message.src | |
136 | imagesink.set_property('force-aspect-ratio', True) | |
137 | imagesink.set_window_handle(self.videowidget.get_property('window').get_xid()) | |
138 | ||
139 | ||
140 | # USE THAT FUNCTION TO GET THE SOURCE CHOICE (ELPHEL OR WEBCAM) | |
141 | def on_file_selected(self, widget): | |
142 | ||
143 | self.multimedia_file = self.load_file.get_filename() | |
144 | ||
145 | def on_stream_clicked(self, widget): | |
146 | ||
147 | # Put here the script to launch streaming and start recording | |
148 | ## self.streampipe.uri_construct('rtsp', '://192.168.48.2:554') | |
149 | labelname = self.stream_button.get_label() | |
150 | if labelname == 'Stream': | |
151 | self.pipel.set_state(Gst.State.PLAYING) | |
152 | self.stream_button.set_label('ON AIR') | |
153 | elif labelname == 'ON AIR': | |
154 | self.pipel.set_state(Gst.State.NULL) | |
155 | self.stream_button.set_label('Stream') | |
156 | ||
157 | ||
158 | if __name__ == "__main__": | |
159 | Gst.init() | |
160 | Streamgui() | |
161 | Gtk.main() |