A blog by Devendra Tewari
In this post, we’ll stream live WebM video to the browser using just GStreamer and Node.js. We’ll use Node.js with the Express middleware. We have used the latter to stream a WebM file on demand.
We receive a request from the browser at port 9001, create a TCP server socket to receive the WebM stream, and stream all data received from that socket to the browser. Then, we spawn a GStreamer pipeline to mux a WebM stream, and stream it to the TCP server socket using the tcpclientsink
element.
The code follows
var express = require('express')
var http = require('http')
var net = require('net');
var child = require('child_process');
var app = express();
var httpServer = http.createServer(app);
app.get('/', function (req, res) {
var date = new Date();
res.writeHead(200, {
'Date': date.toUTCString(),
'Connection': 'close',
'Cache-Control': 'private',
'Content-Type': 'video/webm',
'Server': 'CustomStreamer/0.0.1',
});
var tcpServer = net.createServer(function (socket) {
socket.on('data', function (data) {
res.write(data);
});
socket.on('close', function (had_error) {
res.end();
});
});
tcpServer.maxConnections = 1;
tcpServer.listen(function () {
var cmd = 'gst-launch-1.0';
var args =
['autovideosrc',
'!', 'video/x-raw,framerate=30/1,width=320,height=240',
'!', 'videoconvert',
'!', 'queue', 'leaky=1',
'!', 'vp8enc',
'!', 'queue', 'leaky=1',
'!', 'm.', 'autoaudiosrc',
'!', 'queue', 'leaky=1',
'!', 'audioconvert',
'!', 'vorbisenc',
'!', 'queue', 'leaky=1',
'!', 'm.', 'webmmux', 'name=m', 'streamable=true',
'!', 'queue', 'leaky=1',
'!', 'tcpclientsink', 'host=localhost',
'port=' + tcpServer.address().port];
var gstMuxer = child.spawn(cmd, args);
gstMuxer.stderr.on('data', onSpawnError);
gstMuxer.on('exit', onSpawnExit);
res.connection.on('close', function () {
gstMuxer.kill();
});
});
});
httpServer.listen(9001);
function onSpawnError(data) {
console.log(data.toString());
}
function onSpawnExit(code) {
if (code != null) {
console.log('GStreamer error, exit code ' + code);
}
}
process.on('uncaughtException', function (err) {
console.log(err);
});
Assuming you have saved the code to a file called script.js, run Node.js thus
node script.js
Now, you can play the WebM stream in Chrome by accessing http://localhost:9001/.
You may want to trace all system calls, especially if you change the args to GStreamer and get a cryptic message such as
execvp(): No such file or directory
You can execute Node.js with strace
strace -fF -o strace.log node script.js
Here’s a list of alternative video source elements
Here’s a list of alternative audio source elements
An important point to note is that all these sources are live sources. GStreamer defines live sources as sources that discard data when paused, and produce data at a fixed rate thus providing a clock to publish this rate.
GStreamer pipelines cannot simultaneously capture streams using sources that access the same device, hence tcpServer.maxConnections
has been restricted to 1. Even assuming that simultaneous access to the device was possible, the code above is CPU intensive since audio and video encoding is done once per viewer.