-
-
Save deandob/9240090 to your computer and use it in GitHub Desktop.
// 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 | |
} |
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
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.
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~
For anyone looking to use this, removing the '-bsf:v dump_extra' option fixed the video for me for some reason.
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.
The code should not work well, note the line
for (var cam in cameras)
, but there is no place to define thecameras
array, thus the essentiel code in that loop won't work.