Deleting useless lines.
[libre-streamer.git] / stream_2016 / libre-streamer.py
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 # - Display the Gst element 'videotestsrc', in case of failure of the pipeline
24 # - Add a checkbox to enable/disable options (storing/streaming - storing only - stream only - etc...)
25 # - Add a function to get the ip address of the camera automatically (see github.com/paulmilliken)
26 # - Create a module for the network configuration (fan/cpu, ifconfig, stream server,etc)
27 # - Generate a log file during runtime. (e.g. this will let you know if the network configuration
28 # and the pipeline construction went well (or not))
29 # - Add an input source choice for the user (camera on IP or webcam)
30 # - Add a time counter
31 # - Add a VU-meter to check if audio feed is emitting signal
32 # - Add a 'CPU load' widget
33 # - Add the FSF logo (need to do some pixel art) as an application icon
34 # - Add the FSF logo inside the streamer use the 'textoverlay' method in ElementFactory.make()
35 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36
37 # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
38 # INFO: run the following command in a terminal before launching libre-streamer to get a error log.
39 # GST_DEBUG=4,python:5,gnl*:5 ./libre-streamer.py | tee -a log 2>&1
40 # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
41
42 __author__ = 'David Testé'
43 __licence__ = 'GPLv3'
44 __version__ = 0.1
45 __maintainer__ = 'David Testé'
46 __email__ = 'soonum@gnu.org'
47 __status__ = 'Prototype'
48
49
50 import sys
51 from time import time, gmtime, strftime
52
53 import gi
54 gi.require_version('Gtk', '3.0')
55 from gi.repository import Gtk
56 gi.require_version('Gst', '1.0')
57 from gi.repository import Gst
58 from gi.repository import GdkX11
59 from gi.repository import GstVideo
60 from gi.repository import GObject
61
62 import gstconf
63
64 formatted_date = strftime('%Y_%m_%d', gmtime())
65 metadata = {'speaker_name':'NC',
66 'session_title':'NC',
67 'organisation':'NC',}
68 start_time = 0
69
70 class Streamgui(object):
71
72
73 def __init__(self):
74
75 # Create the GUI
76 self.win = Gtk.Window()
77 self.win.set_title("Libre-Streamer")
78 self.win.connect("delete_event",
79 lambda w,e: Gtk.main_quit())
80 vbox = Gtk.VBox(False, 0)
81 vbox_labels = Gtk.VBox(False, 0)
82 vbox_entries = Gtk.VBox(False, 0)
83 vbox_streaminfo = Gtk.VBox(False, 0)
84 vbox_cpuinfo = Gtk.VBox(False, 0)
85 hbox = Gtk.HBox(False, 0)
86 hbox_time = Gtk.HBox(False, 0)
87
88 self.videowidget = Gtk.DrawingArea()
89 self.videowidget.set_size_request(600, 400)
90
91 self.baseinfo_label = Gtk.Label('Base info: ')
92 self.baseinfo_entry_label = Gtk.Label('LP_' + formatted_date)
93 self.speakerinfo_label = Gtk.Label('Speaker name: ')
94 self.speakerinfo_entry = Gtk.Entry()
95 self.sessioninfo_label = Gtk.Label('Session name: ')
96 self.sessioninfo_entry = Gtk.Entry()
97
98 self.stream_button = Gtk.Button("Stream")
99 self.stream_button.connect("clicked", self.on_stream_clicked)
100 self.streamtime_label = Gtk.Label('Time elapsed ')
101 self.streamtime_value = Gtk.Label('00:00:00')
102
103 vbox_labels.pack_start(self.baseinfo_label, True, True, 0)
104 vbox_labels.pack_start(self.speakerinfo_label, True, True, 0)
105 vbox_labels.pack_start(self.sessioninfo_label, True, True, 0)
106 vbox_entries.pack_start(self.baseinfo_entry_label, True, True, 0)
107 vbox_entries.pack_start(self.speakerinfo_entry, True, True, 0)
108 vbox_entries.pack_start(self.sessioninfo_entry, True, True, 0)
109 vbox_streaminfo.pack_start(self.stream_button, False, True, 15)
110 hbox_time.pack_start(self.streamtime_label, False, False, 0)
111 hbox_time.pack_start(self.streamtime_value, False, False, 0)
112 vbox_streaminfo.pack_start(hbox_time, False, True, 0)
113 hbox.pack_start(vbox_labels, False, False, 0)
114 hbox.pack_start(vbox_entries, False, False, 0)
115 hbox.pack_start(vbox_streaminfo, False, False, 0)
116 vbox.pack_start(self.videowidget, True, True, 0)
117 vbox.pack_start(hbox, False, True, 0)
118
119 self.win.add(vbox)
120 self.win.set_position(Gtk.WindowPosition.CENTER)
121 self.win.show_all()
122
123 self.xid = self.videowidget.get_property('window').get_xid()
124
125 self.pipel = gstconf.New_user_pipeline()
126
127 bus = gstconf.get_gstreamer_bus()
128 bus.connect("sync-message::element", self.on_sync_message)
129
130 def on_sync_message(self, bus, message):
131
132 if message.get_structure().get_name() == 'prepare-window-handle':
133 imagesink = message.src
134 imagesink.set_property('force-aspect-ratio', True)
135 imagesink.set_window_handle(self.videowidget.get_property('window').get_xid())
136
137 def on_stream_clicked(self, widget):
138
139 labelname = self.stream_button.get_label()
140 if labelname == 'Stream':
141 self.clean_entry_fields()
142 self.pipel.stream_play()
143 ## self.pipel.get_stream_state()
144 self.stream_button.set_label('ON AIR')
145 start_time = time()
146 elif labelname == 'ON AIR':
147 self.pipel.stream_stop()
148 self.stream_button.set_label('Stream')
149 self.build_filename()
150
151 def build_filename(self):
152 """Get text in entries, check if empty and apply formatting if needed."""
153 sep = '_'
154 base = self.baseinfo_entry_label.get_text()
155 speaker = self.speakerinfo_entry.get_text()
156 speaker = sep.join(speaker.split())
157 session = self.sessioninfo_entry.get_text()
158 session = sep.join(session.split())
159 raw_filename = base + sep + speaker + sep + session
160 maxlen = 70
161 has_all_fields = False
162 while not has_all_fields:
163 if speaker and session:
164 if len(raw_filename) <= maxlen:
165 has_all_fields = True
166 else:
167 offset = len(raw_filename) - maxlen
168 raw_filename = raw_filename[:-offset]
169 has_all_fields = True
170 else:
171 pass
172 # One of the field is empty, open a dialogbox to ask for filling the field
173 self.pipel.set_filenames(raw_filename)
174
175 def clean_entry_fields(self):
176 self.speakerinfo_entry.set_text('')
177 self.sessioninfo_entry.set_text('')
178
179 ## Use threading module to refresh the time elapsed sinc the begining of the stream??
180 def time_elapsed(self, widget):
181 if self.pipel.stream_get_state() == 'PLAYING':
182 pass
183
184
185 if __name__ == "__main__":
186 Gst.init()
187 Streamgui()
188 Gtk.main()