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