From e84c1bd7bc5c995bc79d4dce034b9c1f4af9a87b Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20Test=C3=A9?= Date: Mon, 7 Mar 2016 17:07:26 +0100 Subject: [PATCH] Starting implementing backup pipeline.(Need to be finished) Adding auto device selection function. --- stream_2016/gstconf.py | 248 +++++++++++++++++++++++------------------ 1 file changed, 142 insertions(+), 106 deletions(-) diff --git a/stream_2016/gstconf.py b/stream_2016/gstconf.py index 2f564fa..254da74 100755 --- a/stream_2016/gstconf.py +++ b/stream_2016/gstconf.py @@ -18,6 +18,7 @@ # Copyright (c) 2016 David Testé from os import rename +from os import listdir import gi from gi.repository import Gst @@ -28,37 +29,56 @@ PATHNAME = '' AUDIO_DEFAULT = PATHNAME + 'AUDIO_DEFAULT' RAWVIDEO_DEFAULT = PATHNAME + 'RAWVIDEO_DEFAULT' STREAM_DEFAULT = PATHNAME + 'STREAM_DEFAULT' -WEBCAMUSB_DEFAULT = '/dev/video1' class New_user_pipeline(): - def __init__(self): - self.user_pipeline = self.create_gstreamer_pipeline() - + def __init__(self, feed='main'): + 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('latency', 0) -## self.videosrc = Gst.ElementFactory.make('v4l2src', 'videosrc') -## self.videosrc.set_property('device', '/dev/video1') + if self.feed == 'backup': + self.videosrc_backup = Gst.ElementFactory.make('v4l2src', + 'videosrc_backup') + device_location = self.find_webcam_device() + print ('[INFO] Webcam device location: ', device_location) + self.videosrc_backup.set_property('device', device_location) + + def find_webcam_device(self): + """Look out for the USB webcam device.""" + devices = [dev for dev in listdir('/dev/') if 'video' in dev] + for item in devices: + # In case of computer having a built-in webcam + if item != 'video0' and len(devices) > 1: + return '/dev/' + item + # Without built-in webcam + elif len(devices) == 1: + return '/dev/video0' + print('[ERROR] No webcam device found.') - def create_audio_sources(self): - """Create audio inputs from various sources.""" - self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc') -## self.videosrc.set_property('latency', 0) - def create_pipeline_callbacks(self): """Callbacks to connect dynamically created pads.""" - self.videosrc.connect("pad-added", self.on_pad_added_to_rtspsrc) + self.videosrc.connect('pad-added', self.on_pad_added_to_rtspsrc) def on_pad_added_to_rtspsrc(self, rtspsrc, pad): """Connect the dynamic 'src'pad of an RTSP source.""" sinkpad = self.queuev_1.get_static_pad('sink') pad.link(sinkpad) + def create_audio_sources(self): + """Create audio inputs from various sources.""" + self.audiosrc = Gst.ElementFactory.make('pulsesrc', 'audiosrc') +## self.videosrc.set_property('latency', 0) + def create_audiolevel_plugin(self): """Create audio level plugin to feed a vu-meter.""" self.audiolevel = Gst.ElementFactory.make('level', 'audiolevel') @@ -78,6 +98,7 @@ class New_user_pipeline(): """Create streamable output elements.""" # To local screen: self.screensink = Gst.ElementFactory.make('xvimagesink', 'screensink') + self.screensink.set_property('sync', False) # To icecast server: self.icecastsink_audio = Gst.ElementFactory.make('shout2send', 'icecastsink_audio') ## Configuration should be written on a file locally to keep safe private addresses @@ -127,6 +148,10 @@ class New_user_pipeline(): caps = Gst.caps_from_string('video/x-raw, width=(int)640, height=(int)360') self.capsfilter = Gst.ElementFactory.make('capsfilter', 'capsfilter') self.capsfilter.set_property('caps', caps) + + caps_backup = Gst.caps_from_string('video/x-raw, width=(int)640, height=(int)360') + self.capsfilter_backup = Gst.ElementFactory.make('capsfilter', 'capsfilter_backup') + self.capsfilter_backup.set_property('caps', caps_backup) def create_tee_elements(self): """Create tee elements to divide feeds.""" @@ -197,51 +222,53 @@ class New_user_pipeline(): print('Pipeline creation state: adding elements... ', end='') if feed == 'main': - pass # Add here the elments associated with the RTSP feed + # Inputs elements: + self.streampipe.add(self.videosrc) + self.streampipe.add(self.audiosrc) + # Middle elements: + self.streampipe.add(self.audiolevel) + self.streampipe.add(self.rtpjpegdepay) + self.streampipe.add(self.jpegdec) + self.streampipe.add(self.tee_rawvideo) + self.streampipe.add(self.mkvmux) + self.streampipe.add(self.vorbisenc) + self.streampipe.add(self.oggmux) + self.streampipe.add(self.scaling) + self.streampipe.add(self.capsfilter) + self.streampipe.add(self.vp8enc) + self.streampipe.add(self.webmmux) + self.streampipe.add(self.tee_rawaudio) + self.streampipe.add(self.tee_streamaudio) + self.streampipe.add(self.tee_videodecoded) + self.streampipe.add(self.tee_streamfull) + self.streampipe.add(self.queuev_1) + 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.queuev_6) + 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) + # 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) elif feed == 'backup': - pass # Add here the elments associated with the WEBCAM feed - - # Inputs elements: - self.streampipe.add(self.videosrc) - self.streampipe.add(self.audiosrc) - # Middle elements: - self.streampipe.add(self.audiolevel) - self.streampipe.add(self.rtpjpegdepay) - self.streampipe.add(self.jpegdec) - self.streampipe.add(self.tee_rawvideo) - self.streampipe.add(self.mkvmux) - self.streampipe.add(self.vorbisenc) - self.streampipe.add(self.oggmux) - self.streampipe.add(self.scaling) - self.streampipe.add(self.capsfilter) - self.streampipe.add(self.vp8enc) - self.streampipe.add(self.webmmux) - self.streampipe.add(self.tee_rawaudio) - self.streampipe.add(self.tee_streamaudio) - self.streampipe.add(self.tee_videodecoded) - self.streampipe.add(self.tee_streamfull) - self.streampipe.add(self.queuev_1) - 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.queuev_6) - 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) - # 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) + self.streampipe.add(self.videosrc_backup) + self.streampipe.add(self.capsfilter_backup) + self.streampipe.add(self.queuev_1) + self.streampipe.add(self.screensink) + print ('BACKUP OK...', end='') print('added') def link_pipeline_elements(self, feed='main'): @@ -249,63 +276,68 @@ class New_user_pipeline(): print('Pipeline creation state: linking elements... ', end='') if feed == 'main': - pass # linking here RTSP feed + # Video feed: + self.queuev_1.link(self.rtpjpegdepay) + self.connect_tee(self.tee_rawvideo, + self.rtpjpegdepay, + self.queuev_2, + self.jpegdec,) + self.queuev_2.link(self.mkvmux) + self.mkvmux.link(self.queuev_4) + self.queuev_4.link(self.disksink_rawvideo) + self.connect_tee(self.tee_videodecoded, + self.jpegdec, + self.queuev_3, + self.scaling,) + self.queuev_3.link(self.screensink) + # 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) + # Stream (audio+video) feed: + self.scaling.link(self.capsfilter) + self.capsfilter.link(self.vp8enc) + self.vp8enc.link(self.queuev_6) + self.queuev_6.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) elif feed == 'backup': - pass # linking here backup feed (WEBCAM) - - # Video feed: - self.queuev_1.link(self.rtpjpegdepay) - self.connect_tee(self.tee_rawvideo, - self.rtpjpegdepay, - self.queuev_2, - self.jpegdec,) - self.queuev_2.link(self.mkvmux) - self.mkvmux.link(self.queuev_4) - self.queuev_4.link(self.disksink_rawvideo) - self.connect_tee(self.tee_videodecoded, - self.jpegdec, - self.queuev_3, - self.scaling,) - self.queuev_3.link(self.screensink) - # 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) - # Stream (audio+video) feed: - self.scaling.link(self.capsfilter) - self.capsfilter.link(self.vp8enc) - self.vp8enc.link(self.queuev_6) - self.queuev_6.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) + self.videosrc_backup.link(self.capsfilter_backup) + self.capsfilter_backup.link(self.queuev_1) + self.queuev_1.link(self.screensink) + print('BACKUP OK...', end='') print('linked') - def create_gstreamer_pipeline(self): + def create_gstreamer_pipeline(self, feed='main'): # New empty pipeline: self.streampipe = Gst.Pipeline() - # Setting-up: self.create_pipeline_elements() - self.add_elements_to_pipeline() - self.link_pipeline_elements() - self.create_pipeline_callbacks() + # Setting-up: + if feed == 'main': + self.add_elements_to_pipeline() + self.link_pipeline_elements() + self.create_pipeline_callbacks() + elif feed == 'backup': + self.add_elements_to_pipeline(feed='backup') + self.link_pipeline_elements(feed='backup') global bus bus = self.streampipe.get_bus() @@ -322,18 +354,22 @@ class New_user_pipeline(): print("CREATE HERE A BACKUP PIPELINE") 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) - self.stream_button.set_label('Stream') elif t == Gst.MessageType.ERROR: err, debug = message.parse_error() print ("Error: %s" % err, debug) self.streampipe.set_state(Gst.State.NULL) - self.create_gstreamer_backup_pipeline() - +## self.create_gstreamer_backup_pipeline() +## return 'ERROR' + def stream_play(self): self.streampipe.set_state(Gst.State.PLAYING) + print('[INFO] PLAYING State resquested') def stream_stop(self): self.streampipe.set_state(Gst.State.NULL) -- 2.25.1