Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HLS Streaming using node JS

I'm trying to stream HLS content using node.js. And somehow it is not working. It'll be of great help if someone helps me out.

Problem:- Trying to serve HLS content from node.js (not live stream, but a set of .ts files and .m3u8 playlist, or in other words VOD content)

Folder Structure

stream_test
|--- app.js
|--- node_modules
|--- streamcontent
        |--- test.m3u8
        |--- segment0.ts
        |--- segment1.ts
        .
        .
        .
        |--- segment127.ts

My app.js looks like this

var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs');
var mimeTypes = {
    "html": "text/html",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "png": "image/png",
    "js": "text/javascript",
    "css": "text/css",
    "ts": "video/MP2T",
    "m3u8": "application/vnd.apple.mpegurl"};

http.createServer(function(req, res) {
    var uri = url.parse(req.url).pathname;
    var filename = path.join(process.cwd(), unescape(uri));
    var stats;

    console.log('filename '+filename);

    try {
        stats = fs.lstatSync(filename); // throws if path doesn't exist
    } catch (e) {
        res.writeHead(404, {'Content-Type': 'text/plain'});
        res.write('404 Not Found\n');
        res.end();
        return;
    }


    if (stats.isFile()) {
        // path exists, is a file
        var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
        res.writeHead(200, {'Content-Type': mimeType} );

        var fileStream = fs.createReadStream(filename);
        fileStream.pipe(res);
    } else if (stats.isDirectory()) {
        // path exists, is a directory
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.write('Index of '+uri+'\n');
        res.write('TODO, show index?\n');
        res.end();
    } else {
        // Symbolic link, other?
        // TODO: follow symlinks?  security?
        res.writeHead(500, {'Content-Type': 'text/plain'});
        res.write('500 Internal server error\n');
        res.end();
    }

}).listen(8000);

The test.m3u8 looks like this

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:19
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:12.595922,
segment0.ts
.
.
.

I used ffmpeg to create the segments and palylist

ffmpeg -i video-a.mp4  -c:a libmp3lame -ar 48000 -ab 64k  -c:v libx264   -b:v 128k -flags -global_header -map 0 -f segment  -segment_list test.m3u8 -segment_time 30 -segment_format mpegts segment_%05d.ts

Test Scenraio:- Works fine if served from Apache, does not if served from node.

Test Tool:- VNC Player

like image 559
Tirtha Avatar asked Feb 19 '14 10:02

Tirtha


People also ask

Can I use HLS library in Node JS?

You can safely require this library in Node and absolutely nothing will happen. A dummy object is exported so that requiring the library does not throw an error. HLS.js is not instantiable in Node.js. See #1841 for more details. The dev server will host files on port 8000. Once started, the demo can be found running at http://localhost:8000/demo/.

What is HLS JS?

Failed to load latest commit information. HLS.js is a JavaScript library that implements an HTTP Live Streaming client. It relies on HTML5 video and MediaSource Extensions for playback. It works by transmuxing MPEG-2 Transport Stream and AAC/MP3 streams into ISO BMFF (MP4) fragments.

Why can’t my browser play HLS streams?

When a platform has neither MediaSource nor native HLS support, the browser cannot play HLS. Keep in mind that if the intention is to support HLS on multiple platforms, beyond those compatible with HLS.js, the HLS streams need to strictly follow the specifications of RFC8216, especially if apps, smart TVs, and set-top boxes are to be supported.

What is the path to the HLS file?

The main HLS file is the .m3u8 file, and the URL that will be given to the streaming client will be the path to this file. This .m3u8 metadata file tells the client where to find each data (.ts) file.


1 Answers

With the idea from Brad, I was able to do this using express.static. Here goes the solution.

The app.js is changed like this

var express = require('express');
var app = express();
var path = require('path');

app.use(express.static(path.join(__dirname,'streamcontent')));

app.listen(8000);
console.log('Listening on Port 8000');

and the .m3u8 playlist changed to this

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:19
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:12.595922,
http://localhost:8000/segment0.ts
#EXTINF:10.135133,
http://localhost:8000/segment1.ts
#EXTINF:11.511511,
http://localhost:8000/segment2.ts

And thats it. Voila !!!

like image 138
Tirtha Avatar answered Oct 14 '22 09:10

Tirtha