Skip to content

Instantly share code, notes, and snippets.

@deandob
Created February 26, 2014 22:31
Show Gist options
  • Save deandob/9240090 to your computer and use it in GitHub Desktop.
Save deandob/9240090 to your computer and use it in GitHub Desktop.
Node.JS function to remux mp4/h.264 video from an IP camera to a HTML5 video tag using FFMPEG
// Live video stream management for HTML5 video. Uses FFMPEG to connect to H.264 camera stream,
// Camera stream is remuxed to a MP4 stream for HTML5 video compatibility and segments are recorded for later playback
var liveStream = function (req, resp) { // handle each client request by instantiating a new FFMPEG instance
// For live streaming, create a fragmented MP4 file with empty moov (no seeking possible).
var reqUrl = url.parse(req.url, true)
var cameraName = typeof reqUrl.pathname === "string" ? reqUrl.pathname.substring(1) : undefined;
if (cameraName) {
try {
cameraName = decodeURIComponent(cameraName);
} catch (exception) {
console.log("Live Camera Streamer bad request received - " + reqUrl); // Can throw URI malformed exception.
return false;
}
} else {
console.log("Live Camera Streamer - incorrect camera requested " + cameraName); // Can throw URI malformed exception.
return false;
}
console.log("Client connection made to live Camera Streamer requesting camera: " + cameraName)
resp.writeHead(200, {
//'Transfer-Encoding': 'binary'
"Connection": "keep-alive"
, "Content-Type": "video/mp4"
//, 'Content-Length': chunksize // ends after all bytes delivered
, "Accept-Ranges": "bytes" // Helps Chrome
});
for (var cam in cameras) {
if (cameraName.toLowerCase() === cameras[cam].name.toLowerCase()) {
if (!cameras[cam].liveStarted) {
cameras[cam].liveffmpeg = child_process.spawn("ffmpeg", [
"-rtsp_transport", "tcp", "-i", cameras[cam].rtsp, "-vcodec", "copy", "-f", "mp4", "-movflags", "frag_keyframe+empty_moov",
"-reset_timestamps", "1", "-vsync", "1","-flags", "global_header", "-bsf:v", "dump_extra", "-y", "-" // output to stdout
], {detached: false});
cameras[cam].liveStarted = true;
cameras[cam].liveffmpeg.stdout.pipe(resp);
cameras[cam].liveffmpeg.stdout.on("data",function(data) {
});
cameras[cam].liveffmpeg.stderr.on("data", function (data) {
console.log(cameras[cam].name + " -> " + data);
});
cameras[cam].liveffmpeg.on("exit", function (code) {
console.log(cameras[cam].name + " live FFMPEG terminated with code " + code);
});
cameras[cam].liveffmpeg.on("error", function (e) {
console.log(cameras[cam].name + " live FFMPEG system error: " + e);
});
}
break; // Keep cam variable active with the selected cam number
}
}
if (cameras[cam].liveStarted === false) {
// Didn't select a camera
}
req.on("close", function () {
shutStream("closed")
})
req.on("end", function () {
shutStream("ended")
});
function shutStream(event) {
//TODO: Stream is only shut when the browser has exited, so switching screens in the client app does not kill the session
console.log("Live streaming connection to client has " + event)
if (typeof cameras[cam].liveffmpeg !== "undefined") {
cameras[cam].liveffmpeg.kill();
cameras[cam].liveStarted = false;
}
}
return true
}
@halton
Copy link

halton commented Sep 17, 2014

The code should not work well, note the line for (var cam in cameras), but there is no place to define the cameras array, thus the essentiel code in that loop won't work.

@dbussert
Copy link

I used this code to create a working test harness, and it works with video.js in Chrome and FF, but IE11 will not play back the video. It downloads the beginning and then just quits out.

I uploaded my edits to the gist @ https://gist.github.com/dbussert/0cf0476b15ab45e0851d/6b3d6f049bd9449ac82f6e8f3df488620f637ddb

@Globik
Copy link

Globik commented Jan 22, 2016

Here must be stack of technologies. Node-rtsp-stream via net module or gstreamer with his rtsp server, webrtc gateway, binary.js socket and so on.

@a9595776
Copy link

a9595776 commented Feb 2, 2016

HI
when I use safari ,the liveServer will be broken, but IE10、Firefox、chrome are no problem, I don't know why safari not support?
thanks~

@atomictom
Copy link

For anyone looking to use this, removing the '-bsf:v dump_extra' option fixed the video for me for some reason.

@tronar
Copy link

tronar commented Jan 8, 2019

You may use something like:

const express = require('express')
const url = require('url');
const child_process = require('child_process');

const app = express()
const port = 3601
const cameras = [ {name: "cam1", rtsp: "rtsp://10.0.0.121/axis-media/media.amp", liveStarted: false} ];

app.get('/', (req, res) => liveStream(req, res))
app.listen(port, () => console.log(Server up on port ${port}))

In front of the code to use it with node.

Works for me, but video is jerky.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment