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:[email protected]: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.Jawaban:
Segala sesuatu di bawah garis ini sudah usang. Menyimpannya di sini untuk anak cucu.
Ada banyak alasan mengapa video dan, khususnya, video langsung sangat sulit. (Harap perhatikan bahwa pertanyaan awal menentukan bahwa video HTML5 merupakan persyaratan, tetapi penanya menyatakan Flash mungkin di komentar. Jadi, pertanyaan ini menyesatkan)
Pertama saya akan menyatakan kembali: TIDAK ADA DUKUNGAN RESMI UNTUK STREAMING LANGSUNG LEBIH DARI HTML5 . Ada peretasan, tetapi jarak tempuh Anda mungkin beragam.
Selanjutnya, Anda perlu memahami bahwa Video on demand (VOD) dan video langsung sangat berbeda. Ya, keduanya adalah video, tetapi masalahnya berbeda, maka formatnya berbeda. Misalnya, jika jam di komputer Anda berjalan 1% lebih cepat dari yang seharusnya, Anda tidak akan melihat pada VOD. Dengan video langsung, Anda akan mencoba memutar video sebelum itu terjadi. Jika Anda ingin bergabung dengan streaming video langsung yang sedang berlangsung, Anda memerlukan data yang diperlukan untuk menginisialisasi dekoder, sehingga harus diulangi dalam aliran, atau dikirim keluar dari pita. Dengan VOD, Anda dapat membaca awal file yang mereka cari ke titik mana pun yang Anda inginkan.
Sekarang mari kita gali sedikit.
Platform:
Codec:
Metode Pengiriman umum untuk video langsung di browser:
Metode Pengiriman umum untuk VOD di browser:
tag video html5:
Mari kita lihat browser mana yang mendukung format apa
Safari:
Firefox
YAITU
Chrome
MP4 tidak dapat digunakan untuk video langsung (CATATAN: DASH adalah superset dari MP4, jadi jangan bingung dengan itu). MP4 terbagi menjadi dua bagian: moov dan mdat. mdat berisi data video audio mentah. Tapi itu tidak diindeks, jadi tanpa moov, itu tidak berguna. Moov berisi indeks semua data di mdat. Tetapi karena formatnya, itu tidak dapat 'diratakan' sampai cap waktu dan ukuran bingkai SETIAP diketahui. Dimungkinkan untuk membangun moov yang 'fib' ukuran frame, tetapi bandwidth sangat boros.
Jadi, jika Anda ingin mengirim ke mana-mana, kami perlu menemukan penyebut yang paling tidak umum. Anda akan melihat tidak ada LCD di sini tanpa menggunakan flash contoh:
Hal yang paling dekat dengan LCD adalah menggunakan HLS untuk mendapatkan pengguna iOS Anda, dan mem-flash untuk orang lain. Favorit pribadi saya adalah untuk menyandikan HLS, lalu gunakan flash untuk memainkan HLS untuk semua orang. Anda dapat memainkan HLS dalam flash melalui JW player 6, (atau menulis HLS Anda sendiri ke FLV di AS3 seperti yang saya lakukan)
Segera, cara paling umum untuk melakukan ini adalah HLS di iOS / Mac dan DASH melalui MSE di tempat lain (Inilah yang akan segera dilakukan Netflix). Tetapi kami masih menunggu semua orang untuk memperbarui peramban mereka. Anda juga mungkin akan membutuhkan DASH / VP9 terpisah untuk Firefox (saya tahu tentang open264; itu menyebalkan. Itu tidak dapat melakukan video di profil utama atau tinggi. Jadi saat ini tidak berguna).
sumber
Terima kasih semua orang terutama szatmary karena ini adalah pertanyaan yang kompleks dan memiliki banyak lapisan untuk itu, semuanya harus berfungsi sebelum Anda dapat melakukan streaming video langsung. Untuk mengklarifikasi pertanyaan awal saya dan penggunaan video HTML5 vs flash - use case saya memiliki preferensi yang kuat untuk HTML5 karena generik, mudah diterapkan pada klien dan masa depan. Flash adalah yang terbaik kedua jadi mari kita tetap menggunakan HTML5 untuk pertanyaan ini.
Saya belajar banyak melalui latihan ini dan setuju streaming langsung jauh lebih sulit daripada VOD (yang bekerja dengan baik dengan video HTML5). Tapi saya mendapatkan ini bekerja dengan memuaskan untuk kasus penggunaan saya dan solusinya menjadi sangat sederhana, setelah mengejar opsi yang lebih kompleks seperti MSE, flash, skema buffering rumit di Node. Masalahnya adalah FFMPEG merusak MP4 yang terfragmentasi dan saya harus menyetel parameter FFMPEG, dan pengalihan pipa node node standar melalui http yang saya gunakan semula adalah semua yang diperlukan.
Di MP4 ada opsi 'fragmentasi' yang memecah mp4 menjadi fragmen yang jauh lebih kecil yang memiliki indeks sendiri dan membuat opsi streaming live mp4 layak. Tetapi tidak mungkin untuk mencari kembali ke aliran (OK untuk kasus penggunaan saya), dan versi selanjutnya dari fragmentasi dukungan FFMPEG.
Catatan waktu dapat menjadi masalah, dan dengan solusi saya, saya memiliki jeda antara 2 dan 6 detik yang disebabkan oleh kombinasi remuxing (secara efektif FFMPEG harus menerima streaming langsung, remux kemudian mengirimkannya ke node untuk melayani melalui HTTP) . Tidak banyak yang dapat dilakukan mengenai hal ini, namun di Chrome video tersebut mencoba untuk mengejar sebanyak yang dapat membuat video sedikit gelisah tetapi lebih terkini dari IE11 (klien pilihan saya).
Daripada menjelaskan bagaimana kode bekerja dalam posting ini, lihat GIST dengan komentar (kode klien tidak termasuk, itu adalah tag video HTML5 standar dengan alamat http node server). GIST ada di sini: https://gist.github.com/deandob/9240090
Saya belum dapat menemukan contoh serupa dari use case ini, jadi saya harap penjelasan dan kode di atas membantu orang lain, terutama karena saya telah belajar banyak dari situs ini dan masih menganggap diri saya seorang pemula!
Meskipun ini adalah jawaban untuk pertanyaan spesifik saya, saya telah memilih jawaban szatmary sebagai jawaban yang diterima karena ini adalah yang paling komprehensif.
sumber
Lihatlah proyek JSMPEG . Ada ide bagus diimplementasikan di sana - untuk memecahkan kode MPEG di browser menggunakan JavaScript. Bytes dari encoder (FFMPEG, misalnya) dapat ditransfer ke browser menggunakan WebSockets atau Flash, misalnya. Jika komunitas akan mengejar ketinggalan, saya pikir, itu akan menjadi solusi streaming video langsung HTML5 terbaik untuk saat ini.
sumber
Saya menulis pemutar video HTML5 di sekitar broadway h264 codec (emscripten) yang dapat memutar video langsung (tanpa penundaan) h264 di semua browser (desktop, iOS, ...).
Aliran video dikirim melalui websocket ke klien, decode frame per frame dan ditampilkan dalam canva (menggunakan webgl untuk akselerasi)
Lihat https://github.com/131/h264-live-player di github.
sumber
Salah satu cara untuk melakukan streaming langsung webcam berbasis RTSP ke klien HTML5 (melibatkan penyandian ulang, jadi harapkan kehilangan kualitas dan membutuhkan daya CPU):
Pada mesin yang menerima aliran dari kamera, jangan gunakan FFMPEG tetapi gstreamer. Ia dapat menerima dan men-decode RTSP-stream, menyandikan ulang dan mengalirkannya ke server icecast. Contoh pipeline (hanya video, tidak ada audio):
=> Anda kemudian dapat menggunakan tag <video> dengan URL dari icecast-stream ( http://127.0.0.1:12000/cam.webm ) dan itu akan bekerja di setiap browser dan perangkat yang mendukung webm
sumber
Lihatlah solusi ini . Seperti yang saya tahu, Flashphoner memungkinkan untuk memutar streaming audio + video langsung di halaman HTML5 murni.
Mereka menggunakan codec MPEG1 dan G.711 untuk pemutaran. Peretasan menghasilkan video yang diterjemahkan ke elemen kanvas HTML5 dan memutar audio yang didekodekan melalui konteks audio HTML5.
sumber
Bagaimana dengan menggunakan solusi jpeg, biarkan server mendistribusikan jpeg satu per satu ke browser, lalu gunakan elemen kanvas untuk menggambar jpeg ini? http://thejackalofjavascript.com/rpi-live-streaming/
sumber
Ini adalah kesalahpahaman yang sangat umum. Tidak ada dukungan video HTML5 langsung (kecuali untuk HLS di iOS dan Mac Safari). Anda mungkin dapat 'meretasnya' menggunakan wadah webm, tapi saya tidak berharap itu akan didukung secara universal. Apa yang Anda cari termasuk dalam Media Source Extensions, di mana Anda dapat memberi makan fragmen ke browser satu per satu. tetapi Anda harus menulis beberapa javascript sisi klien.
sumber
solutions
tetapi tidak adasupport
streaming langsung. Ini secara langsung merujuk pada komentar saya yang terlihat di atas. Dan webm didukung pada browser utama, sebagian besar versi stabil terbaru.Coba binaryjs. Sama seperti socket.io tapi satu-satunya yang bisa dilakukan adalah streaming video audio. Binaryjs google itu
sumber