219 votes

La meilleure approche en temps réel la diffusion http en vidéo HTML5 client

Tous,

Je suis vraiment coincé à essayer de comprendre la meilleure façon de diffuser en temps réel de la sortie de ffmpeg pour un client à l'aide de HTML5 node.js comme il y a un certain nombre de variables en jeu et je n'ai pas beaucoup d'expérience dans ce domaine, ayant passé de nombreuses heures à essayer différentes combinaisons.

Mon cas d'utilisation est:

1) IP de la caméra vidéo RTSP H. 264 flux est ramassé par FFMPEG et remuxed dans un conteneur mp4 à l'aide de la suite de FFMPEG paramètres du nœud, sortie vers STDOUT. Ce n'est exécutée que sur la première connexion du client, de sorte que partielle, du contenu des demandes de ne pas essayer de frayer FFMPEG de nouveau.

liveFFMPEG = child_process.spawn("ffmpeg", [
                "-i", "rtsp://admin:12345@192.168.1.234:554" , "-vcodec", "copy", "-f",
                "mp4", "-reset_timestamps", "1", "-movflags", "frag_keyframe+empty_moov", 
                "-"   // output to stdout
                ],  {detached: false});

2) j'utilise le nœud de serveur http pour capturer la sortie standard (STDOUT) et le flux de retour au client au moment de la requête d'un client. Lorsque le client se connecte tout d'abord je spawn au-dessus de FFMPEG en ligne de commande de rediriger la sortie standard (STDOUT) flux de la réponse HTTP.

liveFFMPEG.stdout.pipe(resp);

J'ai également utilisé le flux d'événements pour écrire le FFMPEG données de la réponse HTTP, mais ne fait aucune différence

xliveFFMPEG.stdout.on("data",function(data) {
        resp.write(data);
}

J'utilise l'en-tête HTTP suivant (qui est également utilisé et de travail lors de la diffusion de pré-enregistrés des fichiers)

var total = 999999999         // fake a large file
var partialstart = 0
var partialend = total - 1

if (range !== undefined) {
    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;   // fake a large file if no range reques 

var chunksize = (end-start)+1; 

resp.writeHead(206, {
                  'Transfer-Encoding': 'chunked'
                 , 'Content-Type': 'video/mp4'
                 , 'Content-Length': chunksize // large size to fake a file
                 , 'Accept-Ranges': 'bytes ' + start + "-" + end + "/" + total
});

3) Le client doit utiliser les balises video HTML5.

Je n'ai pas de problèmes avec la lecture en streaming (à l'aide de fs.createReadStream avec 206 HTTP partielle, du contenu) de l'HTML5 client un fichier vidéo enregistré précédemment avec le ci-dessus FFMPEG en ligne de commande (mais enregistré dans un fichier au lieu de la sortie standard STDOUT), donc je sais que le FFMPEG flux est correct, et je peux même voir correctement la vidéo en direct streaming à VLC lors de la connexion au HTTP nœud de serveur.

Cependant en essayant de diffuser en direct à partir de FFMPEG par nœud HTTP semble être beaucoup plus difficile que le client affiche une image puis de s'arrêter. Je soupçonne que le problème est que je ne suis pas la configuration de la connexion HTTP pour être compatible avec le HTML5 video client. J'ai essayé une variété de choses comme l'utilisation de HTTP 206 (contenu partiel) et de 200 réponses, de mettre les données dans une mémoire tampon puis streaming avec pas de chance, j'ai donc besoin de revenir à des principes pour s'assurer que je suis cette mise en place de la bonne façon.

Voici ma compréhension de la façon dont cela devrait fonctionner, s'il vous plaît corrigez-moi si je me trompe:

1) FFMPEG doit être paramétré pour fragment de la production et de l'utilisation d'un vide moov (FFMPEG frag_keyframe et empty_moov mov drapeaux). Cela signifie que le client n'utilise pas le moov atom qui est généralement à la fin du fichier, ce qui n'est pas pertinente lorsque la diffusion en continu (pas de fin de fichier), mais pas de recherche possible, ce qui est bien pour mon cas d'utilisation.

