#!/usr/bin/env python3.4
+# -*- coding: utf-8 -*-
-# This file is part of Libre-Streamer.
+# This file is part of ABYSS.
+# ABYSS Broadcast Your Streaming Successfully
#
-# Libre-Streamer is free software: you can redistribute it and/or modify
+# ABYSS is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
-# Libre-Streamer is distributed in the hope that it will be useful,
+# ABYSS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with Libre-Streamer. If not, see <http://www.gnu.org/licenses/>.
+# along with ABYSS. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (c) 2016 David Testé
from os import rename
from os import listdir
+from os import path
+from os import mkdir
from time import localtime, strftime
+import configparser
import gi
from gi.repository import Gst
from gi.repository import GstVideo
-# Pathname has to be defined
-PATHNAME = ''
-AUDIO_DEFAULT = PATHNAME + 'AUDIO_DEFAULT'
-RAWVIDEO_DEFAULT = PATHNAME + 'RAWVIDEO_DEFAULT'
-STREAM_DEFAULT = PATHNAME + 'STREAM_DEFAULT'
+DIR_NAME = 'FILES_RECORDED'
+AUDIO_DEFAULT = './' + DIR_NAME + '/' + 'AUDIO_DEFAULT'
+RAWVIDEO_DEFAULT = './' + DIR_NAME + '/' + 'RAWVIDEO_DEFAULT'
+STREAM_DEFAULT = './' + DIR_NAME + '/' + 'STREAM_DEFAULT'
BACKUP_SUFFIX = '_BACKUP'
+FAILED_SUFFIX = '_FAILED_'
+fail_counter = 1
AUDIO_BACKUP = AUDIO_DEFAULT + BACKUP_SUFFIX
RAWVIDEO_BACKUP = RAWVIDEO_DEFAULT + BACKUP_SUFFIX
STREAM_BACKUP = STREAM_DEFAULT + BACKUP_SUFFIX
ERROR = '[ERROR] '
INFO = '[INFO] '
WARN = '[WARN] '
+CONFIG = '.abyss'
+sources = {'RTSP_IP' : None,
+ 'AUDIO_INPUT' : None,}
+sinks = {'AUDIO_OUTPUT' : None,
+ 'DIR': None,
+ 'STREAM_SERVER_IP' : None,
+ 'SERVER_PORT' : None,
+ 'PASSWORD' : None,
+ 'AUDIO_MOUNT' : None,
+ 'VIDEO_MOUNT' : None,}
+
+##AUDIO_INPUT = 'alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00-CODEC.analog-stereo'
+##AUDIO_OUTPUT = 'alsa_output.pci-0000_00_1b.0.analog-stereo'
+
+config = configparser.RawConfigParser()
+if path.exists(CONFIG):
+ config.read(CONFIG)
+ try:
+ sources = {key : config.get('sources', key) for key in sources}
+ sinks = {key : config.get('sinks', key) for key in sinks}
+ except:
+ print(ERROR, gettime(), 'Failed to parse config file.')
+else:
+ print(ERROR, gettime(), '".abyss" config file doesn\'t exist.')
+
+if not path.isdir(DIR_NAME):
+ mkdir(DIR_NAME)
class New_user_pipeline():
def __init__(self, feed='main'):
+ self.rtsp_address = 'rtsp://' + sources['RTSP_IP']
self.feed = feed
-## if self.feed == 'main':
self.user_pipeline = self.create_gstreamer_pipeline()
-## elif self.feed == 'backup':
-## self.user_pipeline = self.create_gstreamer_pipeline(feed='backup')
def create_video_sources(self):
"""Create video inputs from various sources."""
self.videosrc = Gst.ElementFactory.make('rtspsrc', 'videosrc')
- self.videosrc.set_property('location', 'rtsp://192.168.48.2:554')
+ self.videosrc.set_property('location', self.rtsp_address)
self.videosrc.set_property('latency', 0)
## self.videosrc.set_property('debug', True)
if self.feed == 'backup':
elif len(devices) == 1:
return '/dev/video0'
print(ERROR, gettime(), 'No webcam device found.')
-
+
+ def find_mixingdesk_device(self):
+ """Look out for the USB mixing desk device.
+ Product used here: Behringer XENYX Q1002USB.
+ """
+ # shell cmd : 'pactl list | grep alsa_input'
+ # AUDIO_INPUT --> const used currently
+ pass
+
def create_pipeline_callbacks(self):
"""Callbacks to connect dynamically created pads."""
self.videosrc.connect('pad-added', self.on_pad_added_to_rtspsrc)
def create_audio_sources(self):
"""Create audio inputs from various sources."""
self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc')
-## self.videosrc.set_property('latency', 0)
+ self.audiosrc.set_property('device', sources['AUDIO_INPUT'])
def create_audiolevel_plugin(self):
"""Create audio level plugin to feed a vu-meter."""
def create_filesink(self):
"""Create storable output elements."""
self.disksink_rawvideo = Gst.ElementFactory.make('filesink')
- #[TO DO]: File location has to be defined
self.disksink_rawvideo.set_property('location', RAWVIDEO_DEFAULT)
self.disksink_audio = Gst.ElementFactory.make('filesink')
self.disksink_audio.set_property('location', AUDIO_DEFAULT)
self.disksink_stream = Gst.ElementFactory.make('filesink')
self.disksink_stream.set_property('location', STREAM_DEFAULT)
-
+ if self.feed == 'backup':
+ self.disksink_rawvideo.set_property('location', RAWVIDEO_BACKUP)
+ self.disksink_audio.set_property('location', AUDIO_BACKUP)
+ self.disksink_stream.set_property('location', STREAM_BACKUP)
+
def create_streamsink(self):
"""Create streamable output elements."""
# To local screen:
self.screensink = Gst.ElementFactory.make('xvimagesink', 'screensink')
self.screensink.set_property('sync', False)
+ # To local audio output (headphones):
+ self.audiosink = Gst.ElementFactory.make('pulsesink', 'audiosink')
+ self.audiosink.set_property('device', sinks['AUDIO_OUTPUT'])
+ self.audiosink.set_property('sync', False)
# To icecast server:
self.icecastsink_audio = Gst.ElementFactory.make('shout2send', 'icecastsink_audio')
self.icecastsink_audio.set_property('sync', False)
-## Configuration should be written on a file locally to keep safe private addresses
- self.icecastsink_audio.set_property('ip', 'live2.fsf.org')
- self.icecastsink_audio.set_property('port', 80)
- self.icecastsink_audio.set_property('mount', 'testaudio.ogg')
- self.icecastsink_audio.set_property('password', 'thahw3Wiez')
+ self.icecastsink_audio.set_property('ip', sinks['STREAM_SERVER_IP'])
+ self.icecastsink_audio.set_property('port', int(sinks['SERVER_PORT']))
+ self.icecastsink_audio.set_property('mount', sinks['AUDIO_MOUNT'])
+ self.icecastsink_audio.set_property('password', sinks['PASSWORD'])
self.icecastsink_stream = Gst.ElementFactory.make('shout2send', 'icecastsink_stream')
self.icecastsink_stream.set_property('sync', False)
- self.icecastsink_stream.set_property('ip', 'live2.fsf.org')
- self.icecastsink_stream.set_property('port', 80)
- self.icecastsink_stream.set_property('mount', 'teststream.webm')
- self.icecastsink_stream.set_property('password', 'thahw3Wiez')
+ self.icecastsink_stream.set_property('ip', sinks['STREAM_SERVER_IP'])
+ self.icecastsink_stream.set_property('port', int(sinks['SERVER_PORT']))
+ self.icecastsink_stream.set_property('mount', sinks['VIDEO_MOUNT'])
+ self.icecastsink_stream.set_property('password', sinks['PASSWORD'])
def create_payloader_elements(self):
pass
self.queuev_3 = Gst.ElementFactory.make('queue', 'queuev_3')
self.queuev_4 = Gst.ElementFactory.make('queue', 'queuev_4')
self.queuev_5 = Gst.ElementFactory.make('queue', 'queuev_5')
- self.queuev_6 = Gst.ElementFactory.make('queue', 'queuev_6')
# For audio feed:
self.queuea_1 = Gst.ElementFactory.make('queue', 'queuea_1')
self.queuea_2 = Gst.ElementFactory.make('queue', 'queuea_2')
# Output elements:
self.create_filesink()
self.create_streamsink()
+ if self.feed == 'test':
+ print('TEST OK...', end='')
print('created')
if self.feed == 'backup':
print (INFO,
def add_elements_to_pipeline(self):
print(INFO, gettime(), 'Pipeline creation state: adding elements... ', end='')
+ cond = self.feed != 'test'
+
# Inputs elements:
self.streampipe.add(self.audiosrc)
# Middle elements:
self.streampipe.add(self.audiolevel)
- self.streampipe.add(self.vorbisenc)
- self.streampipe.add(self.vp8enc)
- self.streampipe.add(self.mkvmux)
- self.streampipe.add(self.oggmux)
- self.streampipe.add(self.webmmux)
- self.streampipe.add(self.tee_rawaudio)
- self.streampipe.add(self.tee_rawvideo)
- self.streampipe.add(self.tee_streamaudio)
- self.streampipe.add(self.tee_streamfull)
- self.streampipe.add(self.queuev_2)
- self.streampipe.add(self.queuev_3)
- self.streampipe.add(self.queuev_4)
- self.streampipe.add(self.queuev_5)
self.streampipe.add(self.queuea_1)
- self.streampipe.add(self.queuea_2)
- self.streampipe.add(self.queuea_3)
- self.streampipe.add(self.queuea_4)
- self.streampipe.add(self.queuea_5)
- self.streampipe.add(self.queuem_1)
- self.streampipe.add(self.queuem_2)
+ self.streampipe.add(self.queuev_3)
+ if cond:
+ self.streampipe.add(self.vorbisenc)
+ self.streampipe.add(self.oggmux)
+ self.streampipe.add(self.queuea_2)
+ self.streampipe.add(self.queuea_3)
+ self.streampipe.add(self.vp8enc)
+ self.streampipe.add(self.mkvmux)
+ self.streampipe.add(self.webmmux)
+ self.streampipe.add(self.tee_rawaudio)
+ self.streampipe.add(self.tee_rawvideo)
+ self.streampipe.add(self.tee_streamaudio)
+ self.streampipe.add(self.tee_streamfull)
+ self.streampipe.add(self.queuev_2)
+ self.streampipe.add(self.queuev_4)
+ self.streampipe.add(self.queuev_5)
+ self.streampipe.add(self.queuea_4)
+ self.streampipe.add(self.queuea_5)
+ self.streampipe.add(self.queuem_1)
+ self.streampipe.add(self.queuem_2)
# Outputs elements:
self.streampipe.add(self.screensink)
- self.streampipe.add(self.disksink_rawvideo)
- self.streampipe.add(self.disksink_audio)
- self.streampipe.add(self.disksink_stream)
- self.streampipe.add(self.icecastsink_audio)
- self.streampipe.add(self.icecastsink_stream)
- if self.feed == 'main':
+ if cond:
+ self.streampipe.add(self.disksink_rawvideo)
+ self.streampipe.add(self.disksink_audio)
+ self.streampipe.add(self.disksink_stream)
+ self.streampipe.add(self.icecastsink_audio)
+ self.streampipe.add(self.icecastsink_stream)
+ else:
+ self.streampipe.add(self.audiosink)
+
+ if self.feed == 'main' or self.feed == 'test':
# Inputs elements:
self.streampipe.add(self.videosrc)
# Middle elements:
self.streampipe.add(self.capsfilter)
self.streampipe.add(self.tee_videodecoded)
self.streampipe.add(self.queuev_1)
+ if self.feed == 'test':
+ print ('TEST OK...', end='')
elif self.feed == 'backup':
# Inputs elements:
self.streampipe.add(self.videosrc_backup)
def link_pipeline_elements(self):
"""Link all elements with static pads."""
print(INFO, gettime(), 'Pipeline creation state: linking elements... ', end='')
+ cond = self.feed != 'test'
+
# Audio feed:
self.audiosrc.link(self.audiolevel)
self.audiolevel.link(self.queuea_1)
- self.queuea_1.link(self.vorbisenc)
- self.connect_tee(self.tee_rawaudio,
- self.vorbisenc,
- self.queuea_2,
- self.queuea_5,)
- self.queuea_2.link(self.oggmux)
- self.connect_tee(self.tee_streamaudio,
- self.oggmux,
- self.queuea_3,
- self.queuea_4,)
- self.queuea_3.link(self.disksink_audio)
- self.queuea_4.link(self.icecastsink_audio)
- self.queuea_5.link(self.webmmux)
+ if cond:
+ self.queuea_1.link(self.vorbisenc)
+ self.connect_tee(self.tee_rawaudio,
+ self.vorbisenc,
+ self.queuea_2,
+ self.queuea_5,)
+ self.queuea_2.link(self.oggmux)
+ self.connect_tee(self.tee_streamaudio,
+ self.oggmux,
+ self.queuea_3,
+ self.queuea_4,)
+ self.queuea_3.link(self.disksink_audio)
+ self.queuea_4.link(self.icecastsink_audio)
+ self.queuea_5.link(self.webmmux)
+ else:
+ self.queuea_1.link(self.audiosink)
+
# Video feed:
- self.queuev_2.link(self.mkvmux)
- self.mkvmux.link(self.queuev_4)
- self.queuev_4.link(self.disksink_rawvideo)
+ if cond:
+ self.queuev_2.link(self.mkvmux)
+ self.mkvmux.link(self.queuev_4)
+ self.queuev_4.link(self.disksink_rawvideo)
+ else:
+ self.queuev_1.link(self.rtpjpegdepay)
+ self.rtpjpegdepay.link(self.jpegdec)
+ self.jpegdec.link(self.queuev_3)
self.queuev_3.link(self.screensink)
+
# Stream (audio+video) feed:
- self.vp8enc.link(self.queuev_5)
- self.queuev_5.link(self.webmmux)
- self.connect_tee(self.tee_streamfull,
- self.webmmux,
- self.queuem_1,
- self.queuem_2,)
- self.queuem_1.link(self.disksink_stream)
- self.queuem_2.link(self.icecastsink_stream)
- if self.feed == 'main':
- # linking here RTSP feed
- self.queuev_1.link(self.rtpjpegdepay)
- self.connect_tee(self.tee_rawvideo,
- self.rtpjpegdepay,
- self.queuev_2,
- self.jpegdec,)
- self.connect_tee(self.tee_videodecoded,
- self.jpegdec,
- self.queuev_3,
- self.scaling,)
- # Stream (video) feed:
- self.scaling.link(self.capsfilter)
- self.capsfilter.link(self.vp8enc)
-
- elif self.feed == 'backup':
- # linking here backup feed (WEBCAM)
- self.videosrc_backup.link(self.capsfilter_backup)
- self.connect_tee(self.tee_rawvideo,
- self.capsfilter_backup,
- self.queuev_2,
- self.queuev_3,
- output_element_3=self.vp8enc)
+ if cond:
+ self.vp8enc.link(self.queuev_5)
+ self.queuev_5.link(self.webmmux)
+ self.connect_tee(self.tee_streamfull,
+ self.webmmux,
+ self.queuem_1,
+ self.queuem_2,)
+ self.queuem_1.link(self.disksink_stream)
+ self.queuem_2.link(self.icecastsink_stream)
+ if self.feed == 'main':
+ # linking here RTSP feed
+ self.queuev_1.link(self.rtpjpegdepay)
+ self.connect_tee(self.tee_rawvideo,
+ self.rtpjpegdepay,
+ self.queuev_2,
+ self.jpegdec,)
+ self.connect_tee(self.tee_videodecoded,
+ self.jpegdec,
+ self.queuev_3,
+ self.scaling,)
+ # Stream (video) feed:
+ self.scaling.link(self.capsfilter)
+ self.capsfilter.link(self.vp8enc)
+ elif self.feed == 'backup':
+ # linking here backup feed (WEBCAM)
+ self.videosrc_backup.link(self.capsfilter_backup)
+ self.connect_tee(self.tee_rawvideo,
+ self.capsfilter_backup,
+ self.queuev_2,
+ self.queuev_3,
+ output_element_3=self.vp8enc)
## self.capsfilter_backup.link(self.queuev_3)
- # Stream (video) feed:
- print('BACKUP OK...', end='')
+ print('BACKUP OK...', end='')
+ if not cond:
+ print('TEST OK...', end='')
print('linked')
def create_gstreamer_pipeline(self):
# Setting-up:
self.add_elements_to_pipeline()
self.link_pipeline_elements()
- if self.feed == 'main':
+ if self.feed == 'main' or self.feed == 'test':
self.create_pipeline_callbacks()
global bus
return self.streampipe
def on_message(self, bus, message):
- #
-## print("[MESSAGE]", message.get_structure().get_name()) # [DEBUG]
- #
t = message.type
if t == Gst.MessageType.EOS:
self.streampipe.set_state(Gst.State.NULL)
elif t == Gst.MessageType.ERROR:
err, debug = message.parse_error()
print (ERROR, '%s' % err, debug)
-# self.streampipe.set_state(Gst.State.NULL)
def stream_play(self):
self.streampipe.set_state(Gst.State.PLAYING)
if self.feed == 'backup':
print(WARN, gettime(), 'Backup pipeline started.')
- print(INFO, gettime(), 'PLAYING State resquested')
+ print(INFO, gettime(), 'PLAYING State resquested.')
def stream_stop(self):
self.streampipe.set_state(Gst.State.NULL)
- print(INFO, gettime(), 'STOPPED State resquested')
+ print(INFO, gettime(), 'STOPPED State resquested.')
- def get_stream_state(self):
- print(self.streampipe.get_state(self))
-##[FIXME] return self.streampipe.get_state()
-
- def set_filenames(self, string):
+ def set_filenames(self, string, streamfailed=False):
"""Sets filename and location for each sink."""
+ global fail_counter
filename = string
- audio = PATHNAME + filename + '_AUDIO'
- rawvideo = PATHNAME + filename + '_RAWVIDEO'
- stream = PATHNAME + filename + '_STREAM'
+ audio = './' + DIR_NAME + '/' + filename + '_AUDIO'
+ rawvideo = './' + DIR_NAME + '/' + filename + '_RAWVIDEO'
+ stream = './' + DIR_NAME + '/' + filename + '_STREAM'
if self.feed == 'main':
- rename(AUDIO_DEFAULT, audio)
- rename(RAWVIDEO_DEFAULT, rawvideo)
- rename(STREAM_DEFAULT, stream)
+ if streamfailed and filename:
+ audio = audio + FAILED_SUFFIX + str(fail_counter)
+ rawvideo = rawvideo + FAILED_SUFFIX + str(fail_counter)
+ stream = stream + FAILED_SUFFIX + str(fail_counter)
+ self.rename_files(audio, rawvideo, stream)
+ fail_counter += 1
+ elif streamfailed:
+ audio = AUDIO_DEFAULT + FAILED_SUFFIX + str(fail_counter)
+ rawvideo = RAWVIDEO_DEFAULT + FAILED_SUFFIX + str(fail_counter)
+ stream = STREAM_DEFAULT + FAILED_SUFFIX + str(fail_counter)
+ self.rename_files(audio, rawvideo, stream)
+ fail_counter += 1
+ else:
+ self.rename_files(audio, rawvideo, stream)
elif self.feed == 'backup':
+## print('INSIDE BACKUP RENAMING')
rename(AUDIO_BACKUP, audio)
rename(RAWVIDEO_BACKUP, rawvideo)
rename(STREAM_BACKUP, stream)
+ print(INFO, gettime(), 'Audio file written on disk.')
+ print(INFO, gettime(), 'Raw video file written on disk.')
+ print(INFO, gettime(), 'Streamed file written on disk.')
+
+ def rename_files(self, audio_name, rawvideo_name, stream_name):
+ rename(AUDIO_DEFAULT, audio_name)
+ rename(RAWVIDEO_DEFAULT, rawvideo_name)
+ rename(STREAM_DEFAULT, stream_name)
+
def get_gstreamer_bus():
return bus