diff options
-rw-r--r-- | default.css | 6 | ||||
-rw-r--r-- | icecastClient.js | 1 | ||||
-rw-r--r-- | init.js | 157 | ||||
-rw-r--r-- | panel.js | 6 |
4 files changed, 132 insertions, 38 deletions
diff --git a/default.css b/default.css index 774f1b0..1e893f9 100644 --- a/default.css +++ b/default.css @@ -5,9 +5,3 @@ #panel { background-color: #555555; } - -#stage-layout { - background-color: black; -} - - diff --git a/icecastClient.js b/icecastClient.js index a9b7978..522fca1 100644 --- a/icecastClient.js +++ b/icecastClient.js @@ -41,6 +41,7 @@ IcecastClient.prototype = { this._pipeline = Gst.Pipeline.new('stream'); this._bus = this._pipeline.get_bus(); + this._bus.add_signal_watch(); this._bus.connect('message::eos', Lang.bind(this, this._onEndOfStream)); this._bus.connect('message::error', @@ -26,6 +26,7 @@ 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; @@ -60,23 +61,16 @@ function _initStage() { Clutter.init(null, null); stage = Clutter.Stage.get_default(); - stage.set_size(512, 512); 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"); - - stageLayout = new Mx.BoxLayout({ name: 'stage-layout', - orientation: Mx.Orientation.VERTICAL }); - stage.add_actor(stageLayout); - - stageLayout.add_constraint(new Clutter.BindConstraint({ source: stage, - coordinate: Clutter.BindCoordinate.SIZE })); - stageLayout.add_constraint(new Clutter.BindConstraint({ source: stage, - coordinate: Clutter.BindCoordinate.POSITION })); } function _init() { @@ -86,35 +80,140 @@ function _init() { _initStage(); let pipeline = Gst.Pipeline.new('feed-pipeline'); + let bus = pipeline.get_bus(); let texture = new Clutter.Texture({ name: 'video-texture' }); - stageLayout.add_actor(texture, -1); - stageLayout.child_set_expand(texture, true); - stageLayout.child_set_y_fill(texture, true); - stageLayout.child_set_y_align(texture, 0.0); 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; - pipeline.set_state(Gst.State.PLAYING); - - let panel = new Panel.Panel(); - stageLayout.add_actor(panel.actor, -1); - stageLayout.child_set_expand(panel.actor, false); - stageLayout.child_set_x_align(panel.actor, 0.0); - stageLayout.child_set_x_fill(panel.actor, true); - stageLayout.child_set_y_align(panel.actor, 1.0); - stageLayout.child_set_y_fill(panel.actor, false); - - panel.connect('toggle-fullscreen', - function () { - stage.set_fullscreen(!stage.get_fullscreen()); - }); + 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'); + }); + }); - stage.show_all(); Mainloop.run(''); } @@ -36,7 +36,7 @@ Panel.prototype = { this._broadcastButton.set_icon_name('media-record-symbolic'); this._broadcastButton.set_icon_size(16); this.actor.add_actor(this._broadcastButton, -1); - this.actor.child_set_x_align(this._broadcastButton, 0.0); + this.actor.child_set_x_align(this._broadcastButton, Mx.Align.START); this._broadcastButton.connect('clicked', Lang.bind(this, function() { @@ -47,14 +47,14 @@ Panel.prototype = { disabled: true }); this.actor.add_actor(this._slider, -1); this.actor.child_set_expand(this._slider, true); - this.actor.child_set_x_align(this._slider, 0.5); + this.actor.child_set_x_align(this._slider, Mx.Align.MIDDLE); this.actor.child_set_x_fill(this._slider, true); this._fullscreenButton = new Mx.Button({ style_class: 'panel-item' }); this._fullscreenButton.set_icon_name('view-fullscreen-symbolic'); this._fullscreenButton.set_icon_size(16); this.actor.add_actor(this._fullscreenButton, -1); - this.actor.child_set_x_align(this._fullscreenButton, 1.0); + this.actor.child_set_x_align(this._fullscreenButton, Mx.Align.END); this._fullscreenButton.connect('clicked', Lang.bind(this, function() { |