isaac9A
isaac9A

Reputation: 903

Using Nodejs to Serve an MP4 Video File

I am trying to serve a ~52MB mp4 video file from a nodejs server. Attached below is a screenshot of the code used to serve the file.Code used to serve mp4 I have an object of mime types for static file calls which contains the mime type for mp4.

var mimeTypes = { html: 'text/html; charset=utf-8', jpeg: 'image/jpeg', jpg: 'image/jpeg', png: 'image/png', js: 'text/javascript', css: 'text/css', mp4: 'video/mp4' };

However, when I try to navigate to the page in chrome, I get the error:

GET http://localhost:8888/videos/movie.mp4 net::ERR_INCOMPLETE_CHUNKED_ENCODING

Now this same logic (screenshotted above) is used to serve images and css just fine, however it fails miserably when trying to serve the mp4. Looking at the network requests panel in Chrome, I can see that the server responded with a 200 OK status, and served a zero byte file as the video. The range of bytes in the network request also looks suspicious but I don't know enough about HTTP requests to know for sure. Request Request_Abridged

Looking at the stats object (shown below, gotten from fs.lstat), It appears that the file 'knows' how to be split into chunks of 4096 bytes, however I keep getting the incomplete chunked encoding error. I have no antivirus, and tried turning off various settings in Chrome/using another browser but I can't see the video.

{"dev":16777220,"mode":33188,"nlink":1,"uid":501,"gid":20,"rdev":0,"blksize":4096,"ino":1070608,"size":51246445,"blocks":100096,"atime":"2016-06-15T23:06:27.000Z","mtime":"2016-06-15T21:41:00.000Z","ctime":"2016-06-15T21:45:56.000Z"}

Is there a header I am missing? Am I somehow ending the response too early? I'm clueless right now.

Upvotes: 5

Views: 17346

Answers (3)

Vinicius Castro
Vinicius Castro

Reputation: 31

This was enough with me. MP4 has native support for strimming (pseudo streaming). It worked very well for watching videos in the browser via streaming.

res.setHeader('Content-Type', 'video/mp4');

res.status(200).sendFile(full_path, function (err) {
    if (err) { ... } else { ... }
});

Upvotes: 3

isaac9A
isaac9A

Reputation: 903

Fixed using this solution.

```

  if (stats.isFile()) {
    var extension = path.extname(file).split('.').reverse()[0];
    if (extension === 'mp4') {
      // gotta chunk the response if serving an mp4
      var range = req.headers.range;
      var parts = range.replace(/bytes=/, "").split("-");
      var partialstart = parts[0];
      var partialend = parts[1];
      var total = stats.size;
      var start = parseInt(partialstart, 10);
      var end = partialend ? parseInt(partialend, 10) : total - 1;
      var chunksize = (end - start) + 1;
      var mimeType = mimeTypes[extension] || 'text/plain; charset=utf-8';
      res.writeHead(206, {            
        'Content-Range': 'bytes ' + start + '-' + end + '/' + total,
        'Accept-Ranges': 'bytes',
        'Content-Length': chunksize,
        'Content-Type': mimeType
      });
      var fileStream = fs.createReadStream(file, {
          start: start,
          end: end
      });
      fileStream.pipe(res);
      res.on('close', function() {
        console.log('response closed');
        if (res.fileStream) {
            res.fileStream.unpipe(this);
            if (this.fileStream.fd) {
                fs.close(this.fileStream.fd);
            }
        }
      });
    } else {
      var mimeType = mimeTypes[extension] || 'text/plain; charset=utf-8';
      res.writeHead(200, {'Content-Type': mimeType});
      var fileStream = fs.createReadStream(file);
      fileStream.pipe(res);
    }

    return;
  }

```

Upvotes: 2

Martial
Martial

Reputation: 1562

This is what I used for my project.

https://gist.github.com/paolorossi/1993068

hth

Upvotes: 3

Related Questions