Commit | Line | Data |
---|---|---|
669383aa | 1 | #!/usr/bin/env python3.4 |
dfee4fc3 | 2 | # -*- coding: utf-8 -*- |
669383aa | 3 | |
332e58df | 4 | # This file is part of ABYSS. |
dfee4fc3 | 5 | # ABYSS Broadcast Your Streaming Successfully |
669383aa | 6 | # |
332e58df | 7 | # ABYSS is free software: you can redistribute it and/or modify |
669383aa DT |
8 | # it under the terms of the GNU General Public License as published by |
9 | # the Free Software Foundation, either version 3 of the License, or | |
10 | # (at your option) any later version. | |
11 | # | |
332e58df | 12 | # ABYSS is distributed in the hope that it will be useful, |
669383aa DT |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | # GNU General Public License for more details. | |
16 | # | |
17 | # You should have received a copy of the GNU General Public License | |
332e58df | 18 | # along with ABYSS. If not, see <http://www.gnu.org/licenses/>. |
669383aa DT |
19 | # |
20 | # Copyright (c) 2016 David Testé | |
21 | ||
340ab727 | 22 | from os import rename |
e84c1bd7 | 23 | from os import listdir |
969dd837 | 24 | from os import path |
6bb57e06 | 25 | from os import mkdir |
ba4fea24 | 26 | from time import localtime, strftime |
969dd837 | 27 | import configparser |
340ab727 | 28 | |
669383aa DT |
29 | import gi |
30 | from gi.repository import Gst | |
31 | from gi.repository import GstVideo | |
32 | ||
6bb57e06 DT |
33 | DIR_NAME = 'FILES_RECORDED' |
34 | AUDIO_DEFAULT = './' + DIR_NAME + '/' + 'AUDIO_DEFAULT' | |
35 | RAWVIDEO_DEFAULT = './' + DIR_NAME + '/' + 'RAWVIDEO_DEFAULT' | |
36 | STREAM_DEFAULT = './' + DIR_NAME + '/' + 'STREAM_DEFAULT' | |
ba4fea24 | 37 | BACKUP_SUFFIX = '_BACKUP' |
3d4734cb DT |
38 | FAILED_SUFFIX = '_FAILED_' |
39 | fail_counter = 1 | |
ba4fea24 DT |
40 | AUDIO_BACKUP = AUDIO_DEFAULT + BACKUP_SUFFIX |
41 | RAWVIDEO_BACKUP = RAWVIDEO_DEFAULT + BACKUP_SUFFIX | |
42 | STREAM_BACKUP = STREAM_DEFAULT + BACKUP_SUFFIX | |
43 | ERROR = '[ERROR] ' | |
44 | INFO = '[INFO] ' | |
45 | WARN = '[WARN] ' | |
969dd837 | 46 | CONFIG = '.abyss' |
340ab727 | 47 | |
969dd837 DT |
48 | sources = {'RTSP_IP' : None, |
49 | 'AUDIO_INPUT' : None,} | |
50 | sinks = {'AUDIO_OUTPUT' : None, | |
51 | 'DIR': None, | |
52 | 'STREAM_SERVER_IP' : None, | |
53 | 'SERVER_PORT' : None, | |
54 | 'PASSWORD' : None, | |
55 | 'AUDIO_MOUNT' : None, | |
56 | 'VIDEO_MOUNT' : None,} | |
57 | ||
58 | ##AUDIO_INPUT = 'alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00-CODEC.analog-stereo' | |
59 | ##AUDIO_OUTPUT = 'alsa_output.pci-0000_00_1b.0.analog-stereo' | |
60 | ||
61 | config = configparser.RawConfigParser() | |
62 | if path.exists(CONFIG): | |
63 | config.read(CONFIG) | |
64 | try: | |
65 | sources = {key : config.get('sources', key) for key in sources} | |
66 | sinks = {key : config.get('sinks', key) for key in sinks} | |
67 | except: | |
68 | print(ERROR, gettime(), 'Failed to parse config file.') | |
69 | else: | |
70 | print(ERROR, gettime(), '".abyss" config file doesn\'t exist.') | |
4f6dadd2 | 71 | |
6bb57e06 DT |
72 | if not path.isdir(DIR_NAME): |
73 | mkdir(DIR_NAME) | |
340ab727 | 74 | |
669383aa | 75 | class New_user_pipeline(): |
340ab727 | 76 | |
669383aa | 77 | |
969dd837 DT |
78 | def __init__(self, feed='main'): |
79 | self.rtsp_address = 'rtsp://' + sources['RTSP_IP'] | |
e84c1bd7 | 80 | self.feed = feed |
ba4fea24 | 81 | self.user_pipeline = self.create_gstreamer_pipeline() |
e84c1bd7 | 82 | |
669383aa DT |
83 | def create_video_sources(self): |
84 | """Create video inputs from various sources.""" | |
85 | self.videosrc = Gst.ElementFactory.make('rtspsrc', 'videosrc') | |
dfee4fc3 | 86 | self.videosrc.set_property('location', self.rtsp_address) |
669383aa | 87 | self.videosrc.set_property('latency', 0) |
ba4fea24 | 88 | ## self.videosrc.set_property('debug', True) |
e84c1bd7 DT |
89 | if self.feed == 'backup': |
90 | self.videosrc_backup = Gst.ElementFactory.make('v4l2src', | |
91 | 'videosrc_backup') | |
92 | device_location = self.find_webcam_device() | |
e84c1bd7 DT |
93 | self.videosrc_backup.set_property('device', device_location) |
94 | ||
95 | def find_webcam_device(self): | |
96 | """Look out for the USB webcam device.""" | |
97 | devices = [dev for dev in listdir('/dev/') if 'video' in dev] | |
98 | for item in devices: | |
99 | # In case of computer having a built-in webcam | |
100 | if item != 'video0' and len(devices) > 1: | |
101 | return '/dev/' + item | |
102 | # Without built-in webcam | |
103 | elif len(devices) == 1: | |
104 | return '/dev/video0' | |
ba4fea24 | 105 | print(ERROR, gettime(), 'No webcam device found.') |
4f6dadd2 DT |
106 | |
107 | def find_mixingdesk_device(self): | |
108 | """Look out for the USB mixing desk device. | |
109 | Product used here: Behringer XENYX Q1002USB. | |
110 | """ | |
111 | # shell cmd : 'pactl list | grep alsa_input' | |
112 | # AUDIO_INPUT --> const used currently | |
113 | pass | |
114 | ||
669383aa DT |
115 | def create_pipeline_callbacks(self): |
116 | """Callbacks to connect dynamically created pads.""" | |
e84c1bd7 | 117 | self.videosrc.connect('pad-added', self.on_pad_added_to_rtspsrc) |
669383aa DT |
118 | |
119 | def on_pad_added_to_rtspsrc(self, rtspsrc, pad): | |
120 | """Connect the dynamic 'src'pad of an RTSP source.""" | |
121 | sinkpad = self.queuev_1.get_static_pad('sink') | |
122 | pad.link(sinkpad) | |
123 | ||
e84c1bd7 DT |
124 | def create_audio_sources(self): |
125 | """Create audio inputs from various sources.""" | |
126 | self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc') | |
969dd837 | 127 | self.audiosrc.set_property('device', sources['AUDIO_INPUT']) |
e84c1bd7 | 128 | |
6db3115f DT |
129 | def create_audiolevel_plugin(self): |
130 | """Create audio level plugin to feed a vu-meter.""" | |
131 | self.audiolevel = Gst.ElementFactory.make('level', 'audiolevel') | |
132 | self.audiolevel.set_property('interval', 200000000) | |
133 | ||
669383aa DT |
134 | def create_filesink(self): |
135 | """Create storable output elements.""" | |
136 | self.disksink_rawvideo = Gst.ElementFactory.make('filesink') | |
340ab727 | 137 | self.disksink_rawvideo.set_property('location', RAWVIDEO_DEFAULT) |
669383aa | 138 | self.disksink_audio = Gst.ElementFactory.make('filesink') |
340ab727 | 139 | self.disksink_audio.set_property('location', AUDIO_DEFAULT) |
669383aa | 140 | self.disksink_stream = Gst.ElementFactory.make('filesink') |
340ab727 | 141 | self.disksink_stream.set_property('location', STREAM_DEFAULT) |
3d4734cb DT |
142 | if self.feed == 'backup': |
143 | self.disksink_rawvideo.set_property('location', RAWVIDEO_BACKUP) | |
144 | self.disksink_audio.set_property('location', AUDIO_BACKUP) | |
145 | self.disksink_stream.set_property('location', STREAM_BACKUP) | |
146 | ||
669383aa DT |
147 | def create_streamsink(self): |
148 | """Create streamable output elements.""" | |
149 | # To local screen: | |
150 | self.screensink = Gst.ElementFactory.make('xvimagesink', 'screensink') | |
e84c1bd7 | 151 | self.screensink.set_property('sync', False) |
dfee4fc3 DT |
152 | # To local audio output (headphones): |
153 | self.audiosink = Gst.ElementFactory.make('pulsesink', 'audiosink') | |
969dd837 | 154 | self.audiosink.set_property('device', sinks['AUDIO_OUTPUT']) |
dfee4fc3 | 155 | self.audiosink.set_property('sync', False) |
669383aa DT |
156 | # To icecast server: |
157 | self.icecastsink_audio = Gst.ElementFactory.make('shout2send', 'icecastsink_audio') | |
ba4fea24 | 158 | self.icecastsink_audio.set_property('sync', False) |
6bb57e06 | 159 | self.icecastsink_audio.set_property('ip', sinks['STREAM_SERVER_IP']) |
969dd837 | 160 | self.icecastsink_audio.set_property('port', int(sinks['SERVER_PORT'])) |
6bb57e06 DT |
161 | self.icecastsink_audio.set_property('mount', sinks['AUDIO_MOUNT']) |
162 | self.icecastsink_audio.set_property('password', sinks['PASSWORD']) | |
669383aa | 163 | self.icecastsink_stream = Gst.ElementFactory.make('shout2send', 'icecastsink_stream') |
ba4fea24 | 164 | self.icecastsink_stream.set_property('sync', False) |
6bb57e06 DT |
165 | self.icecastsink_stream.set_property('ip', sinks['STREAM_SERVER_IP']) |
166 | self.icecastsink_stream.set_property('port', int(sinks['SERVER_PORT'])) | |
167 | self.icecastsink_stream.set_property('mount', sinks['VIDEO_MOUNT']) | |
168 | self.icecastsink_stream.set_property('password', sinks['PASSWORD']) | |
669383aa DT |
169 | |
170 | def create_payloader_elements(self): | |
171 | pass | |
172 | ||
173 | def create_depayloader_elements(self): | |
174 | self.rtpjpegdepay = Gst.ElementFactory.make('rtpjpegdepay', 'rtpjpegdepay') | |
175 | ||
176 | def create_encoder_elements(self): | |
177 | # Audio encoders: | |
178 | self.vorbisenc = Gst.ElementFactory.make('vorbisenc', 'vorbisenc') | |
179 | # Video encoders: | |
180 | self.vp8enc = Gst.ElementFactory.make('vp8enc', 'vp8enc') | |
181 | self.vp8enc.set_property('min_quantizer', 1) | |
182 | self.vp8enc.set_property('max_quantizer', 13) | |
183 | self.vp8enc.set_property('cpu-used', 5) | |
b5da55eb | 184 | self.vp8enc.set_property('deadline', 1) |
669383aa DT |
185 | self.vp8enc.set_property('threads', 2) |
186 | self.vp8enc.set_property('sharpness', 7) | |
a7be5692 | 187 | self.vp8enc.set_property('keyframe-max-dist', 25) |
1009e9f3 | 188 | self.vp8enc.set_property('target-bitrate', 800000) |
61903927 | 189 | |
669383aa DT |
190 | def create_decoder_elements(self): |
191 | self.jpegdec = Gst.ElementFactory.make('jpegdec', 'jpegdec') | |
192 | self.jpegdec.set_property('max-errors', -1) | |
193 | ||
194 | def create_muxer_elements(self): | |
195 | self.oggmux = Gst.ElementFactory.make('oggmux', 'oggmux') | |
196 | self.mkvmux = Gst.ElementFactory.make('matroskamux', 'mkvmux') | |
197 | self.webmmux = Gst.ElementFactory.make('webmmux', 'webmmux') | |
198 | self.webmmux.set_property('streamable', True) | |
199 | ||
200 | def create_demuxer_elements(self): | |
201 | pass | |
202 | ||
203 | def create_filtering_elements(self): | |
204 | self.scaling = Gst.ElementFactory.make('videoscale', 'scaling') | |
b5da55eb DT |
205 | caps = Gst.caps_from_string( |
206 | 'video/x-raw, width=(int)640, height=(int)360, framerate=(float)25/1') | |
669383aa DT |
207 | self.capsfilter = Gst.ElementFactory.make('capsfilter', 'capsfilter') |
208 | self.capsfilter.set_property('caps', caps) | |
e84c1bd7 DT |
209 | |
210 | caps_backup = Gst.caps_from_string('video/x-raw, width=(int)640, height=(int)360') | |
211 | self.capsfilter_backup = Gst.ElementFactory.make('capsfilter', 'capsfilter_backup') | |
212 | self.capsfilter_backup.set_property('caps', caps_backup) | |
669383aa DT |
213 | |
214 | def create_tee_elements(self): | |
215 | """Create tee elements to divide feeds.""" | |
216 | self.tee_rawvideo = Gst.ElementFactory.make('tee', 'tee_rawvideo') | |
217 | self.tee_videodecoded = Gst.ElementFactory.make('tee', 'tee_videodecoded') | |
218 | self.tee_streamfull = Gst.ElementFactory.make('tee', 'tee_streamfull') | |
219 | self.tee_rawaudio = Gst.ElementFactory.make('tee', 'tee_rawaudio') | |
220 | self.tee_streamaudio = Gst.ElementFactory.make('tee', 'tee_streamaudio') | |
221 | ||
222 | def connect_tee(self, | |
223 | tee_element, | |
224 | input_element, | |
225 | output_element_1, | |
ba4fea24 DT |
226 | output_element_2, |
227 | output_element_3=None,): | |
669383aa DT |
228 | """Links input and outputs of a given tee element.""" |
229 | # Find a way to check if the element given are in the pipeline | |
230 | # then pass the result to the 'if' statement. | |
231 | ## argcheck = [True for arg in locals() if arg in 'the_list_of_elements_added'] | |
232 | ## print('[DEBUG] ArgList check: ', argcheck) | |
233 | ## if False not in argcheck | |
234 | if True: | |
235 | input_element.link(tee_element) | |
236 | tee_element.link(output_element_1) | |
237 | tee_element.link(output_element_2) | |
ba4fea24 DT |
238 | if output_element_3: |
239 | tee_element.link(output_element_3) | |
669383aa | 240 | else: |
ba4fea24 DT |
241 | print(ERROR, |
242 | gettime(), | |
243 | 'Couldn\'t link the tee. Element(s) probably not in the pipeline ') | |
669383aa DT |
244 | |
245 | def create_queues(self): | |
246 | # For video feed: | |
247 | self.queuev_1 = Gst.ElementFactory.make('queue', 'queuev_1') | |
248 | self.queuev_2 = Gst.ElementFactory.make('queue', 'queuev_2') | |
249 | self.queuev_3 = Gst.ElementFactory.make('queue', 'queuev_3') | |
250 | self.queuev_4 = Gst.ElementFactory.make('queue', 'queuev_4') | |
251 | self.queuev_5 = Gst.ElementFactory.make('queue', 'queuev_5') | |
669383aa DT |
252 | # For audio feed: |
253 | self.queuea_1 = Gst.ElementFactory.make('queue', 'queuea_1') | |
254 | self.queuea_2 = Gst.ElementFactory.make('queue', 'queuea_2') | |
255 | self.queuea_3 = Gst.ElementFactory.make('queue', 'queuea_3') | |
256 | self.queuea_4 = Gst.ElementFactory.make('queue', 'queuea_4') | |
ba4fea24 | 257 | self.queuea_4.set_property('leaky', 2) |
669383aa DT |
258 | self.queuea_5 = Gst.ElementFactory.make('queue', 'queuea_5') |
259 | # For audio+video muxer: | |
260 | self.queuem_1 = Gst.ElementFactory.make('queue', 'queuem_1') | |
261 | self.queuem_2 = Gst.ElementFactory.make('queue', 'queuem_2') | |
ba4fea24 | 262 | self.queuem_2.set_property('leaky', 2) |
669383aa DT |
263 | |
264 | def create_pipeline_elements(self): | |
ba4fea24 | 265 | print(INFO, gettime(), 'Pipeline creation state: creating elements... ', end='') |
669383aa DT |
266 | # Inputs elements: |
267 | self.create_video_sources() | |
268 | self.create_audio_sources() | |
269 | # Middle elements: | |
6db3115f | 270 | self.create_audiolevel_plugin() |
669383aa DT |
271 | self.create_payloader_elements() |
272 | self.create_depayloader_elements() | |
273 | self.create_encoder_elements() | |
274 | self.create_decoder_elements() | |
275 | self.create_muxer_elements() | |
276 | self.create_filtering_elements() | |
277 | self.create_tee_elements() | |
278 | self.create_queues() | |
279 | # Output elements: | |
280 | self.create_filesink() | |
281 | self.create_streamsink() | |
dfee4fc3 DT |
282 | if self.feed == 'test': |
283 | print('TEST OK...', end='') | |
669383aa | 284 | print('created') |
ba4fea24 DT |
285 | if self.feed == 'backup': |
286 | print (INFO, | |
287 | gettime(), | |
288 | 'Webcam device location: ', | |
289 | self.videosrc_backup.get_property('device')) | |
669383aa DT |
290 | |
291 | ||
ba4fea24 DT |
292 | def add_elements_to_pipeline(self): |
293 | print(INFO, gettime(), 'Pipeline creation state: adding elements... ', end='') | |
dfee4fc3 DT |
294 | cond = self.feed != 'test' |
295 | ||
ba4fea24 DT |
296 | # Inputs elements: |
297 | self.streampipe.add(self.audiosrc) | |
298 | # Middle elements: | |
299 | self.streampipe.add(self.audiolevel) | |
ba4fea24 | 300 | self.streampipe.add(self.queuea_1) |
dfee4fc3 DT |
301 | self.streampipe.add(self.queuev_3) |
302 | if cond: | |
303 | self.streampipe.add(self.vorbisenc) | |
304 | self.streampipe.add(self.oggmux) | |
305 | self.streampipe.add(self.queuea_2) | |
306 | self.streampipe.add(self.queuea_3) | |
307 | self.streampipe.add(self.vp8enc) | |
308 | self.streampipe.add(self.mkvmux) | |
309 | self.streampipe.add(self.webmmux) | |
310 | self.streampipe.add(self.tee_rawaudio) | |
311 | self.streampipe.add(self.tee_rawvideo) | |
312 | self.streampipe.add(self.tee_streamaudio) | |
313 | self.streampipe.add(self.tee_streamfull) | |
314 | self.streampipe.add(self.queuev_2) | |
315 | self.streampipe.add(self.queuev_4) | |
316 | self.streampipe.add(self.queuev_5) | |
317 | self.streampipe.add(self.queuea_4) | |
318 | self.streampipe.add(self.queuea_5) | |
319 | self.streampipe.add(self.queuem_1) | |
320 | self.streampipe.add(self.queuem_2) | |
ba4fea24 DT |
321 | # Outputs elements: |
322 | self.streampipe.add(self.screensink) | |
dfee4fc3 DT |
323 | if cond: |
324 | self.streampipe.add(self.disksink_rawvideo) | |
325 | self.streampipe.add(self.disksink_audio) | |
326 | self.streampipe.add(self.disksink_stream) | |
327 | self.streampipe.add(self.icecastsink_audio) | |
328 | self.streampipe.add(self.icecastsink_stream) | |
329 | else: | |
330 | self.streampipe.add(self.audiosink) | |
331 | ||
332 | if self.feed == 'main' or self.feed == 'test': | |
e84c1bd7 DT |
333 | # Inputs elements: |
334 | self.streampipe.add(self.videosrc) | |
e84c1bd7 | 335 | # Middle elements: |
e84c1bd7 DT |
336 | self.streampipe.add(self.rtpjpegdepay) |
337 | self.streampipe.add(self.jpegdec) | |
e84c1bd7 DT |
338 | self.streampipe.add(self.scaling) |
339 | self.streampipe.add(self.capsfilter) | |
e84c1bd7 | 340 | self.streampipe.add(self.tee_videodecoded) |
e84c1bd7 | 341 | self.streampipe.add(self.queuev_1) |
dfee4fc3 DT |
342 | if self.feed == 'test': |
343 | print ('TEST OK...', end='') | |
ba4fea24 DT |
344 | elif self.feed == 'backup': |
345 | # Inputs elements: | |
e84c1bd7 | 346 | self.streampipe.add(self.videosrc_backup) |
ba4fea24 | 347 | # Middle elements: |
e84c1bd7 | 348 | self.streampipe.add(self.capsfilter_backup) |
e84c1bd7 | 349 | print ('BACKUP OK...', end='') |
669383aa DT |
350 | print('added') |
351 | ||
ba4fea24 | 352 | def link_pipeline_elements(self): |
669383aa | 353 | """Link all elements with static pads.""" |
ba4fea24 | 354 | print(INFO, gettime(), 'Pipeline creation state: linking elements... ', end='') |
dfee4fc3 DT |
355 | cond = self.feed != 'test' |
356 | ||
ba4fea24 DT |
357 | # Audio feed: |
358 | self.audiosrc.link(self.audiolevel) | |
359 | self.audiolevel.link(self.queuea_1) | |
dfee4fc3 DT |
360 | if cond: |
361 | self.queuea_1.link(self.vorbisenc) | |
362 | self.connect_tee(self.tee_rawaudio, | |
363 | self.vorbisenc, | |
364 | self.queuea_2, | |
365 | self.queuea_5,) | |
366 | self.queuea_2.link(self.oggmux) | |
367 | self.connect_tee(self.tee_streamaudio, | |
368 | self.oggmux, | |
369 | self.queuea_3, | |
370 | self.queuea_4,) | |
371 | self.queuea_3.link(self.disksink_audio) | |
372 | self.queuea_4.link(self.icecastsink_audio) | |
373 | self.queuea_5.link(self.webmmux) | |
374 | else: | |
375 | self.queuea_1.link(self.audiosink) | |
376 | ||
ba4fea24 | 377 | # Video feed: |
dfee4fc3 DT |
378 | if cond: |
379 | self.queuev_2.link(self.mkvmux) | |
380 | self.mkvmux.link(self.queuev_4) | |
381 | self.queuev_4.link(self.disksink_rawvideo) | |
382 | else: | |
383 | self.queuev_1.link(self.rtpjpegdepay) | |
384 | self.rtpjpegdepay.link(self.jpegdec) | |
385 | self.jpegdec.link(self.queuev_3) | |
ba4fea24 | 386 | self.queuev_3.link(self.screensink) |
dfee4fc3 | 387 | |
ba4fea24 | 388 | # Stream (audio+video) feed: |
dfee4fc3 DT |
389 | if cond: |
390 | self.vp8enc.link(self.queuev_5) | |
391 | self.queuev_5.link(self.webmmux) | |
392 | self.connect_tee(self.tee_streamfull, | |
393 | self.webmmux, | |
394 | self.queuem_1, | |
395 | self.queuem_2,) | |
396 | self.queuem_1.link(self.disksink_stream) | |
397 | self.queuem_2.link(self.icecastsink_stream) | |
398 | if self.feed == 'main': | |
399 | # linking here RTSP feed | |
400 | self.queuev_1.link(self.rtpjpegdepay) | |
401 | self.connect_tee(self.tee_rawvideo, | |
402 | self.rtpjpegdepay, | |
403 | self.queuev_2, | |
404 | self.jpegdec,) | |
405 | self.connect_tee(self.tee_videodecoded, | |
406 | self.jpegdec, | |
407 | self.queuev_3, | |
408 | self.scaling,) | |
409 | # Stream (video) feed: | |
410 | self.scaling.link(self.capsfilter) | |
411 | self.capsfilter.link(self.vp8enc) | |
412 | elif self.feed == 'backup': | |
413 | # linking here backup feed (WEBCAM) | |
414 | self.videosrc_backup.link(self.capsfilter_backup) | |
415 | self.connect_tee(self.tee_rawvideo, | |
416 | self.capsfilter_backup, | |
417 | self.queuev_2, | |
418 | self.queuev_3, | |
419 | output_element_3=self.vp8enc) | |
dfee4fc3 DT |
420 | print('BACKUP OK...', end='') |
421 | if not cond: | |
422 | print('TEST OK...', end='') | |
669383aa DT |
423 | print('linked') |
424 | ||
ba4fea24 | 425 | def create_gstreamer_pipeline(self): |
669383aa DT |
426 | # New empty pipeline: |
427 | self.streampipe = Gst.Pipeline() | |
669383aa | 428 | self.create_pipeline_elements() |
e84c1bd7 | 429 | # Setting-up: |
ba4fea24 DT |
430 | self.add_elements_to_pipeline() |
431 | self.link_pipeline_elements() | |
dfee4fc3 | 432 | if self.feed == 'main' or self.feed == 'test': |
e84c1bd7 | 433 | self.create_pipeline_callbacks() |
669383aa DT |
434 | |
435 | global bus | |
436 | bus = self.streampipe.get_bus() | |
437 | bus.add_signal_watch() | |
438 | bus.enable_sync_message_emission() | |
439 | # Used to get messages that GStreamer emits. | |
440 | bus.connect("message", self.on_message) | |
441 | ||
ba4fea24 | 442 | print(INFO, gettime(), 'Pipeline creation state: successfully done.') |
669383aa | 443 | return self.streampipe |
6db3115f | 444 | |
669383aa DT |
445 | def on_message(self, bus, message): |
446 | t = message.type | |
447 | if t == Gst.MessageType.EOS: | |
6db3115f | 448 | self.streampipe.set_state(Gst.State.NULL) |
669383aa DT |
449 | elif t == Gst.MessageType.ERROR: |
450 | err, debug = message.parse_error() | |
ba4fea24 | 451 | print (ERROR, '%s' % err, debug) |
e84c1bd7 | 452 | |
669383aa DT |
453 | def stream_play(self): |
454 | self.streampipe.set_state(Gst.State.PLAYING) | |
ba4fea24 DT |
455 | if self.feed == 'backup': |
456 | print(WARN, gettime(), 'Backup pipeline started.') | |
6bb57e06 | 457 | print(INFO, gettime(), 'PLAYING State resquested.') |
669383aa DT |
458 | |
459 | def stream_stop(self): | |
460 | self.streampipe.set_state(Gst.State.NULL) | |
6bb57e06 | 461 | print(INFO, gettime(), 'STOPPED State resquested.') |
ba4fea24 | 462 | |
3d4734cb | 463 | def set_filenames(self, string, streamfailed=False): |
340ab727 | 464 | """Sets filename and location for each sink.""" |
3d4734cb | 465 | global fail_counter |
340ab727 | 466 | filename = string |
6bb57e06 DT |
467 | audio = './' + DIR_NAME + '/' + filename + '_AUDIO' |
468 | rawvideo = './' + DIR_NAME + '/' + filename + '_RAWVIDEO' | |
469 | stream = './' + DIR_NAME + '/' + filename + '_STREAM' | |
ba4fea24 | 470 | if self.feed == 'main': |
3d4734cb DT |
471 | if streamfailed and filename: |
472 | audio = audio + FAILED_SUFFIX + str(fail_counter) | |
473 | rawvideo = rawvideo + FAILED_SUFFIX + str(fail_counter) | |
474 | stream = stream + FAILED_SUFFIX + str(fail_counter) | |
6bb57e06 | 475 | self.rename_files(audio, rawvideo, stream) |
3d4734cb DT |
476 | fail_counter += 1 |
477 | elif streamfailed: | |
478 | audio = AUDIO_DEFAULT + FAILED_SUFFIX + str(fail_counter) | |
479 | rawvideo = RAWVIDEO_DEFAULT + FAILED_SUFFIX + str(fail_counter) | |
480 | stream = STREAM_DEFAULT + FAILED_SUFFIX + str(fail_counter) | |
6bb57e06 | 481 | self.rename_files(audio, rawvideo, stream) |
3d4734cb DT |
482 | fail_counter += 1 |
483 | else: | |
6bb57e06 | 484 | self.rename_files(audio, rawvideo, stream) |
ba4fea24 | 485 | elif self.feed == 'backup': |
6bb57e06 | 486 | ## print('INSIDE BACKUP RENAMING') |
ba4fea24 DT |
487 | rename(AUDIO_BACKUP, audio) |
488 | rename(RAWVIDEO_BACKUP, rawvideo) | |
489 | rename(STREAM_BACKUP, stream) | |
669383aa | 490 | |
6bb57e06 DT |
491 | print(INFO, gettime(), 'Audio file written on disk.') |
492 | print(INFO, gettime(), 'Raw video file written on disk.') | |
493 | print(INFO, gettime(), 'Streamed file written on disk.') | |
494 | ||
495 | def rename_files(self, audio_name, rawvideo_name, stream_name): | |
496 | rename(AUDIO_DEFAULT, audio_name) | |
497 | rename(RAWVIDEO_DEFAULT, rawvideo_name) | |
498 | rename(STREAM_DEFAULT, stream_name) | |
3d4734cb | 499 | |
669383aa DT |
500 | def get_gstreamer_bus(): |
501 | return bus | |
ba4fea24 DT |
502 | |
503 | def gettime(): | |
504 | return strftime('%y-%m-%d_%H:%M:%S ', localtime()) |