summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--default.css6
-rw-r--r--icecastClient.js1
-rw-r--r--init.js157
-rw-r--r--panel.js6
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',
diff --git a/init.js b/init.js
index d8dc5ae..d66e4b4 100644
--- a/init.js
+++ b/init.js
@@ -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('');
}
diff --git a/panel.js b/panel.js
index bfee077..f0683f2 100644
--- a/panel.js
+++ b/panel.js
@@ -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() {