46 votes

Streaming vidéo avec HTML 5 via node.js

J'essaie de mettre en place un serveur web qui prendra en charge le streaming vidéo vers une balise vidéo HTML5 en utilisant node.js. Voici mon code jusqu'à présent :

var range = request.headers.range;
var total = file.length;

var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];

var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;

var chunksize = (end-start)+1;

response.writeHead(206, { "Content-Range": "bytes " + start + "-" + end + "/" + total, "Accept-Ranges": "bytes", "Content-Length": chunksize, "Content-Type": type });
response.end(file);

Où "request" représente la requête http, le type est soit "application/ogg" soit "video/ogg" (j'ai essayé les deux) et "file" est le fichier .ogv qui a été lu depuis le système de fichiers. Voici les en-têtes de réponse :

Content-Range   bytes 0-14270463/14270464
Accept-Ranges   bytes
Content-Length   14270464
Connection     keep-alive
Content-Type     video/ogg

J'ai examiné les en-têtes de réponse et ce code semble fonctionner correctement, mais il y a quelques problèmes :

  1. La vidéo semble se charger très lentement pour être sur un réseau local. D'après ce que je peux dire en examinant la réponse avec firebug, le fichier semble être diffusé à environ 150 kb/sec.
  2. La vidéo ne passe pas du tout. Même si j'attends le chargement complet de la vidéo, la balise vidéo HTML 5 affiche un grand "x" au lieu d'une vidéo dans Firefox.

Quelqu'un a-t-il une idée de ce que je peux faire pour que le streaming vidéo fonctionne via node.js ?

Merci !
Chris

3voto

podperson Points 768

J'ai trouvé cette solution qui semble être plus simple et (contrairement à la réponse cochée) fonctionne pour moi. (J'ai essayé d'adapter la solution de coffeescript à la fin de ce fil de discussion et cela a plus ou moins fonctionné une fois que j'ai géré le fait que la demande initiale (pour "bytes=0-") fait tout sauter.

http://elegantcode.com/2011/04/06/taking-baby-steps-with-node-js-pumping-data-between-streams/

Ma mise en œuvre réelle :

function stream_response( res, file_path, content_type ){
    var readStream = fs.createReadStream(file_path);

    readStream.on('data', function(data) {
        var flushed = res.write(data);
        // Pause the read stream when the write stream gets saturated
        console.log( 'streaming data', file_path );
        if(!flushed){
            readStream.pause();
        }
    });

    res.on('drain', function() {
        // Resume the read stream when the write stream gets hungry 
        readStream.resume();
    });

    readStream.on('end', function() {
        res.end();
    });

    readStream.on('error', function(err) {
        console.error('Exception', err, 'while streaming', file_path);
        res.end();
    });

    res.writeHead(200, {'Content-Type': content_type});
}

0 votes

Cela permet de diffuser des médias en continu de manière très satisfaisante ... mais il faudrait qu'il traite les en-têtes des requêtes afin de réagir aux demandes de widgets côté client, comme le saut en avant/en arrière sur le média source ... beau travail.

0voto

Kevin Muchwat Points 351

Si vous utilisez express, mettez ceci dans votre media_server.js ou index.js qui servira le média sur le port 3000.

const express = require('express')
const fs = require('fs')
const path = require('path')
const app = express()

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

app.get('/', function(req, res) {
  res.sendFile(path.join(__dirname + '/index.html'))
})

app.get('/video', function(req, res) {
  const path = 'assets/sample.mp4'// your video path
  const stat = fs.statSync(path)
  const fileSize = stat.size
  const range = req.headers.range

  if (range) {
    const parts = range.replace(/bytes=/, "").split("-")
    const start = parseInt(parts[0], 10)
    const end = parts[1]
      ? parseInt(parts[1], 10)
      : fileSize-1

    const chunksize = (end-start)+1
    const file = fs.createReadStream(path, {start, end})
    const head = {
      'Content-Range': `bytes ${start}-${end}/${fileSize}`,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4',
    }

    res.writeHead(206, head)
    file.pipe(res)
  } else {
    const head = {
      'Content-Length': fileSize,
      'Content-Type': 'video/mp4',
    }
    res.writeHead(200, head)
    fs.createReadStream(path).pipe(res)
  }
})

app.listen(3000, function () {
  console.log('Listening on port 3000!')
})

puis dans votre index.html

<html>
  <head>
    <title>Video stream sample</title>
  </head>
  <body>
    <video id="videoPlayer" controls muted="muted" autoplay> 
      <source src="http://localhost:3000/video" type="video/mp4">
    </video>
  </body>
</html>

0voto

Islem Penywis Points 11

J'ai trouvé ceci codesandbox et cela semble vraiment utile https://codesandbox.io/s/14n6q1yr33

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X