imports.gi.versions.GLib = '2.0'; imports.gi.versions.GObject = '2.0'; imports.gi.versions.Gio = '2.0'; imports.gi.versions.Gdk = '3.0'; imports.gi.versions.Gtk = '3.0'; imports.gi.versions.Clutter = '1.0'; imports.gi.versions.Gst = '0.10'; imports.gi.versions.GstBase = '0.10'; imports.gi.versions.GstVideo = '0.10'; const Mainloop = imports.mainloop; const IcecastClient = imports.icecastClient; const Panel = imports.panel; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; const Gio = imports.gi.Gio; const Gdk = imports.gi.Gdk; const Gtk = imports.gi.Gtk; const Clutter = imports.gi.Clutter; const Mx = imports.gi.Mx; const Gst = imports.gi.Gst; const GstInterfaces = imports.gi.GstInterfaces; const ClutterGst = imports.gi.ClutterGst; let application = null; let style = null; let stage = null; let stageLayout = null; _init(); function _initApplication() { Gtk.init(null, null); let settings = Gtk.Settings.get_default(); settings.gtk_application_prefer_dark_theme = true; application = new Gtk.Application({ application_id: 'org.gnome.LiveMeetFeed' }); } function _initGStreamer() { Gst.init(null, null); Gst.debug_set_active(true); Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING); Gst.debug_set_colored(false); } function _initStyle() { style = Mx.Style.get_default(); style.load_from_file('default.css'); } function _initStage() { Clutter.init(null, null); stage = Clutter.Stage.get_default(); stage.set_user_resizable(true); stage.set_color(new Clutter.Color({ red: 0, green: 0, blue: 0})); stage.connect('delete-event', function() { Mainloop.quit(''); return true; }); stage.set_title("Live Meet Feed"); } function _init() { _initApplication(); _initGStreamer(); _initStyle(); _initStage(); let pipeline = Gst.Pipeline.new('feed-pipeline'); let bus = pipeline.get_bus(); let texture = new Clutter.Texture({ name: 'video-texture' }); texture.show(); let frame = new Mx.Frame({ child: texture, name: 'video-frame' }); frame.x_fill = true; frame.y_fill = false; frame.y_align = Mx.Align.MIDDLE; frame.add_constraint(new Clutter.BindConstraint({ source: stage, coordinate: Clutter.BindCoordinate.SIZE })); frame.add_constraint(new Clutter.BindConstraint({ source: stage, coordinate: Clutter.BindCoordinate.POSITION })); stage.add_actor(frame); let source = Gst.ElementFactory.make('camerabin', 'camera-source'); source.video_capture_height = 0; source.video_capture_width = 0; bus.add_signal_watch(); pipeline.add(source); let sink = new ClutterGst.VideoSink({ texture: texture }); sink.async = false; source.viewfinder_sink = sink; let caps = Gst.caps_from_string('video/x-raw-yuv; video/x-raw-rgb'); source.filter_caps = caps; let videoEncoder = Gst.ElementFactory.make('theoraenc', 'video-encoder'); videoEncoder.speed_level = 2; source.video_encoder = videoEncoder; let audioEncoder = Gst.ElementFactory.make('vorbisenc', 'audio-encoder'); source.audio_encoder = audioEncoder; let bin = Gst.Bin.new('output-bin'); let muxer = Gst.ElementFactory.make('oggmux', 'muxer'); bin.add(muxer); let tee = Gst.ElementFactory.make('tee', 'output-split'); bin.add(tee); muxer.link(tee); let transmitter = Gst.ElementFactory.make('shout2send', 'feed-transmitter'); transmitter.ip = 'livefeed.lab.bos.redhat.com'; transmitter.port = 80; transmitter.password = 'sodoubt'; transmitter.mount = 'test.ogg' ; transmitter.async = false; bin.add(transmitter); tee.link(transmitter); let muxerSink = muxer.get_request_pad('sink_%d'); let ghostSink = Gst.GhostPad.new('sink', muxerSink); bin.add_pad(ghostSink); let teeSource = tee.get_request_pad('src%d'); let ghostSource = Gst.GhostPad.new('src', teeSource); bin.add_pad(ghostSource); source.video_muxer = bin; source.mode = 1; source.flags = 0x000000d9 | 0x20; source.filename = "test.ogg" pipeline.set_state(Gst.State.READY); /* FIXME: figure out how to get notified when input caps are available */ Mainloop.timeout_add(150, function() { let capsSize = source.video_source_caps.get_size(); let maxCameraWidth; let maxCameraHeight; maxCameraWidth = 0; maxCameraHeight = 0; for (let i = 0; i < capsSize; i++) { let [hasWidth, width] = source.video_source_caps.get_structure(i).get_int('width'); let [hasHeight, height] = source.video_source_caps.get_structure(i).get_int('height'); if (!hasWidth || !hasHeight) { continue; } if (width > 512) { continue; } if (height > 512) { continue; } if (width > maxCameraWidth) { maxCameraWidth = width; } if (height > maxCameraHeight) { maxCameraHeight = height; } } let panel = new Panel.Panel(); stage.connect('notify::allocation', function() { panel.actor.set_size(stage.width, -1); let x = 0; let y = stage.height - panel.actor.height; panel.actor.set_position(x, y); }); stage.add_actor(panel.actor); panel.connect('toggle-fullscreen', function () { stage.set_fullscreen(!stage.get_fullscreen()); }); let [minimumPanelHeight, naturalPanelHeight] = panel.actor.get_preferred_height(maxCameraWidth); stage.set_size(maxCameraWidth, maxCameraHeight + naturalPanelHeight); stage.show_all(); pipeline.set_state(Gst.State.PLAYING); panel.connect('toggle-broadcast', function () { Gst.debug_set_default_threshold(Gst.DebugLevel.WARNING); source.emit('capture-start'); }); }); Mainloop.run(''); }