2) Même si je les utilise MP4 fragments et vide MOOV, j'ai encore à l'utilisation de HTTP partielle, du contenu, comme le lecteur HTML5 va attendre jusqu'à ce que la totalité du flux de données est téléchargé avant de jouer, avec un flux en direct de n'en finit pas, donc impraticable.

3) je ne comprends pas pourquoi la tuyauterie de la sortie standard (STDOUT) flux de la réponse HTTP ne fonctionne pas lors de la diffusion en direct mais si je l'ai enregistrer dans un fichier que je peux diffuser ce fichier facilement HTML5 clients à l'aide d'un code similaire. C'est peut-être un problème de timing qu'il faut un deuxième pour le FFMPEG spawn pour commencer, connectez l'appareil-photo d'IP et d'envoyer des morceaux de nœud et le nœud de données des événements sont irrégulières. Cependant, le bytestream doit être exactement le même que l'enregistrement dans un fichier, et HTTP doivent être en mesure de répondre à des retards.

4) Lors de la vérification de l'historique du réseau à partir de l'adresse HTTP du client lors de la diffusion d'un fichier MP4 créé par FFMPEG de la caméra, je vois il y a 3 demandes des clients, par Une requête GET pour la vidéo, laquelle le serveur HTTP renvoie à environ 40 ko, puis une partie du contenu de la demande avec une plage d'octets pour le dernier 10K du fichier, puis une finale demande pour les bits dans le milieu ne sont pas chargés. Peut-être que le HTML5 client une fois qu'il reçoit le premier réflexe est de demander pour la dernière partie du fichier à charger le MP4 MOOV atom? Si c'est le cas, il ne fonctionnera pas pour le streaming, comme il n'existe pas de fichier MOOV et pas à la fin du fichier.

5) Lors de la vérification de l'historique du réseau lors de la tentative de flux en direct, je reçois un avorté demande initiale avec seulement environ 200 octets reçus, puis un re-demande de nouveau abandonnée avec 200 octets et une troisième demande, qui est à seulement 2K long. Je ne comprends pas pourquoi le HTML5 client d'annuler la demande de la bytestream est exactement la même que je peux utiliser avec succès lors de la diffusion à partir d'un fichier enregistré. Il semble aussi que le nœud n'est pas d'envoyer le reste de la FFMPEG flux de données vers le client, mais je peux voir le FFMPEG données dans la .sur événement de routine de sorte qu'il est arriver à la FFMPEG nœud de serveur HTTP.

6) Bien que je pense de la tuyauterie de la sortie standard (STDOUT) flux de la réponse HTTP tampon devrait fonctionner, dois-je construire un tampon intermédiaire et les flux qui va permettre à l'adresse HTTP partielle, du contenu des demandes du client pour bien travailler comme il le fait lorsqu'il (avec succès) lit un fichier? Je pense que c'est la principale raison de mes problèmes, cependant je ne suis pas exactement sûr de Nœud à la meilleure manière de les configurer. Et je ne sais pas comment gérer un client demande pour les données à la fin du fichier, comme il n'y a pas de fin de fichier.

7) Suis-je sur la mauvaise piste à essayer de gérer 206 partielle, du contenu des demandes, et si cela fonctionne avec la normale de 200 réponses HTTP? HTTP 200 réponses fonctionne très bien pour VLC je crois que la vidéo HTML5 client ne fonctionne qu'avec partielle, du contenu des demandes?

Comme je suis encore à apprendre ce genre de choses c'est difficile de travailler à travers les différentes couches de ce problème (FFMPEG, nœud, streaming, HTTP, la vidéo HTML5) de sorte que toute les pointeurs seront grandement appréciés. J'ai passé des heures à chercher sur ce site et sur le net, et je n'ai pas rencontré quelqu'un qui a été capable de faire de la diffusion en temps réel dans le nœud, mais je ne peux pas être le premier, et je pense que cela devrait être en mesure de travailler (en quelque sorte!).

Merci.

213voto

szatmary Points 5478

