Adding webcam feed pipeline (has to be implemented in gstconf.py)
[libre-streamer.git] / stream_2016 / gstconf.py
CommitLineData
669383aa
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
340ab727
DT
20from os import rename
21
669383aa
DT
22import gi
23from gi.repository import Gst
24from gi.repository import GstVideo
25
340ab727
DT
26# Pathname has to be defined
27PATHNAME = ''
28AUDIO_DEFAULT = PATHNAME + 'AUDIO_DEFAULT'
29RAWVIDEO_DEFAULT = PATHNAME + 'RAWVIDEO_DEFAULT'
30STREAM_DEFAULT = PATHNAME + 'STREAM_DEFAULT'
31
32
669383aa 33class New_user_pipeline():
340ab727 34
669383aa
DT
35
36 def __init__(self):
37 self.user_pipeline = self.create_gstreamer_pipeline()
38
39 def create_video_sources(self):
40 """Create video inputs from various sources."""
41 self.videosrc = Gst.ElementFactory.make('rtspsrc', 'videosrc')
42 self.videosrc.set_property('location', 'rtsp://192.168.48.2:554')
43 self.videosrc.set_property('latency', 0)
44
45 def create_audio_sources(self):
46 """Create audio inputs from various sources."""
47 self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc')
48## self.videosrc.set_property('latency', 0)
49
50 def create_pipeline_callbacks(self):
51 """Callbacks to connect dynamically created pads."""
52 self.videosrc.connect("pad-added", self.on_pad_added_to_rtspsrc)
53
54 def on_pad_added_to_rtspsrc(self, rtspsrc, pad):
55 """Connect the dynamic 'src'pad of an RTSP source."""
56 sinkpad = self.queuev_1.get_static_pad('sink')
57 pad.link(sinkpad)
58
59 def create_filesink(self):
60 """Create storable output elements."""
61 self.disksink_rawvideo = Gst.ElementFactory.make('filesink')
62 #[TO DO]: File location has to be defined
340ab727 63 self.disksink_rawvideo.set_property('location', RAWVIDEO_DEFAULT)
669383aa 64 self.disksink_audio = Gst.ElementFactory.make('filesink')
340ab727 65 self.disksink_audio.set_property('location', AUDIO_DEFAULT)
669383aa 66 self.disksink_stream = Gst.ElementFactory.make('filesink')
340ab727 67 self.disksink_stream.set_property('location', STREAM_DEFAULT)
669383aa
DT
68
69 def create_streamsink(self):
70 """Create streamable output elements."""
71 # To local screen:
72 self.screensink = Gst.ElementFactory.make('xvimagesink', 'screensink')
73 # To icecast server:
74 self.icecastsink_audio = Gst.ElementFactory.make('shout2send', 'icecastsink_audio')
75## Configuration should be written on a file locally to keep safe private addresses
76 self.icecastsink_audio.set_property('ip', 'live2.fsf.org')
77 self.icecastsink_audio.set_property('port', 80)
78 self.icecastsink_audio.set_property('mount', 'testaudio.ogv')
79 self.icecastsink_audio.set_property('password', 'thahw3Wiez')
80 self.icecastsink_stream = Gst.ElementFactory.make('shout2send', 'icecastsink_stream')
81 self.icecastsink_stream.set_property('ip', 'live2.fsf.org')
82 self.icecastsink_stream.set_property('port', 80)
83 self.icecastsink_stream.set_property('mount', 'teststream.ogv')
84 self.icecastsink_stream.set_property('password', 'thahw3Wiez')
85
86 def create_payloader_elements(self):
87 pass
88
89 def create_depayloader_elements(self):
90 self.rtpjpegdepay = Gst.ElementFactory.make('rtpjpegdepay', 'rtpjpegdepay')
91
92 def create_encoder_elements(self):
93 # Audio encoders:
94 self.vorbisenc = Gst.ElementFactory.make('vorbisenc', 'vorbisenc')
95 # Video encoders:
96 self.vp8enc = Gst.ElementFactory.make('vp8enc', 'vp8enc')
97 self.vp8enc.set_property('min_quantizer', 1)
98 self.vp8enc.set_property('max_quantizer', 13)
99 self.vp8enc.set_property('cpu-used', 5)
100 self.vp8enc.set_property('deadline', 42000)
101 self.vp8enc.set_property('threads', 2)
102 self.vp8enc.set_property('sharpness', 7)
103
104 def create_decoder_elements(self):
105 self.jpegdec = Gst.ElementFactory.make('jpegdec', 'jpegdec')
106 self.jpegdec.set_property('max-errors', -1)
107
108 def create_muxer_elements(self):
109 self.oggmux = Gst.ElementFactory.make('oggmux', 'oggmux')
110 self.mkvmux = Gst.ElementFactory.make('matroskamux', 'mkvmux')
111 self.webmmux = Gst.ElementFactory.make('webmmux', 'webmmux')
112 self.webmmux.set_property('streamable', True)
113
114 def create_demuxer_elements(self):
115 pass
116
117 def create_filtering_elements(self):
118 self.scaling = Gst.ElementFactory.make('videoscale', 'scaling')
119 caps = Gst.caps_from_string('video/x-raw, width=(int)640, height=(int)360')
120 self.capsfilter = Gst.ElementFactory.make('capsfilter', 'capsfilter')
121 self.capsfilter.set_property('caps', caps)
122
123 def create_tee_elements(self):
124 """Create tee elements to divide feeds."""
125 self.tee_rawvideo = Gst.ElementFactory.make('tee', 'tee_rawvideo')
126 self.tee_videodecoded = Gst.ElementFactory.make('tee', 'tee_videodecoded')
127 self.tee_streamfull = Gst.ElementFactory.make('tee', 'tee_streamfull')
128 self.tee_rawaudio = Gst.ElementFactory.make('tee', 'tee_rawaudio')
129 self.tee_streamaudio = Gst.ElementFactory.make('tee', 'tee_streamaudio')
130
131 def connect_tee(self,
132 tee_element,
133 input_element,
134 output_element_1,
135 output_element_2,):
136 """Links input and outputs of a given tee element."""
137 # Find a way to check if the element given are in the pipeline
138 # then pass the result to the 'if' statement.
139 ## argcheck = [True for arg in locals() if arg in 'the_list_of_elements_added']
140 ## print('[DEBUG] ArgList check: ', argcheck)
141 ## if False not in argcheck
142 if True:
143 input_element.link(tee_element)
144 tee_element.link(output_element_1)
145 tee_element.link(output_element_2)
146 else:
147 print('[ERROR] Couldn\'t link the tee. Element(s) probably not in the pipeline ')
148
149 def create_queues(self):
150 # For video feed:
151 self.queuev_1 = Gst.ElementFactory.make('queue', 'queuev_1')
152 self.queuev_2 = Gst.ElementFactory.make('queue', 'queuev_2')
153 self.queuev_3 = Gst.ElementFactory.make('queue', 'queuev_3')
154 self.queuev_4 = Gst.ElementFactory.make('queue', 'queuev_4')
155 self.queuev_5 = Gst.ElementFactory.make('queue', 'queuev_5')
156 self.queuev_6 = Gst.ElementFactory.make('queue', 'queuev_6')
157 # For audio feed:
158 self.queuea_1 = Gst.ElementFactory.make('queue', 'queuea_1')
159 self.queuea_2 = Gst.ElementFactory.make('queue', 'queuea_2')
160 self.queuea_3 = Gst.ElementFactory.make('queue', 'queuea_3')
161 self.queuea_4 = Gst.ElementFactory.make('queue', 'queuea_4')
162 self.queuea_5 = Gst.ElementFactory.make('queue', 'queuea_5')
163 # For audio+video muxer:
164 self.queuem_1 = Gst.ElementFactory.make('queue', 'queuem_1')
165 self.queuem_2 = Gst.ElementFactory.make('queue', 'queuem_2')
166
167 def create_pipeline_elements(self):
168 print('Pipeline creation state: creating elements... ', end='')
169 # Inputs elements:
170 self.create_video_sources()
171 self.create_audio_sources()
172 # Middle elements:
173 self.create_payloader_elements()
174 self.create_depayloader_elements()
175 self.create_encoder_elements()
176 self.create_decoder_elements()
177 self.create_muxer_elements()
178 self.create_filtering_elements()
179 self.create_tee_elements()
180 self.create_queues()
181 # Output elements:
182 self.create_filesink()
183 self.create_streamsink()
184 print('created')
185
186
187 def add_elements_to_pipeline(self):
188 print('Pipeline creation state: adding elements... ', end='')
189 # Inputs elements:
190 self.streampipe.add(self.videosrc)
191 self.streampipe.add(self.audiosrc)
192 # Middle elements:
193 self.streampipe.add(self.rtpjpegdepay)
194 self.streampipe.add(self.jpegdec)
195 self.streampipe.add(self.tee_rawvideo)
196 self.streampipe.add(self.mkvmux)
197 self.streampipe.add(self.vorbisenc)
198 self.streampipe.add(self.oggmux)
199 self.streampipe.add(self.scaling)
200 self.streampipe.add(self.capsfilter)
201 self.streampipe.add(self.vp8enc)
202 self.streampipe.add(self.webmmux)
203 self.streampipe.add(self.tee_rawaudio)
204 self.streampipe.add(self.tee_streamaudio)
205 self.streampipe.add(self.tee_videodecoded)
206 self.streampipe.add(self.tee_streamfull)
207 self.streampipe.add(self.queuev_1)
208 self.streampipe.add(self.queuev_2)
209 self.streampipe.add(self.queuev_3)
210 self.streampipe.add(self.queuev_4)
211 self.streampipe.add(self.queuev_5)
212 self.streampipe.add(self.queuev_6)
213 self.streampipe.add(self.queuea_1)
214 self.streampipe.add(self.queuea_2)
215 self.streampipe.add(self.queuea_3)
216 self.streampipe.add(self.queuea_4)
217 self.streampipe.add(self.queuea_5)
218 self.streampipe.add(self.queuem_1)
219 self.streampipe.add(self.queuem_2)
220 # Outputs elements:
221 self.streampipe.add(self.screensink)
222 self.streampipe.add(self.disksink_rawvideo)
223 self.streampipe.add(self.disksink_audio)
224 self.streampipe.add(self.disksink_stream)
225 self.streampipe.add(self.icecastsink_audio)
226 self.streampipe.add(self.icecastsink_stream)
227 print('added')
228
229 def link_pipeline_elements(self):
230 """Link all elements with static pads."""
231 print('Pipeline creation state: linking elements... ', end='')
232 # Video feed:
233 self.queuev_1.link(self.rtpjpegdepay)
234 self.connect_tee(self.tee_rawvideo,
235 self.rtpjpegdepay,
236 self.queuev_2,
237 self.jpegdec,)
238 self.queuev_2.link(self.mkvmux)
239 self.mkvmux.link(self.queuev_4)
240 self.queuev_4.link(self.disksink_rawvideo)
241 self.connect_tee(self.tee_videodecoded,
242 self.jpegdec,
243 self.queuev_3,
244 self.scaling,)
245 self.queuev_3.link(self.screensink)
246 # Audio feed:
247 self.audiosrc.link(self.queuea_1)
248 self.queuea_1.link(self.vorbisenc)
249 self.connect_tee(self.tee_rawaudio,
250 self.vorbisenc,
251 self.queuea_2,
252 self.queuea_5,)
253 self.queuea_2.link(self.oggmux)
254 self.connect_tee(self.tee_streamaudio,
255 self.oggmux,
256 self.queuea_3,
257 self.queuea_4,)
258 self.queuea_3.link(self.disksink_audio)
259 self.queuea_4.link(self.icecastsink_audio)
260 self.queuea_5.link(self.webmmux)
261 # Stream (audio+video) feed:
262 self.scaling.link(self.capsfilter)
263 self.capsfilter.link(self.vp8enc)
264 self.vp8enc.link(self.queuev_6)
265 self.queuev_6.link(self.webmmux)
266 self.connect_tee(self.tee_streamfull,
267 self.webmmux,
268 self.queuem_1,
269 self.queuem_2,)
270 self.queuem_1.link(self.disksink_stream)
271 self.queuem_2.link(self.icecastsink_stream)
272 print('linked')
273
274 def create_gstreamer_pipeline(self):
275 # New empty pipeline:
276 self.streampipe = Gst.Pipeline()
277 # Setting-up:
278 self.create_pipeline_elements()
279 self.add_elements_to_pipeline()
280 self.link_pipeline_elements()
281 self.create_pipeline_callbacks()
282
283 global bus
284 bus = self.streampipe.get_bus()
285 bus.add_signal_watch()
286 bus.enable_sync_message_emission()
287 # Used to get messages that GStreamer emits.
288 bus.connect("message", self.on_message)
289
290 print('Pipeline creation state: successfully done.')
291 return self.streampipe
292
293 def on_message(self, bus, message):
294 t = message.type
295 if t == Gst.MessageType.EOS:
296 self.pipeol.set_state(Gst.State.NULL)
297 self.stream_button.set_label('Stream')
298 elif t == Gst.MessageType.ERROR:
299 err, debug = message.parse_error()
300 print ("Error: %s" % err, debug)
301 self.pipel.set_state(Gst.State.NULL)
302 self.stream_button.set_label('Stream')
303
304 def stream_play(self):
305 self.streampipe.set_state(Gst.State.PLAYING)
306
307 def stream_stop(self):
308 self.streampipe.set_state(Gst.State.NULL)
309
310 def get_stream_state(self):
311 print(self.streampipe.get_state(self))
da450d89 312##[FIXME] return self.streampipe.get_state()
340ab727
DT
313
314 def set_filenames(self, string):
315 """Sets filename and location for each sink."""
316 filename = string
317 audio = PATHNAME + filename + '_AUDIO'
318 rawvideo = PATHNAME + filename + '_RAWVIDEO'
319 stream = PATHNAME + filename + '_STREAM'
320 rename(AUDIO_DEFAULT, audio)
321 rename(RAWVIDEO_DEFAULT, rawvideo)
322 rename(STREAM_DEFAULT, stream)
669383aa
DT
323
324def get_gstreamer_bus():
325 return bus
340ab727 326