Created
September 11, 2014 14:36
-
-
Save spscream/88013e1db00e1de89766 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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