Skip to content

Instantly share code, notes, and snippets.

@moeiscool
Last active January 25, 2024 21:47
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 17 You must be signed in to fork a gist
  • Save moeiscool/e2a584cca6f4e3f1691a96b6c56856f9 to your computer and use it in GitHub Desktop.
Save moeiscool/e2a584cca6f4e3f1691a96b6c56856f9 to your computer and use it in GitHub Desktop.
FFMPEG to Web Browser with Express, Socket.IO and JSMPEG
// Shinobi (http://shinobi.video) - FFMPEG H.264 over HTTP Test
// How to Use raw H.264 (Simulated RTSP)
// 1. Start with `node ffmpegToWeb.js`
// 2. Get the IP address of the computer where you did step 1. Example : 127.0.0.1
// 3. Open VLC and "Open Network Stream".
// 4. Input the following without quotes : `http://127.0.0.1:8001/h264` and start.
var child = require('child_process');
var io = require('socket.io');
var events = require('events');
var express = require('express')
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var spawn = child.spawn;
var exec = child.exec;
var Emitters = {}
var config = {
port:8001,
url:'rtsp://131.95.3.162/axis-media/media.3gp'
}
var initEmitter = function(feed){
if(!Emitters[feed]){
Emitters[feed] = new events.EventEmitter().setMaxListeners(0)
}
return Emitters[feed]
}
//web app
console.log('Starting Express Web Server on Port '+config.port)
server.listen(config.port);
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
})
//ffmpeg pushed stream in here to make a pipe
app.all('/streamIn/:feed', function (req, res) {
req.Emitter = initEmitter(req.params.feed)
//req.params.feed = Feed Number (Pipe Number)
res.connection.setTimeout(0);
req.on('data', function(buffer){
req.Emitter.emit('data',buffer)
io.to('STREAM_'+req.params.feed).emit('h264',{feed:req.params.feed,buffer:buffer})
});
req.on('end',function(){
console.log('close');
});
})
//socket.io client commands
io.on('connection', function (cn) {
cn.on('f',function (data) {
switch(data.function){
case'getStream':
console.log(data)
cn.join('STREAM_'+data.feed)
break;
}
})
});
//simulate RTSP over HTTP
app.get(['/h264','/h264/:feed'], function (req, res) {
if(!req.params.feed){req.params.feed='1'}
req.Emitter = initEmitter(req.params.feed)
var contentWriter
var date = new Date();
res.writeHead(200, {
'Date': date.toUTCString(),
'Connection': 'keep-alive',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache',
'Content-Type': 'video/mp4',
'Server': 'Shinobi H.264 Test Stream',
});
req.Emitter.on('data',contentWriter=function(buffer){
res.write(buffer)
})
res.on('close', function () {
req.Emitter.removeListener('data',contentWriter)
})
});
//ffmpeg
console.log('Starting FFMPEG')
var ffmpegString = '-i '+config.url+''
ffmpegString += ' -f mpegts -c:v mpeg1video -an http://localhost:'+config.port+'/streamIn/1'
ffmpegString += ' -f mpegts -c:v mpeg1video -an http://localhost:'+config.port+'/streamIn/2'
if(ffmpegString.indexOf('rtsp://')>-1){
ffmpegString='-rtsp_transport tcp '+ffmpegString
}
console.log('Executing : ffmpeg '+ffmpegString)
var ffmpeg = spawn('ffmpeg',ffmpegString.split(' '));
ffmpeg.on('close', function (buffer) {
console.log('ffmpeg died')
})
//ffmpeg.stderr.on('data', function (buffer) {
// console.log(buffer.toString())
//});
//ffmpeg.stdout.on('data', function (buffer) {
// Emitter.emit('data',buffer)
//});
<script src="http://cdn.shinobi.video/js/socket.io.js"></script>
<script src="http://cdn.shinobi.video/js/jquery.min.js"></script>
<!--Special JSMPEG Start-->
<!--You need this version. Check for updates here https://github.com/ShinobiCCTV/jsmpeg-pipe -->
<script src="http://cdn.shinobi.video/js/jsmpeg.pipe.js"></script>
<!--Special JSMPEG End-->
<canvas id="canvas" height=500 width=500></canvas>
<script>
//start socket.io client connection
var socket = io();
//on socket.io connection success
socket.on('connect',function(){
//pretend this is the command you use to initiate getting H.264 (MPEG) data
socket.emit('f',{function:'getStream',feed:'2'})
})
// initiate a player that can be piped to.
var player = new JSMpeg.Player('pipe',{
canvas:document.getElementById('canvas')
});
//on data from "h264" handle
socket.on('h264', function (data) {
// `data.buffer` is the raw video data from FFMPEG
// pretend you are getting data as follows
// var data = {buffer:ArrayBuffer}
player.write(data.buffer)
});
</script>
{
"name": "ffmpegtoweb",
"version": "1.0.0",
"description": "Shinobi Testing Tool for H.264 over HTTP and Socket.IO",
"main": "ffmpegToWeb.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"express": "^4.14.0",
"socket.io": "^1.7.1"
},
"author": "Moe Alam",
"license": "MIT"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment