Gerçekten, fdefler gerçek zamanlı çıktısını node.js kullanarak bir HTML5 istemcisine aktarmanın en iyi yolunu anlamaya çalışırken takılıp kaldım. farklı kombinasyonları denemek için uzun saatler geçirdim.
Benim kullanım durumum:
1) IP video kamera RTSP H.264 akışı, FFMPEG tarafından alınır ve STDOUT'a çıkış olarak, düğümdeki aşağıdaki FFMPEG ayarları kullanılarak bir mp4 kabına yeniden atılır. Bu yalnızca ilk istemci bağlantısında çalıştırılır, böylece kısmi içerik istekleri FFMPEG'i yeniden oluşturmaya çalışmaz.
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) STDOUT'u yakalamak ve istemci isteği üzerine istemciye geri göndermek için http sunucusunu kullanıyorum. İstemci ilk bağlandığında yukarıdaki FFMPEG komut satırını oluşturdum ve STDOUT akışını HTTP yanıtına aktarıyorum.
liveFFMPEG.stdout.pipe(resp);
Ben de HTTP yanıtı FFMPEG veri yazmak için stream olayı kullandım ama hiçbir fark etmez
xliveFFMPEG.stdout.on("data",function(data) {
resp.write(data);
}
Aşağıdaki HTTP üstbilgisini kullanıyorum (önceden kaydedilmiş dosyaları yürütürken de kullanılıyor ve çalışıyor)
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) İstemci HTML5 video etiketlerini kullanmalıdır.
Daha önce yukarıdaki FFMPEG komut satırı (ancak STDOUT yerine bir dosyaya kaydedilmiş) bir video dosyası HTML5 istemcisine oynatma akış (206 HTTP kısmi içeriği ile fs.createReadStream kullanarak) ile hiçbir sorunum yok, bu yüzden FFMPEG akışı biliyorum doğrudur ve HTTP düğüm sunucusuna bağlanırken VLC'de video canlı akışını doğru bir şekilde görebiliyorum.
Ancak HTTP düğümü üzerinden FFMPEG'den canlı yayın yapmaya çalışmak, istemci bir kareyi görüntüleyip durduğundan çok daha zor görünüyor. Sorunun, HTTP bağlantısını HTML5 video istemcisi ile uyumlu olacak şekilde ayarlamamasından şüpheleniyorum. HTTP 206 (kısmi içerik) ve 200 yanıt kullanma gibi çeşitli şeyler denedim, veriyi bir ara belleğe koyarak sonra şanssız akışla denedim, bu yüzden bunu doğru ayarladığımdan emin olmak için ilk ilkelere geri dönmeliyim yol.
İşte bunun nasıl çalışması gerektiği konusundaki anlayışım, lütfen yanılıyorsam beni düzeltin:
1) FFMPEG, çıktıyı parçalayacak ve boş bir moov (FFMPEG frag_keyframe ve empty_moov mov bayrakları) kullanacak şekilde ayarlanmalıdır. Bu, istemcinin genellikle dosyanın sonunda olan ve akış sırasında ilgili olmayan (dosya sonu yok) moov atomunu kullanmadığı, ancak benim kullanım durumum için uygun olan hiçbir arama mümkün olmadığı anlamına gelir.
2) MP4 parçaları ve boş MOOV kullansam da, hala HTTP kısmi içerik kullanmam gerekiyor, çünkü HTML5 oynatıcı oynatılmadan önce tüm akış indirilene kadar bekleyecek, bu da canlı akışla hiç bitmiyor, bu yüzden işlenemez.
3) STDOUT akışını neden HTTP yanıtına çevirmenin canlı akış sırasında işe yaramadığını anlamıyorum, ancak bir dosyaya kaydedersem bu dosyayı benzer kodu kullanarak HTML5 istemcilerine kolayca aktarabilirim. Belki FFMPEG spawn'ın başlaması, IP kameraya bağlanması ve düğüme parçalar göndermesi ve düğüm veri olaylarının da düzensiz olması bir zamanlama sorunudur. Ancak, bytestream bir dosyaya kaydetmeyle tamamen aynı olmalıdır ve HTTP gecikmeleri karşılayabilmelidir.
4) FFMPEG tarafından oluşturulan bir MP4 dosyasını kameradan aktarırken HTTP istemcisinden ağ günlüğünü kontrol ederken, 3 istemci isteği olduğunu görüyorum: HTTP sunucusunun yaklaşık 40Kb, ardından bir kısmi döndürdüğü video için genel bir GET isteği Dosyanın son 10K'sı için bir bayt aralığına sahip içerik isteği, daha sonra ortadaki bitler için son bir istek yüklenmedi. HTML5 istemcisi ilk yanıtı aldıktan sonra dosyanın MP4 MOOV atomunu yüklemek için son bölümünü istiyor? Bu durumda, MOOV dosyası ve dosyanın sonu olmadığı için akış için çalışmaz.
5) Canlı akış gerçekleştirmeye çalışırken ağ günlüğünü kontrol ederken, yalnızca yaklaşık 200 bayt alınan iptal edilmiş bir ilk istek alıyorum, sonra yeniden 200 bayt ve yalnızca 2K uzunluğunda üçüncü bir istek ile iptal edildi. HTML5 istemcisinin neden bytestream'in kaydedilmiş bir dosyadan akış yaparken başarıyla kullanabildiğim ile aynı olduğunu neden iptal edeceğini anlamıyorum. Ayrıca düğüm FFMPEG akışının geri kalanını istemciye göndermiyor gibi görünüyor, ancak FFMPEG düğümü HTTP sunucusuna ulaşırken .on olay yordamındaki FFMPEG verilerini görebiliyorum.
6) Her ne kadar STDOUT akışının HTTP yanıt arabelleğine bağlanmasının işe yarayacağını düşünmeme rağmen, HTTP kısmi içerik istemcisinin bir dosyayı (başarıyla) okuduğunda olduğu gibi düzgün çalışmasına izin verecek bir ara arabellek ve akış oluşturmam gerekiyor mu? ? Bu benim sorunlarımın ana nedeni olduğunu düşünüyorum, ancak Düğümde en iyi nasıl ayarlayacağından tam olarak emin değilim. Ve dosya sonu olmadığı için dosyanın sonundaki veriler için bir istemci isteğinin nasıl işleneceğini bilmiyorum.
7) 206 kısmi içerik isteğini ele almaya çalışırken yanlış yolda mıyım ve bu normal 200 HTTP yanıtıyla mı çalışmalı? HTTP 200 yanıtları VLC için iyi çalışıyor, bu yüzden HTML5 video istemcisinin yalnızca kısmi içerik istekleriyle çalışacağından şüpheleniyorum?
Ben hala bu şeyleri öğrenmek gibi bu sorunun çeşitli katmanları (FFMPEG, düğüm, akış, HTTP, HTML5 video) ile çalışmak zor bu yüzden herhangi bir işaretçiler büyük takdir edilecektir. Bu sitede ve internette saatlerce araştırma yaptım ve düğümde gerçek zamanlı akış yapabilen kimseyle karşılaşmadım ama ilk olamıyorum ve bunun bir şekilde çalışabilmesi gerektiğini düşünüyorum (bir şekilde !).
Content-Type
kafanın içinde? Yığın kodlama mı kullanıyorsunuz? Ben buradan başlardım. Ayrıca, HTML5 akış için gerekli işlevselliği sağlamaz, buradan daha fazla bilgi edinebilirsiniz . Büyük olasılıkla iyi desteklenmediğini düşündüğünüz için video akışını kendi yöntemlerinizi kullanarak tamponlamak ve oynatmak için bir yol uygulamanız gerekecektir ( buraya bakın ). Ayrıca Google'da MediaSource API'sına gidin.