├── static
├── index_video.jade
├── layout.jade
├── index.html
└── smoothie.js
├── README.md
├── webmgst.js
├── imagem.js
├── form.js
├── node-flv-streamer.js
├── node-streamer.js
├── node-augmented-reality-streamer.js
├── node-transcoder-ogg-mp3.js
└── node-transcoder-ogg-theora.js
/static/index_video.jade:
--------------------------------------------------------------------------------
1 | h1= LINK
2 | #container
3 | video(src= LINK, controls, autobuffer)
4 |
--------------------------------------------------------------------------------
/static/layout.jade:
--------------------------------------------------------------------------------
1 | !!! 5
2 | html(lang="pt")
3 | head
4 | title='NodeStreamer - live transcoding with nodejs'
5 | script(type='text/javascript')
6 | if (foo) {
7 | bar()
8 | }
9 | body
10 | #wrapper
11 | != body
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Nodestreamer
2 | ============
3 |
4 | Nodestreamer is a set of experiments with multimedia live streaming using nodejs and gstreamer pipelines. All the streaming "magic" is done by the gstreamer element "tcpserversink" that can handle multiple socket connections gracefully.
5 |
6 |
7 | VIDEO STREAMING
8 | ---------------
9 |
10 | Simple experiment with ogg theora streaming.
11 |
12 | Command line: "node node-streamer.js"
13 | Live video url: http://localhost:8003/stream
14 | Monitoring webpage (need a borwser that supports websockets): http://localhost:8003/
15 |
16 |
17 |
18 | TRANSCODING AND STREAMING
19 | ---------------
20 |
21 | Live transcoding of audio streams from RTMP, OGG, MP3, WMV to Ogg+Vorbis or MP3.
22 |
23 | Command line: "node node-transcoder-ogg-mp3.js URL STREAM_FILE_OUT[.mp3 or .ogg] PORT"
24 | Example: "node node-transcoder-ogg-mp3.js mms://karazhan.senado.gov.br/wmtencoder/radio.wmv senado.ogg 9100"
25 | The output url is: http://localhost:9100/senado.ogg
26 |
27 | Live transcoding of video streams from RTMP, OGG, WebM, WMV to Ogg+Theora or WebM.
28 |
29 | Command line: "node node-transcoder-ogg-thera.js URL STREAM_FILE_OUT[.webm or .ogg] PORT"
30 | Example: "node node-transcoder-ogg-theora.js mms://midia.al.rs.gov.br/tval assembeliars.ogg 1234"
31 | The output url is: http://localhost:1234/assembeliars.ogg
32 |
33 |
34 | TODO
35 | ----
36 |
37 | - Improve fault tolerance.
38 | - Support output RTMP streaming.
39 | - When avaiable, use a javascript native gstreamer binding.
40 |
41 | DONE: Implement live transcoding from mp3 to ogg and vice versa.
42 | DONE: Live video transcoding.
43 |
44 |
--------------------------------------------------------------------------------
/webmgst.js:
--------------------------------------------------------------------------------
1 | var express = require('express')
2 | var net = require('net');
3 | var child = require('child_process');
4 |
5 | var cmd = 'gst-launch';
6 | var args = '';
7 | var options = null;
8 | // {env: {LD_LIBRARY_PATH: '/usr/local/lib',
9 | // PATH: '/usr/local/bin:/usr/bin:/bin'}};
10 |
11 | var app = express.createServer();
12 |
13 | app.get('/', function(req, res) {
14 | var date = new Date();
15 |
16 | res.writeHead(200, {
17 | 'Date':date.toUTCString(),
18 | 'Connection':'close',
19 | 'Cache-Control':'private',
20 | 'Content-Type':'video/webm',
21 | 'Server':'CustomStreamer/0.0.1',
22 | });
23 |
24 | var server = net.createServer(function (socket) {
25 | socket.on('data', function (data) {
26 | res.write(data);
27 | });
28 | socket.on('close', function(had_error) {
29 | res.end();
30 | });
31 | });
32 |
33 | server.listen(function() {
34 | args =
35 | [//'ximagesrc',
36 | //'v4l2src',
37 | 'videotestsrc', 'horizontal-speed=3', 'is-live=1',
38 | '!', 'video/x-raw-rgb,framerate=3/1',
39 | '!', 'ffmpegcolorspace',
40 | '!', 'vp8enc', 'speed=2',
41 | '!', 'queue2',
42 | '!', 'm.', 'audiotestsrc',
43 | '!', 'audioconvert',
44 | '!', 'vorbisenc',
45 | '!', 'queue2',
46 | '!', 'm.', 'webmmux', 'name=m', 'streamable=true',
47 | '!', 'tcpclientsink', 'host=localhost',
48 | 'port='+server.address().port];
49 | console.log(args.toString());
50 |
51 | var gstMuxer = child.spawn(cmd, args, options);
52 | gstMuxer.stderr.on('data', onSpawnError);
53 | gstMuxer.on('exit', onSpawnExit);
54 |
55 | res.connection.on('close', function() {
56 | gstMuxer.kill();
57 | });
58 | });
59 | });
60 |
61 | app.listen(9001);
62 |
63 | function onSpawnError(data) {
64 | console.log(data.toString());
65 | }
66 |
67 | function onSpawnExit(code) {
68 | if (code != null) {
69 | console.error('GStreamer error, exit code ' + code);
70 | }
71 | }
72 |
73 | process.on('uncaughtException', function(err) {
74 | console.debug(err);
75 | });
76 |
--------------------------------------------------------------------------------
/imagem.js:
--------------------------------------------------------------------------------
1 | var URL = require('url'),
2 | sURL = 'http://softwarelivre.org/articles/0021/5721/wikipedia-Gnulinux.png?1276286225',
3 | oURL = URL.parse(sURL),
4 | http = require('http'),
5 | client = http.createClient(23456, oURL.hostname),
6 | request = client.request('GET', oURL.pathname, {'host': oURL.hostname})
7 | ;
8 | //var Png = require('png');
9 |
10 | http.createServer(function (req, res) {
11 | var url = req.url.substr(1);
12 | var oURL = URL.parse(url);
13 | var options = {
14 | host: oURL.hostname,
15 | port: 80,
16 | path: oURL.pathname
17 | };
18 | //console.log(options);
19 |
20 | http.get(options, function(gres) {
21 | res.writeHead(200, {'Content-Type': 'text/html'});
22 | var data = '';
23 |
24 | console.log(options);
25 | console.log("Got response: " + gres.statusCode);
26 |
27 | gres.on('data', function (chunk) {
28 | //console.log(chunk);
29 | data += chunk;
30 | });
31 | gres.on('end', function (chunk) {
32 | //if(chunk)
33 | // data += chunk;
34 | var prefix = "data:" + gres.headers["content-type"] + ";base64,";
35 | //res.write("base64...");
36 | var base64 = new Buffer(data, 'binary').toString('base64');
37 | var img = prefix + base64;
38 | //console.log(data);
39 | //res.write(img);
40 | res.write("\n
");
41 | res.write("\n
"); //http://upload.wikimedia.org/wikipedia/commons/3/31/Red-dot-5px.png
42 | res.end();
43 | });
44 | gres.on('error', function(e) {
45 | console.log("Got error on remote image loading: " + e.message);
46 | });
47 |
48 | //console.log(gres);
49 | }).on('error', function(e) {
50 | console.log("Got error: " + e.message);
51 | });
52 | }).listen(2345);
53 |
54 | function image(width, height){
55 | var p = new Png(height, width, 50);
56 | var background = p.color(1, 1, 1, 1);
57 | return 'data:image/png;base64,'+p.getBase64();
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/form.js:
--------------------------------------------------------------------------------
1 | var http = require('http'),
2 | sys = require('sys'),
3 | querystring = require('querystring');
4 |
5 | http.createServer(function(request, response)
6 | {
7 | sys.puts('Request for ' + request.url);
8 |
9 | switch (request.url)
10 | {
11 | case '/':
12 | response.writeHead(200, { 'Content-Type' : 'text/html' });
13 | response.write(
14 | '
'
20 | );
21 | response.end();
22 | break;
23 | case '/cadastrar':
24 | response.writeHead(200, { 'Content-Type' : 'text/html' });
25 | post_handler(request, function(request_data){
26 | response.write(
27 | 'JSON object:
' +
28 | '' + sys.inspect(request_data) + '
' +
29 | '
' +
30 | 'Dados:
' +
31 | 'Nome: ' + request_data.nome + '
' +
32 | 'Email: ' + request_data.email + '
'+
33 | 'Telefone: ' + request_data.telefone + '
'
34 | );
35 | response.end();
36 | });
37 | break;
38 | default:
39 | response.writeHead(400, { 'Content-Type' : 'text/html' });
40 | response.write(
41 | 'Pagina nao encontrada!'
42 | );
43 | response.end();
44 | };
45 | }).listen(8001);
46 | console.log("Servidor rodando na porta 8001");
47 |
48 | function post_handler(request, callback)
49 | {
50 | var _REQUEST = { };
51 | var _CONTENT = '';
52 |
53 | if (request.method == 'POST')
54 | {
55 | request.addListener('data', function(chunk)
56 | {
57 | _CONTENT+= chunk;
58 | });
59 |
60 | request.addListener('end', function()
61 | {
62 | _REQUEST = querystring.parse(_CONTENT);
63 | callback(_REQUEST);
64 | });
65 | };
66 | };
67 |
--------------------------------------------------------------------------------
/node-flv-streamer.js:
--------------------------------------------------------------------------------
1 | /*
2 | This program is free software: you can redistribute it and/or modify
3 | it under the terms of the GNU General Public License as published by
4 | the Free Software Foundation, either version 3 of the License, or
5 | (at your option) any later version.
6 |
7 | This program is distributed in the hope that it will be useful,
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | GNU General Public License for more details.
11 |
12 | You should have received a copy of the GNU General Public License
13 | along with this program. If not, see .
14 | */
15 |
16 | var net = require("net");
17 | var express = require("express");
18 | var http = require("http");
19 | var child = require('child_process');
20 |
21 | var cmd = '/usr/bin/gst-launch-0.10';
22 | var options = null;
23 | var gstMuxer = null;
24 |
25 | http.ServerResponse.prototype.getHashCode = (function() {
26 | var id = 0;
27 | return function() {
28 | if (!this["hashCode"]) {
29 | this["hashCode"] = "";
30 | }
31 | return this["hashCode"];
32 | }
33 | })();
34 |
35 | spawGstreamer(9002);
36 |
37 | var total_data = 0;
38 | var clients = 0;
39 | var app = express.createServer();
40 | var io = require('socket.io').listen(app);
41 | app.get('/stream', function(req, res) {
42 | console.log("new http client");
43 | console.log("server writing header");
44 | req.shouldKeepAlive = false;
45 | var date = new Date();
46 | res.writeHead(200, {
47 | 'Date':date.toUTCString(),
48 | 'Connection':'close',
49 | 'Cache-Control':'private',
50 | 'Content-Type':'video/x-flv',
51 | 'Server':'NodeStreamer/0.0.1',
52 | });
53 |
54 | console.log("trying to connect a socket to gstreamer tcp server.");
55 | var port = 9002;
56 | var socket = new net.createConnection(port);
57 |
58 | io.on('connection', function (s) {
59 | console.log('socket.io client connected');
60 | setInterval(function() {
61 | s.volatile.emit({ "clients" : clients , "total" : total_data });
62 | }, 1000);
63 | });
64 | socket.on('connect', function() {
65 | clients++;
66 | console.log("new client socket connected to gstreamer tcp server "+port);
67 | });
68 | socket.on('data', function (data) {
69 | total_data += data.length;
70 | res.write(data);
71 | });
72 | socket.on('close', function(had_error) {
73 | if(socket && socket.end){
74 | socket.end();
75 | socket.destroy();
76 | }
77 | });
78 | socket.on('end', function () {
79 | socket.end();
80 | });
81 | res.connection.on('close', function() {
82 | console.log("http connecton closed");
83 | if(socket && socket.end) {
84 | socket.end();
85 | socket.destroy();
86 | }
87 | clients--;
88 | });
89 |
90 | });
91 | app.configure(function () {
92 | app.use(express.logger());
93 | app.use(express.errorHandler({
94 | dumpExceptions: true,
95 | showStack: true
96 | }));
97 | app.use(express.static(__dirname+'/static'));
98 | });
99 | app.listen(9000);
100 |
101 | console.log("HTTP server running");
102 |
103 | function spawGstreamer(port) {
104 | args =
105 | ['--gst-debug-level=3',
106 | // 'ximagesrc',
107 | 'videotestsrc', 'is-live=1', //'horizontal-speed=2',
108 | // 'uridecodebin', "uri=htpp://",
109 | // 'filesrc', 'location=', '!', 'decodebin name=dec',
110 | '!', 'videorate',
111 | '!', 'video/x-raw-rgb,framerate=12/1',
112 | '!', 'ffmpegcolorspace',
113 | '!', 'timeoverlay',
114 | '!', 'ffmpegcolorspace',
115 | '!', 'queue',
116 | '!', 'ffenc_flv','bitrate=128',
117 | '!', 'queue',
118 | '!', 'flvmux', 'streamable=true', //'is-live=true',
119 | '!', 'queue',
120 | '!', 'tcpserversink', 'buffers-max=500', 'buffers-soft-max=450', 'recover-policy=1', 'protocol=none', 'blocksize='+(4096 * 5), 'sync=false', 'sync-method=1', 'port='+port];
121 |
122 | gstMuxer = child.spawn(cmd, args, options);
123 | gstMuxer.stderr.on('data', onSpawnError);
124 | gstMuxer.on('exit', onSpawnExit);
125 | console.log(args.toString());
126 | }
127 |
128 | function onSpawnError(data) {
129 | console.log(data.toString());
130 | }
131 |
132 | function onSpawnExit(code) {
133 | if (code != null) {
134 | console.error('GStreamer error, exit code ' + code);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/node-streamer.js:
--------------------------------------------------------------------------------
1 | /*
2 | This program is free software: you can redistribute it and/or modify
3 | it under the terms of the GNU General Public License as published by
4 | the Free Software Foundation, either version 3 of the License, or
5 | (at your option) any later version.
6 |
7 | This program is distributed in the hope that it will be useful,
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | GNU General Public License for more details.
11 |
12 | You should have received a copy of the GNU General Public License
13 | along with this program. If not, see .
14 | */
15 |
16 | var net = require("net");
17 | var express = require("express");
18 | var http = require("http");
19 | var child = require('child_process');
20 |
21 | var cmd = '/usr/bin/gst-launch-0.10';
22 | var options = null;
23 | var gstMuxer = null;
24 |
25 | http.ServerResponse.prototype.getHashCode = (function() {
26 | var id = 0;
27 | return function() {
28 | if (!this["hashCode"]) {
29 | this["hashCode"] = "";
30 | }
31 | return this["hashCode"];
32 | }
33 | })();
34 |
35 | spawGstreamer(11111);
36 |
37 | var total_data = 0;
38 | var clients = 0;
39 | var app = express.createServer();
40 | var io = require('socket.io').listen(app);
41 | app.get('/stream', function(req, res) {
42 | req.shouldKeepAlive = false;
43 | var date = new Date();
44 | res.writeHead(200, {
45 | 'Date':date.toUTCString(),
46 | 'Connection':'close',
47 | 'Cache-Control':'private',
48 | 'Content-Type':'video/ogg',
49 | 'Server':'NodeStreamer/0.0.1',
50 | });
51 | console.log("new http client");
52 | console.log("server writing header");
53 |
54 | console.log("trying to connect a socket to gstreamer tcp server.");
55 | var port = 11111;
56 | var socket = new net.createConnection(port);
57 |
58 | io.on('connection', function (s) {
59 | console.log('socket.io client connected');
60 | setInterval(function() {
61 | s.volatile.emit({ "clients" : clients , "total" : total_data });
62 | }, 1000);
63 | });
64 | socket.on('connect', function() {
65 | clients++;
66 | console.log("new client socket connected to gstreamer tcp server "+port);
67 | });
68 | socket.on('data', function (data) {
69 | total_data += data.length;
70 | /*i++;
71 | if(i % 500 == 0) {
72 | console.log("socket ["+res.getHashCode()+"] total received data from gstreamer: "+ (total_data/(1024*1024))+" MB");
73 | }*/
74 | res.write(data);
75 | });
76 | socket.on('close', function(had_error) {
77 | if(socket && socket.end){
78 | socket.end();
79 | socket.destroy();
80 | }
81 | });
82 | socket.on('end', function () {
83 | socket.end();
84 | });
85 | res.connection.on('close', function() {
86 | console.log("http connecton closed");
87 | if(socket && socket.end) {
88 | socket.end();
89 | socket.destroy();
90 | }
91 | clients--;
92 | });
93 |
94 | });
95 | app.configure(function () {
96 | app.use(express.logger());
97 | app.use(express.errorHandler({
98 | dumpExceptions: true,
99 | showStack: true
100 | }));
101 | app.use(express.static(__dirname+'/static'));
102 | });
103 | app.listen(8003);
104 |
105 | console.log("HTTP server running");
106 |
107 | function spawGstreamer(port) {
108 | args =
109 | ['--gst-debug-level=3',
110 | // 'ximagesrc',
111 | 'videotestsrc', 'is-live=1', //'horizontal-speed=2',
112 | // 'uridecodebin', "uri=htpp://",
113 | // 'filesrc', 'location=', '!', 'decodebin name=dec',
114 | '!', 'videorate',
115 | '!', 'video/x-raw-rgb,framerate=12/1',
116 | '!', 'ffmpegcolorspace',
117 | '!', 'timeoverlay',
118 | '!', 'ffmpegcolorspace',
119 | // '!', 'videorate',
120 | '!', 'queue',
121 | '!', 'theoraenc','quality=10','speed-level=2',
122 | '!', 'queue',
123 | '!', 'oggmux', 'name=m',
124 | '!', 'queue',
125 | '!', 'tcpserversink', 'buffers-max=500', 'buffers-soft-max=450', 'recover-policy=1', 'protocol=none', 'blocksize='+(4096 * 2), 'sync=false', 'sync-method=1', 'port='+port];
126 |
127 | gstMuxer = child.spawn(cmd, args, options);
128 | gstMuxer.stderr.on('data', onSpawnError);
129 | gstMuxer.on('exit', onSpawnExit);
130 | console.log(args.toString());
131 | }
132 |
133 | function onSpawnError(data) {
134 | console.log(data.toString());
135 | }
136 |
137 | function onSpawnExit(code) {
138 | if (code != null) {
139 | console.error('GStreamer error, exit code ' + code);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/node-augmented-reality-streamer.js:
--------------------------------------------------------------------------------
1 | /*
2 | This program is free software: you can redistribute it and/or modify
3 | it under the terms of the GNU General Public License as published by
4 | the Free Software Foundation, either version 3 of the License, or
5 | (at your option) any later version.
6 |
7 | This program is distributed in the hope that it will be useful,
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | GNU General Public License for more details.
11 |
12 | You should have received a copy of the GNU General Public License
13 | along with this program. If not, see .
14 | */
15 |
16 | var net = require("net");
17 | var express = require("express");
18 | var http = require("http");
19 | var child = require('child_process');
20 |
21 | var cmd = '/usr/bin/gst-launch-0.10';
22 | var options = null;
23 | var gstMuxer = null;
24 |
25 | var GSTREAMER_PORT_IN = 7001;
26 | var GSTREAMER_PORT_OUT = 7002;
27 |
28 | var DO_BURST_CONNECTION = false;
29 |
30 | http.ServerResponse.prototype.getHashCode = (function() {
31 | var id = 0;
32 | return function() {
33 | if (!this["hashCode"]) {
34 | this["hashCode"] = "";
35 | }
36 | return this["hashCode"];
37 | }
38 | })();
39 |
40 | try {
41 | spawGstreamerServer(GSTREAMER_PORT_IN, GSTREAMER_PORT_OUT);
42 | } catch(err) {
43 | console.log("Error starting the gstreamer pipeline.");
44 | }
45 |
46 | var total_data = 0;
47 | var clients = 0;
48 | var app = express.createServer();
49 | var io = require('socket.io').listen(app);
50 | app.get('/video.ogg', function(req, res) {
51 | req.shouldKeepAlive = false;
52 | var date = new Date();
53 | res.writeHead(200, {
54 | 'Date':date.toUTCString(),
55 | 'Connection':'close',
56 | 'Cache-Control':'no-cache',
57 | 'Content-Type':'video/ogg',
58 | 'Server':'NodeTranscoder/0.0.1',
59 | });
60 | console.log("new http client");
61 | console.log("server writing header");
62 |
63 | console.log("trying to connect a socket to gstreamer tcp server.");
64 | var socket = new net.createConnection(GSTREAMER_PORT_OUT);
65 |
66 | io.on('connection', function (s) {
67 | console.log('socket.io client connected');
68 | setInterval(function() {
69 | s.volatile.emit({ "clients" : clients , "total" : total_data });
70 | }, 1000);
71 | });
72 | socket.on('connect', function() {
73 | clients++;
74 | console.log("new client socket connected to gstreamer tcp server "+GSTREAMER_PORT_OUT);
75 | });
76 |
77 | console.log("now sending the live buffers direct from gstreamer");
78 | socket.on('data', function (data) {
79 | if(res.writable) {
80 | total_data += data.length;
81 | res.write(data);
82 | }
83 | //console.log("sending "+data.length)
84 | });
85 | socket.on('close', function(had_error) {
86 | if(socket && socket.end){
87 | socket.end();
88 | socket.destroy();
89 | }
90 | });
91 | socket.on('end', function () {
92 | socket.end();
93 | });
94 | res.connection.on('close', function() {
95 | console.log("http connecton closed");
96 | if(socket && socket.end) {
97 | socket.end();
98 | socket.destroy();
99 | }
100 | clients--;
101 | });
102 |
103 | });
104 | app.configure(function () {
105 | app.use(express.logger());
106 | app.use(express.errorHandler({
107 | dumpExceptions: true,
108 | showStack: true
109 | }));
110 | app.use(express.static(__dirname+'/static'));
111 | });
112 | app.listen(7000);
113 |
114 | console.log("HTTP server running");
115 |
116 | function spawGstreamerServer(portIn, portOut) {
117 | args =
118 | ['--gst-debug-level=2',
119 | 'tcpserversrc', 'host=gonod.softwarelivre.org', "port="+portIn,
120 | '!', 'queue',
121 | '!', 'gdpdepay',
122 | '!', 'decodebin2',
123 | '!', 'queue',
124 | '!', 'videorate',
125 | '!', 'videoscale',
126 | '!', 'video/x-raw-yuv, framerate=2/1, width=640, height=480',
127 | '!', 'ffmpegcolorspace',
128 | '!', 'queue',
129 | '!', 'theoraenc', 'bitrate=196',
130 | '!', 'queue',
131 | '!', 'oggmux', 'name=m',
132 | '!', 'queue',
133 | '!', 'progressreport',
134 | '!', 'tcpserversink', 'buffers-max=500', 'buffers-soft-max=450', /*'burst-unit=3',*/ 'recover-policy=1', 'protocol=none', 'blocksize='+(4096 * 1), 'sync=false', 'sync-method=2', 'port='+portOut];
135 | //http://www.flumotion.net/doc/flumotion/reference/trunk/flumotion.component.consumers.httpstreamer.httpstreamer-pysrc.html
136 | gstMuxer = child.spawn(cmd, args, options);
137 | gstMuxer.stderr.on('data', onSpawnError);
138 | gstMuxer.on('exit', onSpawnExit);
139 | console.log(args.toString());
140 | }
141 |
142 | function onSpawnError(data) {
143 | console.log(data.toString());
144 | }
145 |
146 | function onSpawnExit(code) {
147 | if (code == 0) {
148 | console.error('GStreamer error, exit code ' + code);
149 | /* setTimeout(function() {
150 | console.log("Caiu, tentando depois de 5 segundos.");
151 | spawGstreamer(12345);
152 | }, 5 * 1000);*/
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/node-transcoder-ogg-mp3.js:
--------------------------------------------------------------------------------
1 | /*
2 | This program is free software: you can redistribute it and/or modify
3 | it under the terms of the GNU General Public License as published by
4 | the Free Software Foundation, either version 3 of the License, or
5 | (at your option) any later version.
6 |
7 | This program is distributed in the hope that it will be useful,
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | GNU General Public License for more details.
11 |
12 | You should have received a copy of the GNU General Public License
13 | along with this program. If not, see .
14 | */
15 |
16 | var net = require("net");
17 | var express = require("express");
18 | var http = require("http");
19 | var child = require('child_process');
20 |
21 | var cmd = '/usr/bin/gst-launch-0.10';
22 | var options = null;
23 | var gstMuxer = null;
24 |
25 | var GSTREAMER_PORT = new Number(1000+Math.random() * 9000).toFixed(0); //random port
26 |
27 | var DO_BURST_CONNECTION = false;
28 |
29 | http.ServerResponse.prototype.getHashCode = (function() {
30 | var id = 0;
31 | return function() {
32 | if (!this["hashCode"]) {
33 | this["hashCode"] = "";
34 | }
35 | return this["hashCode"];
36 | }
37 | })();
38 |
39 | if(process.argv.length < 5) {
40 | console.log("Please inform all the 3 parameters: URL STREAM_FILE_OUT[.mp3 or .ogg] PORT");
41 | return;
42 | }
43 | //var URL = "http://radiolivre.org:8000/muda.ogg";
44 | var URL = process.argv[2];
45 | var STREAM_OUT = process.argv[3];
46 | var SERVER_PORT = new Number(process.argv[4]);
47 |
48 | try {
49 | console.log("Starting the gstreamer pipeline...");
50 | spawGstreamer(GSTREAMER_PORT, URL, STREAM_OUT.indexOf(".mp3") != -1);
51 | console.log("Gstreamer pipeline started.");
52 | } catch(err) {
53 | console.log("Error starting the gstreamer pipeline.");
54 | }
55 |
56 | var buffer = [];
57 | // Implementing a simple "burts-on-connect"
58 | if(DO_BURST_CONNECTION) {
59 | var bufferSize = 1 * 1024 *1024; // 1mb in bytes
60 | setTimeout(function() {
61 | console.log("Buffering data from gstreamer");
62 | var stream = net.createConnection(GSTREAMER_PORT);
63 | //stream.setTimeout(30 * 1000);
64 | stream.addListener("connect", function() {
65 | console.log("Connected to gstreamer");
66 | stream.addListener("data", function(data){
67 | var size = currentBufferSize();
68 | console.log("Add data " + data.length + " bytes from gstreamer to buffer. Total: "+ size);
69 | while (size > bufferSize) {
70 | buffer.shift();
71 | }
72 | buffer.push(data);
73 | });
74 | });
75 |
76 | }, 10 * 1000);
77 | function currentBufferSize() {
78 | var size = 0, i=0, l=buffer.length;
79 | for (; i.
14 | */
15 |
16 | var net = require("net");
17 | var express = require("express");
18 | var http = require("http");
19 | var child = require('child_process');
20 | var jade = require('jade')
21 | var fs = require('fs');
22 |
23 | var cmd = '/usr/bin/gst-launch-0.10';
24 | var options = null;
25 | var gstMuxer = null;
26 |
27 | var GSTREAMER_PORT = new Number(1000+Math.random() * 9000).toFixed(0); //random port
28 |
29 | var DO_BURST_CONNECTION = false;
30 |
31 | http.ServerResponse.prototype.getHashCode = (function() {
32 | var id = 0;
33 | return function() {
34 | if (!this["hashCode"]) {
35 | this["hashCode"] = "";
36 | }
37 | return this["hashCode"];
38 | }
39 | })();
40 |
41 | if(process.argv.length < 5) {
42 | console.log("Please inform all the 3 parameters: URL OGG_STREAM_LINK PORT");
43 | return;
44 | }
45 | //var URL = "rtsp://stream.camara.gov.br/tvcamara1t200";
46 | var URL = process.argv[2];
47 | var STREAM_OUT = process.argv[3];
48 | var SERVER_PORT = new Number(process.argv[4]);
49 |
50 | try {
51 | console.log("Starting the gstreamer pipeline...");
52 | spawGstreamer(GSTREAMER_PORT, URL);
53 | console.log("Gstreamer pipeline started.");
54 | } catch(err) {
55 | console.log("Error starting the gstreamer pipeline.");
56 | }
57 |
58 | var buffer = [];
59 | // Implementing a simple "burts-on-connect"
60 | if(DO_BURST_CONNECTION) {
61 | var bufferSize = 1 * 1024 *1024; // 1mb in bytes
62 | setTimeout(function() {
63 | console.log("Buffering data from gstreamer");
64 | var stream = net.createConnection(GSTREAMER_PORT);
65 | //stream.setTimeout(30 * 1000);
66 | stream.addListener("connect", function() {
67 | console.log("Connected to gstreamer");
68 | stream.addListener("data", function(data){
69 | var size = currentBufferSize();
70 | console.log("Add data " + data.length + " bytes from gstreamer to buffer. Total: "+ size);
71 | while (size > bufferSize) {
72 | buffer.shift();
73 | }
74 | buffer.push(data);
75 | });
76 | });
77 |
78 | }, 10 * 1000);
79 | function currentBufferSize() {
80 | var size = 0, i=0, l=buffer.length;
81 | for (; i 0) {
101 | for (var t = time - (time % options.grid.millisPerLine); t >= time - (dimensions.width * options.millisPerPixel); t -= options.grid.millisPerLine) {
102 | canvasContext.beginPath();
103 | var gx = Math.round(dimensions.width - ((time - t) / options.millisPerPixel));
104 | canvasContext.moveTo(gx, 0);
105 | canvasContext.lineTo(gx, dimensions.height);
106 | canvasContext.stroke();
107 | canvasContext.closePath();
108 | }
109 | }
110 |
111 | // Horizontal (value) dividers.
112 | for (var v = 1; v < options.grid.verticalSections; v++) {
113 | var gy = Math.round(v * dimensions.height / options.grid.verticalSections);
114 | canvasContext.beginPath();
115 | canvasContext.moveTo(0, gy);
116 | canvasContext.lineTo(dimensions.width, gy);
117 | canvasContext.stroke();
118 | canvasContext.closePath();
119 | }
120 | // Bounding rectangle.
121 | canvasContext.beginPath();
122 | canvasContext.strokeRect(0, 0, dimensions.width, dimensions.height);
123 | canvasContext.closePath();
124 | canvasContext.restore();
125 |
126 | // Calculate the current scale of the chart, from all time series.
127 | var maxValue = undefined;
128 | var minValue = undefined;
129 |
130 | for (var d = 0; d < this.seriesSet.length; d++) {
131 | // TODO(ndunn): We could calculate / track these values as they stream in.
132 | var timeSeries = this.seriesSet[d].timeSeries;
133 | if (timeSeries.maxValue) {
134 | maxValue = maxValue ? Math.max(maxValue, timeSeries.maxValue) : timeSeries.maxValue;
135 | }
136 |
137 | if (timeSeries.minValue) {
138 | minValue = minValue ? Math.min(minValue, timeSeries.minValue) : timeSeries.minValue;
139 | }
140 | }
141 |
142 | if (!maxValue && !minValue) {
143 | return;
144 | }
145 |
146 | var valueRange = maxValue - minValue;
147 | var num = null;
148 |
149 | // For each data set...
150 | for (var d = 0; d < this.seriesSet.length; d++) {
151 | canvasContext.save();
152 | var timeSeries = this.seriesSet[d].timeSeries;
153 | var dataSet = timeSeries.data;
154 | var seriesOptions = this.seriesSet[d].options;
155 |
156 | // Delete old data that's moved off the left of the chart.
157 | // We must always keep the last expired data point as we need this to draw the
158 | // line that comes into the chart, but any points prior to that can be removed.
159 | while (dataSet.length >= 2 && dataSet[1][0] < time - (dimensions.width * options.millisPerPixel)) {
160 | dataSet.splice(0, 1);
161 | }
162 |
163 | // Set style for this dataSet.
164 | canvasContext.lineWidth = seriesOptions.lineWidth || 1;
165 | canvasContext.fillStyle = seriesOptions.fillStyle;
166 | canvasContext.strokeStyle = seriesOptions.strokeStyle || '#ffffff';
167 | // Draw the line...
168 | canvasContext.beginPath();
169 | // Retain lastX, lastY for calculating the control points of bezier curves.
170 | var firstX = 0, lastX = 0, lastY = 0;
171 | for (var i = 0; i < dataSet.length; i++) {
172 | // TODO: Deal with dataSet.length < 2.
173 | var x = Math.round(dimensions.width - ((time - dataSet[i][0]) / options.millisPerPixel));
174 | var value = dataSet[i][1];
175 | if(num == null)
176 | num = value;
177 | var offset = maxValue - value;
178 | var scaledValue = Math.round((offset / valueRange) * dimensions.height);
179 | var y = Math.max(Math.min(scaledValue, dimensions.height - 1), 1); // Ensure line is always on chart.
180 |
181 | if (i == 0) {
182 | firstX = x;
183 | }
184 | // Great explanation of Bezier curves: http://en.wikipedia.org/wiki/B�zier_curve#Quadratic_curves
185 | //
186 | // Assuming A was the last point in the line plotted and B is the new point,
187 | // we draw a curve with control points P and Q as below.
188 | //
189 | // A---P
190 | // |
191 | // |
192 | // |
193 | // Q---B
194 | //
195 | // Importantly, A and P are at the same y coordinate, as are B and Q. This is
196 | // so adjacent curves appear to flow as one.
197 | //
198 | canvasContext.bezierCurveTo( // startPoint (A) is implicit from last iteration of loop
199 | Math.round((lastX + x) / 2), lastY, // controlPoint1 (P)
200 | Math.round((lastX + x)) / 2, y, // controlPoint2 (Q)
201 | x, y); // endPoint (B)
202 |
203 | lastX = x, lastY = y;
204 | }
205 | if (dataSet.length > 0 && seriesOptions.fillStyle) {
206 | // Close up the fill region.
207 | canvasContext.lineTo(dimensions.width + seriesOptions.lineWidth + 1, lastY);
208 | canvasContext.lineTo(dimensions.width + seriesOptions.lineWidth + 1, dimensions.height + seriesOptions.lineWidth + 1);
209 | canvasContext.lineTo(firstX, dimensions.height + seriesOptions.lineWidth);
210 | canvasContext.fill();
211 | }
212 | canvasContext.stroke();
213 | canvasContext.closePath();
214 | canvasContext.restore();
215 | }
216 |
217 | // Draw the axis values on the chart.
218 | if (!options.labels.disabled) {
219 | canvasContext.fillStyle = options.labels.fillStyle;
220 | var maxValueString = maxValue.toFixed(2);
221 | var minValueString = minValue.toFixed(2);
222 | canvasContext.fillText(maxValueString, dimensions.width - canvasContext.measureText(maxValueString).width - 2, 10);
223 | canvasContext.fillText(minValueString, dimensions.width - canvasContext.measureText(minValueString).width - 2, dimensions.height - 2);
224 | canvasContext.fillText(value.toFixed(2), 20, 10);
225 | }
226 |
227 | canvasContext.restore(); // See .save() above.
228 | }
229 |
--------------------------------------------------------------------------------