10

I have a Node.js process which outputs a video stream into my Node.js app.

On the client end, there is a <video> tag. I would like to stream the video from Node.js into the src attribute of the video tag. My previous experience tells me that we must use the blob object for this. However, I'm not a hundred percent certain how and why I would use it.

Another possible solution I'm thinking of is to create some sort of a temporary file on my server, then write the stream to that file, then serve that file as the source for the video. However, that doesn't seem intuitive. I was wondering, then, if there is a more established solution for an issue like this.

sg.cc
  • 1,726
  • 19
  • 41
  • making a file, even a temp one, isn't that bad of a solution and would let you parlay the full http headache to something pre-written like apache that supports `Range` headers; manual http implementation of video serving can be tricky... – dandavis Mar 29 '16 at 03:30
  • @dandavis, is it possible to write the file in such a way that it can be immediately served (even if not fully written) and played back on the client side? – sg.cc Mar 29 '16 at 03:35
  • yes, that's possible, however most high-level "file servers" (and such tools as express) typically transmit the size of the file in a Content-Length header that would instruct the video tag to stop loading future frames. look into Http Live Stream, which is basically an organized manner of writing small video clips, streaming an index of clips, and stitching the clips back together seamlessly. there are other more turn-key approaches and proprietary solutions, but HLS is the "easy" free one. – dandavis Mar 29 '16 at 03:39
  • 1
    I've been curious about whether node is a feasible component for this type of solution; since it's single-threaded by nature I've always questioned whether it could handle multiple streams or not – theaccordance May 26 '16 at 13:48
  • Yep, and my bounty comment reflects this. Node handles most of the work for us for now, but there's no reason I couldn't use `childProcess` to spawn something else to handle video streaming. – sg.cc May 26 '16 at 13:48
  • 1
    Are you delivering a MP4 container with H264/AAC? – lapinkoira May 26 '16 at 14:00
  • 1
    This should help you understand Readable streams a bit: https://github.com/ndugger/blackbeard/blob/master/src/media.js -- If you're still struggling, let me know, and I'll write out a proper answer. – ndugger May 31 '16 at 19:44
  • I would say working off an established library might help or it could hinder you depending on the implementation and the requirements needed. You could look at an npm package called ffmpeg-stream. It's an API client that will work with ffmpeg video/audio encoding/decoding projects. it has lots and lots why re-invent the wheel? (unless requirements are needed specifically) just make sure you install ffmpeg into the machine and set the variable path first. [ffmpeg website](https://ffmpeg.org/about.html) and the [npm package](https://www.npmjs.com/package/ffmpeg-stream) – Andrei Jun 01 '16 at 14:33

3 Answers3

4

m3u8 format is commonly used for streaming. Video streaming/transcoding is a resource intensive thing. I would suggest you to use third party service to do so, if you have that option.

atinder
  • 2,080
  • 13
  • 15
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/12541655) – ankitr Jun 01 '16 at 10:36
  • 1
    being quite familiar with stackoverflow, so I know link only answers are not good. First thing is link is to wikipedia which hardly changes. Second I have written what was known to me apart from the link. Third thing consider adding more detail in your comment if you know more about it. – atinder Jun 01 '16 at 16:29
3

Probably you might want to look at the following options:

  1. BinaryJS. It's bidrectional realtime binary data transfer tool based on websockets.

  2. JSMpeg stream-server (in case of capturing) from Phoboslab guys. All you need to do is start ffmpeg and point it to the domain and port where the nodejs script is running. More info you can find here.

  3. Pipe a stream directly. Good answer is posted here. In few words you just need to specify Accept-Ranges, Content-Range, Content-Length and Content-Type headers, then create relevant Read stream (with start and end options) and pipe it to the response object.

Community
  • 1
  • 1
oleh.meleshko
  • 4,675
  • 2
  • 27
  • 40
2

I've actually tried this at a hackathon two weeks ago. I ended up barely getting this flv stream to work, which I've posted below. My intent was to make a library to automate much of the processes this would entail.

As you can see, I've opened a new port on the server to handle the separate stream of data flowing to the client. This is reflected in the client's src tag.

THREE THINGS YOU NEED:

  1. This Linux version of ffmpeg.

  2. Flowplayer on the js side.

  3. npm fluent-ffmpeg

    // StreamServer.js

    var express = require('express'),
      app = express(),
      ffmpeg = require('fluent-ffmpeg');
    
    module.exports = function () {
        app.stream(req, res)
        {
            res.contentType('flv');
            // make sure you set the correct path to your video file storage 
            var pathToMovie = '/path/to/storage/' + req.params.filename;
            var proc = ffmpeg(pathToMovie)
              // use the 'flashvideo' preset (located in /lib/presets/flashvideo.js) 
              .preset('flashvideo')
              // setup event handlers 
              .on('end', function () {
                  console.log('file has been converted succesfully');
              })
              .on('error', function (err) {
                  console.log('an error happened: ' + err.message);
              })
              // save to stream 
              .pipe(res, { end: true });
    
        };
    
    }
    

    //routes.js

    'use strict';
    var stream = require('../controllers/streaming.server.controller'),
     streamServer = require('../controllers/StreamServer.js'),
    express = require('express');
    

    //streaming.server.controller.js

    module.exports = function (app) {
        app.get('/api/stream', function (req, res) {
            streamServer.stream(req, res);
        });
    };
    
    var path = require('path'),
     express = require('express'),
     app = express(),
     routes = require('../routes/routes.js')(app),
     ffmpeg = require('fluent-ffmpeg');
    
    app.listen(4000);
    

EDIT: Client side part:

https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/tree/master/examples/flowplayer

<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <script type="text/javascript" src="/flowplayer.min.js"></script>
        <title>node-fluent-ffmpeg</title>
    </head>
    <body>

        <!-- this A tag is where your Flowplayer will be placed. it can be anywhere -->
        <a  
             href="http://localhost:4000/api/stream"
             style="display:block;width:520px;height:330px"  
             id="player"> 
        </a> 

        <!-- this will install flowplayer inside previous A- tag. -->
        <script>
            flowplayer("player", "/flowplayer.swf");
        </script>
    </body>
</html>

(Just change the href attribute)

Beshoy Hanna
  • 611
  • 2
  • 9
  • 29