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.