Il existe de nombreuses raisons pourquoi la vidéo et, plus précisément, de la vidéo en direct est très difficile. Je vais les aborder ici un à la fois. (Veuillez noter que la question d'origine spécifié que la vidéo HTML5 est une exigence, mais le demandeur a déclaré Flash est possible dans les commentaires. Donc, immédiatement, cette question est trompeuse)

D'abord, je vais reformuler: IL n'y a PAS de SUPPORT OFFICIEL POUR le STREAMING en DIRECT SUR HTML5. Il y a des hacks, mais votre kilométrage peut varier.

Ensuite, vous devez comprendre que la VOD et de la vidéo en direct sont très différentes. Oui, ils sont à la fois de la vidéo, mais les problèmes sont différents, d'où les formats sont différents. Par exemple, si l'horloge de votre ordinateur est 1% plus vite qu'il ne le devrait, vous ne verrez pas sur un service de VOD. Avec la vidéo en direct, vous serez essayant de jouer la vidéo avant qu'elle arrive. Si vous voulez vous joindre a un flux vidéo en direct en cours, il faut disposer des données nécessaires pour initialiser le décodeur, donc il doit être répété dans le ruisseau, ou envoyés à l'extérieur de la bande. Avec la VOD, vous pouvez lire le début du fichier cherchent à quel point vous le souhaitez.

Maintenant, nous allons creuser un peu.

Plates-formes:

  • iOS
  • PC
  • Mac
  • Android

Codecs:

  • vp8/9
  • h.264
  • la thora (vp3)

Commune de méthodes de Livraison pour la vidéo en direct dans les navigateurs:

  • DASH (HTTP)
  • HLS (HTTP)
  • flash (RTMP)
  • flash (HDS)

Commune de méthodes de Livraison pour la VOD dans les navigateurs:

  • DASH (HTTP Streaming)
  • HLS (HTTP Streaming)
  • flash (RTMP)
  • flash HTTP (Streaming)
  • MP4 (HTTP pseudo-streaming)
  • Je ne vais pas parler de MKV et OOG parce que je ne connais pas très bien.

balise vidéo html5:

  • MP4
  • webm
  • ogg

Permet de regarder qui des navigateurs prennent en charge que les formats

Safari:

  • HLS (iOS et mac uniquement)
  • h.264
  • MP4

Firefox

  • Tableau de bord (via MMS mais pas d'h.264)
  • h.264 via Flash seulement!
  • VP9
  • MP4
  • OGG
  • Webm

IE

  • Flash
  • Tableau de bord (via le MSE)
  • h.264
  • MP4

Chrome

  • Flash
  • Tableau de bord (via le MSE)
  • h.264
  • VP9
  • MP4
  • webm
  • ogg

MP4 ne peuvent pas être utilisés pour la diffusion en direct (REMARQUE: le tableau de bord est un sur-ensemble de MP4, afin de ne pas se confondre avec que). MP4 est cassé en deux morceaux: moov et mdat. mdat contient les données audio brutes de données vidéo. Mais il n'est pas indexé, sans la moov, c'est inutile. Le moov contient un index de tous les données dans le mdat. Mais en raison de son format, il ne peut pas être "aplati" jusqu'à ce que les horodateurs et la taille de CHAQUE image est connue. Il peut être possible de construire un moov que les "bobards" les tailles de cadre, mais il est très inutile de la bande passante sage.

Donc, si vous souhaitez vous faire livrer partout, nous avons besoin de trouver le plus petit dénominateur commun. Vous verrez il n'y a pas de LCD ici sans avoir recours à flash exemple:

  • iOS ne supporte h.264 vidéo. et il ne supporte que le protocole HLS pour vivre.
  • Firefox ne prend pas en charge h.264 à tous, sauf si vous utilisez flash
  • Le Flash ne fonctionne pas sous iOS

La chose la plus proche d'un écran LCD à l'aide de TLS pour obtenir vos utilisateurs iOS, et flash pour tout le monde. Mon préféré est de coder HLS, puis utiliser le flash à jouer HLS pour tout le monde. Vous pouvez jouer HLS en flash via le JW player 6, (ou écrire votre propre HLS au format FLV en AS3 comme je l'ai fait)

Bientôt, la façon la plus courante pour ce faire sera HLS sur iOS/Mac et le tableau de bord via MSE partout ailleurs (c'est Ce que Netflix va faire bientôt). Mais nous sommes toujours en attente pour tout le monde à niveau de leurs navigateurs. Vous aurez aussi probablement besoin d'un DASH/VP9 pour Firefox (je sais à propos de open264; elle le suce. Il ne peut pas faire de la vidéo dans les principaux ou de haut profil. Il est actuellement inutile).

76voto

deandob Points 764

Merci à tous en particulier szatmary que c'est une question complexe et comporte de nombreuses couches, toutes les qui ont à travailler avant de pouvoir diffuser de la vidéo en direct. Pour préciser ma question d'origine de l'usage de la vidéo et HTML5 vs flash - mon cas d'utilisation a une forte préférence pour le HTML5, car il est générique, facile à mettre en œuvre sur le client et l'avenir. Flash est de loin meilleur, donc permet de coller avec HTML5 pour cette question.

J'ai beaucoup appris grâce à cet exercice, et acceptez la diffusion en direct est beaucoup plus difficile que la VOD (qui fonctionne bien avec la vidéo HTML5). Mais je n'en obtenir que cela fonctionne de manière satisfaisante pour mon cas d'utilisation, et la solution a fonctionné très simple, après avoir poursuivi des options plus complexes comme la MSE, flash, d'élaborer des schémas de mise en mémoire tampon dans le Nœud. Le problème était que FFMPEG était en train de corrompre la fragmentation MP4 et j'ai dû régler les paramètres FFMPEG, et la norme nœud stream pipe redirection sur http que j'ai utilisé à l'origine, était tout ce qui était nécessaire.

En MP4, il est un "morcellement" l'option qui rompt le mp4 en beaucoup plus petits fragments qui a son propre index et rend le mp4 live streaming option viable. Mais pas possible de chercher en arrière dans le flux (OK pour mon cas d'utilisation), et, plus tard, des versions de FFMPEG soutien de la fragmentation.

Remarque le temps peut être un problème, et avec ma solution, j'ai un décalage entre 2 et 6 secondes causée par une combinaison de la multiplexage (FFMPEG a à recevoir le flux en direct, remultiplexer il alors de l'envoyer au nœud pour servir sur HTTP). Pas beaucoup peut être fait à ce sujet, cependant dans google Chrome, la vidéo ne tenter de rattraper autant que possible ce qui rend la vidéo un peu nerveux, mais plus de courant que IE11 (mon préféré client).

Plutôt que d'expliquer comment fonctionne le code dans ce post, découvrez l'ESSENTIEL avec des commentaires (le code du client n'est pas inclus, c'est un standard de la balise vidéo HTML5 avec le nœud serveur http dans l'adresse). L'ESSENTIEL est ici: https://gist.github.com/deandob/9240090

Je n'ai pas été en mesure de trouver des exemples de ce cas d'utilisation, donc j'espère que l'explication ci-dessus et le code qui aide les autres, surtout que j'ai appris tellement de choses sur ce site et à me considère encore comme un débutant!

Bien que ce soit la réponse à ma question, j'ai sélectionné szatmary de la réponse que l'on a accepté, comme il est de la plus complète.

15voto

Michael Romanenko Points 363

Jetez un oeil à JSMPEG projet. Il y a une grande idée mise en œuvre - pour décoder le MPEG dans le navigateur à l'aide de JavaScript. D'octets à partir de l'encodeur (FFMPEG, par exemple) peuvent être transférés au navigateur d'utiliser les WebSockets ou Flash, par exemple. Si la communauté va rattraper, je pense, ce sera le meilleur HTML5 vidéo en direct streaming solution pour l'instant.

3voto

szatmary Points 5478

C'est une idée fausse très répandue. Il n'y a pas de live support de vidéo HTML5 (sauf pour les HLS sur iOS et Safari pour Mac). Vous pouvez être en mesure de "hack" à l'aide d'un conteneur webm, mais je ne m'attends pas que pour être universellement pris en charge. Ce que vous cherchez est inclus dans le Media Source Extensions, où vous pouvez nourrir les fragments sur le navigateur, un à un. mais vous allez avoir besoin d'écrire du code javascript coté client.

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