Saya benar-benar terjebak mencoba memahami cara terbaik untuk streaming keluaran real time dari ffmpeg ke klien HTML5 menggunakan node.js, karena ada sejumlah variabel yang bermain dan saya tidak memiliki banyak pengalaman di ruang ini, telah menghabiskan banyak waktu untuk mencoba kombinasi yang berbeda.
Kasus penggunaan saya adalah:
1) Aliran kamera video IP RTSP H.264 diambil oleh FFMPEG dan dipasang kembali ke dalam wadah mp4 menggunakan pengaturan FFMPEG berikut dalam node, output ke STDOUT. Ini hanya berjalan pada koneksi klien awal, sehingga permintaan konten parsial tidak mencoba menelurkan FFMPEG lagi.
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) Saya menggunakan server http node untuk menangkap STDOUT dan streaming yang kembali ke klien atas permintaan klien. Ketika klien pertama kali terhubung, saya menelurkan baris perintah FFMPEG di atas kemudian menyalurkan aliran STDOUT ke respons HTTP.
liveFFMPEG.stdout.pipe(resp);
Saya juga menggunakan acara aliran untuk menulis data FFMPEG ke respons HTTP tetapi tidak ada bedanya
xliveFFMPEG.stdout.on("data",function(data) {
resp.write(data);
}
Saya menggunakan header HTTP berikut (yang juga digunakan dan berfungsi saat streaming file pra-rekaman)
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) Klien harus menggunakan tag video HTML5.
Saya tidak punya masalah dengan streaming streaming (menggunakan fs.createReadStream dengan 206 konten parsial HTTP) ke file HTML5 file video yang sebelumnya direkam dengan baris perintah FFMPEG di atas (tetapi disimpan ke file, bukan STDOUT), jadi saya tahu aliran FFMPEG sudah benar, dan saya bahkan dapat dengan benar melihat live streaming video di VLC ketika menghubungkan ke server simpul HTTP.
Namun mencoba streaming langsung dari FFMPEG melalui simpul HTTP tampaknya jauh lebih sulit karena klien akan menampilkan satu frame kemudian berhenti. Saya menduga masalahnya adalah bahwa saya tidak mengatur koneksi HTTP agar kompatibel dengan klien video HTML5. Saya telah mencoba berbagai hal seperti menggunakan HTTP 206 (konten parsial) dan 200 tanggapan, menempatkan data ke dalam buffer lalu streaming tanpa hasil, jadi saya harus kembali ke prinsip pertama untuk memastikan saya mengatur ini dengan benar cara.
Inilah pemahaman saya tentang bagaimana ini seharusnya bekerja, tolong perbaiki saya jika saya salah:
1) FFMPEG harus di-setup untuk memecah-mecah output dan menggunakan moov kosong (FFMPEG frag_keyframe dan blank_moov mov flags). Ini berarti klien tidak menggunakan atom moov yang biasanya di akhir file yang tidak relevan saat streaming (tidak ada ujung file), tetapi berarti tidak mungkin mencari yang baik untuk kasus penggunaan saya.
2) Meskipun saya menggunakan fragmen MP4 dan MOOV kosong, saya masih harus menggunakan konten parsial HTTP, karena pemutar HTML5 akan menunggu hingga seluruh aliran diunduh sebelum diputar, yang dengan streaming langsung tidak pernah berakhir sehingga tidak bisa bekerja.
3) Saya tidak mengerti mengapa menyalurkan aliran STDOUT ke respons HTTP tidak berfungsi saat streaming langsung jika saya menyimpan ke file saya dapat melakukan streaming file ini dengan mudah ke klien HTML5 menggunakan kode yang sama. Mungkin ini masalah waktu karena memerlukan waktu sedetik untuk memulai FFMPEG, terhubung ke kamera IP dan mengirim potongan ke node, dan peristiwa data node juga tidak teratur. Namun bytestream harus persis sama dengan menyimpan ke file, dan HTTP harus dapat memenuhi penundaan.
4) Saat memeriksa log jaringan dari klien HTTP saat streaming file MP4 yang dibuat oleh FFMPEG dari kamera, saya melihat ada 3 permintaan klien: Permintaan GET umum untuk video, yang dikembalikan oleh server HTTP sekitar 40Kb, kemudian sebagian permintaan konten dengan rentang byte untuk 10K file terakhir, maka permintaan akhir untuk bit di tengah tidak dimuat. Mungkin klien HTML5 setelah menerima respons pertama meminta bagian terakhir dari file untuk memuat atom MP4 MOOV? Jika demikian, ini tidak akan berfungsi untuk streaming karena tidak ada file MOOV dan tidak ada akhir file.
5) Ketika memeriksa log jaringan ketika mencoba melakukan streaming langsung, saya mendapatkan permintaan awal yang dibatalkan dengan hanya sekitar 200 byte yang diterima, kemudian permintaan ulang lagi dibatalkan dengan 200 byte dan permintaan ketiga yang panjangnya hanya 2K. Saya tidak mengerti mengapa klien HTML5 akan membatalkan permintaan karena bytestream persis sama dengan yang saya dapat berhasil gunakan saat streaming dari file yang direkam. Tampaknya juga node tidak mengirimkan sisa aliran FFMPEG ke klien, namun saya dapat melihat data FFMPEG dalam rutinitas .on event sehingga mencapai server HTTP node FFMPEG.
6) Meskipun saya pikir pipa aliran STDOUT ke buffer respons HTTP akan berfungsi, apakah saya harus membuat buffer menengah dan streaming yang akan memungkinkan permintaan sebagian klien konten HTTP untuk berfungsi dengan baik seperti yang dilakukannya ketika (berhasil) membaca file ? Saya pikir ini adalah alasan utama untuk masalah saya, tetapi saya tidak yakin di Node bagaimana cara terbaik mengaturnya. Dan saya tidak tahu bagaimana menangani permintaan klien untuk data di akhir file karena tidak ada ujung file.
7) Apakah saya di jalur yang salah dengan mencoba menangani 206 permintaan konten parsial, dan haruskah ini bekerja dengan 200 respons HTTP normal? Respons HTTP 200 berfungsi dengan baik untuk VLC, jadi saya menduga klien video HTML5 hanya akan berfungsi dengan permintaan sebagian konten?
Karena saya masih belajar hal-hal ini sulit untuk bekerja melalui berbagai lapisan masalah ini (FFMPEG, node, streaming, HTTP, HTML5 video) sehingga petunjuk apa pun akan sangat dihargai. Saya telah menghabiskan waktu berjam-jam untuk meneliti situs ini dan internet, dan saya belum menemukan siapa pun yang dapat melakukan streaming waktu nyata dalam simpul tetapi saya tidak bisa menjadi yang pertama, dan saya pikir ini harus dapat bekerja (entah bagaimana !).
Content-Type
kepala Anda? Apakah Anda menggunakan pengkodean chunk? Di situlah saya mulai. Selain itu, HTML5 tidak selalu menyediakan fungsionalitas untuk streaming, Anda dapat membaca lebih lanjut tentang itu di sini . Anda kemungkinan besar perlu menerapkan cara untuk buffer dan memutar aliran video menggunakan cara Anda sendiri ( lihat di sini ), berpikir ini kemungkinan tidak didukung dengan baik. Juga google ke MediaSource API.