Skip to content

Instantly share code, notes, and snippets.

@spscream
Created September 11, 2014 14:36
Show Gist options
  • Select an option

  • Save spscream/88013e1db00e1de89766 to your computer and use it in GitHub Desktop.

Select an option

Save spscream/88013e1db00e1de89766 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import gi
import os
from datetime import datetime
gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst, Gtk
from gi.repository import GdkX11, GstVideo
from gi.repository.Gtk import Window, VBox, HBox, DrawingArea, ToggleButton, Button, Statusbar
GObject.threads_init()
Gst.init(None)
"""
gst-launch-0.10 -ev \
udpsrc uri="udp://192.168.100.100:20000" ! tee name=source0 \
source0. ! queue ! tsdemux name=demuxer \
demuxer. ! "audio/mpeg" ! queue max-size-buffers=1200 max-size-time=0 max-size-bytes=0 ! tee name=audio0 \
demuxer. ! "video/x-h264" ! queue max-size-buffers=1200 max-size-time=0 max-size-bytes=0 ! tee name=video0 \
qtmux name=mp4muxer moov-recovery-file=/home/dvruser/gstreamer/records/cam0_rec_$DATE.moov dts-method=0 \
video0. ! queue ! h264parse ! mp4muxer. \
audio0. ! queue ! mpegaudioparse ! mp4muxer. \
mp4muxer. ! filesink location=/home/dvruser/gstreamer/records/cam0_rec_$DATE.mp4 \
video0. ! queue ! h264parse ! ffdec_h264 ! ffmpegcolorspace ! deinterlace ! xvimagesink \
#audio0. ! queue ! mpegaudioparse ! mad ! pulsesink device=$ADEVICE \
"""
SOURCE="rtmp://192.168.100.100:1935/cameras/cam0"
#SOURCE="rtmp://itv08.digizuite.dk/tv2b/ch1"
class YayMan:
def __init__(self):
self.make_gui()
self.start_time = datetime.today()
self.pipeline = Gst.Pipeline.new('main')
######### Record Pipeline ####################################################################################################################
# #
# [Source] -> [Source Tee] -> [demux]--,-> [atee]-> [aq]-> [fake] #
# '-> [vtee]-> [vq]-> [h264parse] -> [avdec_h264] -> [videoconvert] -> [deinterlace] -> [xvimagesink] #
# #
##############################################################################################################################################
######## Source tee
self.source = Gst.ElementFactory.make("rtmpsrc", "rtmp-source")
self.source.set_property("location", SOURCE)
# Add to pipeline
self.pipeline.add(self.source)
######## Source tee to demuxer
self.demux = Gst.ElementFactory.make("flvdemux", "demux")
self.demux.connect("pad-added", self.demuxer_callback)
# Add to pipeline
self.pipeline.add(self.demux)
# Link
self.source.link(self.demux)
######## Make a tee
self.atee = Gst.ElementFactory.make("tee", "atee")
self.vtee = Gst.ElementFactory.make("tee", "vtee")
# Add to pipeline
self.pipeline.add(self.atee)
self.pipeline.add(self.vtee)
######## Video Output to video area
self.vq = Gst.ElementFactory.make("queue", "vq")
self.h264parse = Gst.ElementFactory.make("h264parse", "h264parse")
self.ffdec_h264 = Gst.ElementFactory.make("avdec_h264", "avdec_h264")
#self.ffmpegcolorspace = Gst.ElementFactory.make("videoconvert", "ffcs")
#self.deinterlace = Gst.ElementFactory.make("deinterlace", "deinterlace")
#self.xvimagesink = Gst.ElementFactory.make("xvimagesink", "xvimagesink")
# Add to pipeline
self.pipeline.add(self.vq)
self.pipeline.add(self.h264parse)
#self.pipeline.add(self.ffdec_h264)
#self.pipeline.add(self.ffmpegcolorspace)
#self.pipeline.add(self.deinterlace)
#self.pipeline.add(self.xvimagesink)
# Link
self.vtee.link(self.vq)
self.vq.link(self.h264parse)
#self.h264parse.link(self.ffdec_h264)
#self.ffdec_h264.link(self.ffmpegcolorspace)
#self.ffmpegcolorspace.link(self.deinterlace)
#self.deinterlace.link(self.xvimagesink)
######## Audio Output to fake
# queue ! mpegaudioparse ! mad ! pulsesink device=combined
self.aq = Gst.ElementFactory.make("queue", "aq")
self.mpegaudioparse = Gst.ElementFactory.make("aacparse", "mpparse")
self.mad = Gst.ElementFactory.make("avdec_aac", "mad")
self.fake_audio = Gst.ElementFactory.make("fakesink", "fake-a")
#self.pulsesink = Gst.ElementFactory.make("pulsesink","asink")
#self.pulsesink.set_property("device","combined")
# Add to pipeline
self.pipeline.add(self.aq)
self.pipeline.add(self.fake_audio)
self.pipeline.add(self.mpegaudioparse)
#self.pipeline.add(self.mad)
#self.pipeline.add(self.pulsesink)
# Link
self.atee.link(self.aq)
self.atee.link(self.fake_audio)
self.aq.link(self.mpegaudioparse)
#self.mpegaudioparse.link(self.mad)
#self.mad.link(self.pulsesink)
# Link
self.atee.link(self.aq)
self.atee.link(self.fake_audio)
self.aq.link(self.mpegaudioparse)
#self.mpegaudioparse.link(self.mad)
#self.mad.link(self.pulsesink)
######### camerabin LANG: Russian
self.record = Gst.ElementFactory.make("camerabin", "recrus")
self.pipeline.add(self.record)
#self.fake2 = Gst.ElementFactory.make("fakesink","f2")
self.cam_wrapper = Gst.ElementFactory.make("wrappercamerabinsrc","camwrapper")
self.cam_wrapper.set_property("video-source", self.ffdec_h264)
self.record.set_property("camera-source", self.cam_wrapper)
self.record.set_property("audio-source", self.mad)
self.record.set_property("location", self.record_location())
#self.record.set_property("audio-source", self.fake)
self.record.set_property("mode", 2)
#self.record.set_property("viewfinder-sink", self.fake2)
wrapper_input_sink = Gst.GhostPad.new("videosink", self.ffdec_h264.get_static_pad("sink"))
wrapper_input_sink.set_active(True)
self.cam_wrapper.add_pad(wrapper_input_sink)
record_input_sink = Gst.GhostPad.new("videosink", self.cam_wrapper.get_static_pad("videosink"))
record_input_sink.set_active(True)
self.record.add_pad(record_input_sink)
self.h264parse.get_static_pad("src").link(self.record.get_static_pad("videosink"))
record_input_audio_sink = Gst.GhostPad.new("audiosink", self.mad.get_static_pad("sink"))
record_input_audio_sink.set_active(True)
self.record.add_pad(record_input_audio_sink)
self.mpegaudioparse.get_static_pad("src").link(self.record.get_static_pad("audiosink"))
# Add to pipeline
#self.pipeline.add(self.record)
# Link
#self.stee.link(self.record)
######### Record bin ##
self.recorder = None
self.bus = self.pipeline.get_bus()
self.bus.add_signal_watch()
self.bus.connect('message::error', self.on_error)
#self.record_bus.enable_sync_message_emission()
#self.record_bus.connect('sync-message::element', self.on_sync_message)
def demuxer_callback(self, demuxer, pad):
print (pad.get_property("template").name_template)
if pad.get_property("template").name_template == "audio":
atee_pad = self.atee.get_static_pad("sink")
pad.link(atee_pad)
elif pad.get_property("template").name_template == "video":
vtee_pad = self.vtee.get_static_pad("sink")
pad.link(vtee_pad)
def record_location(self):
today = datetime.today()
directory = "./"+today.strftime("%d-%m-%y")
if not os.path.exists(directory):
os.makedirs(directory)
return today.strftime("%d-%m-%y/%H:%M:%S") + "_rus.flv"
def make_gui(self):
self.window = Window()
self.window.connect('destroy', self.quit)
self.window.set_default_size(640, 450)
self.vbox = VBox()
self.video_area = DrawingArea()
self.controls_box = HBox()
self.record_button = ToggleButton(label="Запись")
self.record_button.connect("toggled", self.toggle_record_cb)
self.translator_button = ToggleButton(label="Запись переводчика")
self.translator_button.connect("toggled", self.toggle_translator_cb)
self.statusbar = Statusbar()
self.vbox.pack_start(self.video_area, True, True, 0)
self.controls_box.pack_start(self.record_button, False, False, 0)
self.controls_box.pack_start(self.translator_button, False, False, 0)
self.controls_box.pack_start(self.statusbar, True, True, 0)
self.vbox.pack_start(self.controls_box, False, False, 0)
self.window.add(self.vbox)
def run(self):
self.window.show_all()
self.xid = self.video_area.get_property('window').get_xid()
self.pipeline.set_state(Gst.State.PLAYING)
self.record.set_state(Gst.State.PLAYING)
Gst.debug_bin_to_dot_file(self.record, Gst.DebugGraphDetails.ALL, "record")
Gst.debug_bin_to_dot_file(self.pipeline, Gst.DebugGraphDetails.ALL, "pipeline")
def quit(self, window):
self.pipeline.set_state(Gst.State.NULL)
Gtk.main_quit()
def on_sync_message(self, bus, msg):
if msg.get_structure().get_name() == 'prepare-window-handle':
print('prepare-window-handle')
msg.src.set_property('force-aspect-ratio', True)
msg.src.set_window_handle(self.xid)
def on_error(self, bus, msg):
print('on_error():', msg.parse_error())
def toggle_record_cb(self, widget, data=None):
print (widget.get_active())
if widget.get_active():
self.record.set_property("location", self.record_location())
self.record.emit("start-capture")
else:
self.record.emit("stop-capture")
def toggle_translator_cb(self, widget, data=None):
print (widget.get_active())
if __name__ == "__main__":
yayman = YayMan()
yayman.run()
try:
Gtk.main()
except KeyboardInterrupt:
print("Ctrl^C. Exiting...")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment