Masalah yang ingin diselesaikan
Kamera CCTV Hikvision umumnya menyediakan stream melalui RTSP. RTSP cocok untuk komunikasi antar perangkat video, tetapi browser tidak memutarnya secara langsung seperti memutar MP4 atau HLS. Kamera juga dapat mengirim video dengan codec H.265/HEVC, sementara dukungan codec dan container di browser tidak seragam.
R&D ini membangun lapisan perantara di atas FFmpeg. FFmpeg mengambil stream dari kamera, mengubahnya ke bentuk yang lebih mudah diproses aplikasi web, lalu Node.js meneruskan byte video ke frontend melalui WebSocket.
Kasus ini memiliki dua mode:
- Live streaming: menampilkan video yang sedang berlangsung dari channel CCTV.
- Playback: meminta rekaman kamera untuk rentang waktu tertentu.
Arsitektur live streaming
Alur ini memisahkan tanggung jawab dengan jelas. Kamera tetap menjadi sumber video, FFmpeg menjadi media worker, Node.js mengelola lifecycle process dan koneksi client, sedangkan browser bertanggung jawab atas rendering.
Istilah teknis yang perlu dibedakan
RTSP
Real Time Streaming Protocol adalah protokol kontrol untuk mengatur sesi streaming, misalnya membuka stream, memilih track, pause, atau teardown. RTSP biasanya berjalan di port 554. RTSP bukan codec dan bukan format file.
Codec
Codec menentukan cara video dikompresi dan didekompresi. H.265/HEVC lebih efisien dalam ukuran dibanding H.264, tetapi dukungan hardware dan browser lebih terbatas. H.264 dipilih sebagai output yang lebih kompatibel untuk pipeline web.
Container
Container adalah format pembungkus audio/video dan metadata. MPEG-TS (.ts) dapat membawa stream H.264 sebagai rangkaian paket yang cocok untuk diproses secara streaming. MPEG-TS bukan codec; ia berbeda dari H.264 yang merupakan codec.
Transcoding dan remuxing
Transcoding berarti mendekode lalu meng-encode ulang video, misalnya H.265 menjadi H.264. Ini menggunakan CPU/GPU dan menambah latency.
Remuxing hanya mengganti container tanpa mengubah codec. Remuxing lebih ringan, tetapi tidak menyelesaikan masalah jika codec sumber tidak didukung browser.
WebSocket
WebSocket menyediakan koneksi dua arah yang persisten antara browser dan server. Pada pipeline ini, Node.js mengirim binary chunk hasil stdout FFmpeg ke client. WebSocket hanya menjadi transport; ia tidak otomatis membuat browser memahami MPEG-TS.
Latency
Latency adalah jeda antara kejadian di kamera dan tampilnya frame di browser. Buffer RTSP, ukuran GOP, preset encoder, queue process, dan buffer player semuanya memengaruhinya. ultrafast dan zerolatency dapat mengurangi delay dengan trade-off ukuran dan kualitas kompresi.
Menjalankan dan menguji source RTSP
Sebelum membuat aplikasi, source kamera sebaiknya diuji dengan ffplay. Gunakan placeholder dan jangan menaruh credential asli di source code atau dokumentasi publik.
ffplay -rtsp_transport tcp \
-i "rtsp://<username>:<password>@<camera-host>:554/Streaming/Channels/102"
-rtsp_transport tcp memilih TCP sebagai transport media. TCP biasanya lebih stabil pada jaringan yang memiliki packet loss, walaupun dapat menambah buffering dibanding UDP.
Jika ffplay dapat menampilkan video, masalah berikutnya dapat diisolasi pada process manager, output FFmpeg, WebSocket, atau player browser. Jika gagal, periksa konektivitas, credential, channel, firewall, dan konfigurasi stream kamera terlebih dahulu.
Pipeline FFmpeg untuk live stream
Contoh berikut menulis MPEG-TS ke stdout sehingga Node.js dapat membacanya sebagai binary stream:
ffmpeg -rtsp_transport tcp \
-i "rtsp://<username>:<password>@<camera-host>:554/Streaming/Channels/102" \
-an \
-c:v libx264 \
-preset ultrafast \
-tune zerolatency \
-f mpegts pipe:1
Penjelasan opsi penting:
-imenentukan input RTSP dari kamera.-anmenonaktifkan audio jika aplikasi hanya membutuhkan video.-c:v libx264meng-encode video menjadi H.264.-preset ultrafastmengurangi beban encoding dengan kompresi yang kurang efisien.-tune zerolatencymenyesuaikan encoder untuk streaming interaktif.-f mpegtsmemaksa output menggunakan MPEG-TS.pipe:1mengirim output ke stdout, bukan file.
Pada implementasi Node.js, spawn digunakan agar output tidak dikumpulkan sebagai satu string besar:
const ffmpeg = spawn("ffmpeg", [
"-rtsp_transport", "tcp",
"-i", rtspUrl,
"-an",
"-c:v", "libx264",
"-preset", "ultrafast",
"-tune", "zerolatency",
"-f", "mpegts",
"pipe:1",
]);
ffmpeg.stdout.on("data", (chunk) => {
websocket.send(chunk);
});
Contoh tersebut hanya menunjukkan boundary utama. Aplikasi nyata tetap perlu validasi URL, pembatasan jumlah process, cleanup ketika client disconnect, dan penanganan stderr serta exit code FFmpeg.
Playback berdasarkan waktu
Hikvision menggunakan endpoint RTSP yang berbeda untuk playback. Bentuk umumnya:
rtsp://<username>:<password>@<camera-host>:554/Streaming/Tracks/<channel>?starttime=<startTime>&endtime=<endTime>
Format waktu yang digunakan dokumentasi adalah:
YYYYMMDDTHHmmss+HH:mm
Contoh dengan placeholder:
rtsp://<username>:<password>@<camera-host>:554/Streaming/Tracks/101?starttime=20250922T080000+07:00&endtime=20250922T081500+07:00
Playback bukan sekadar live stream yang diberi parameter tambahan. Aplikasi perlu memvalidasi rentang waktu, memastikan timezone kamera dan server sama, lalu menjalankan FFmpeg sampai track selesai atau user menghentikannya.
Channel dan tipe stream Hikvision
Dokumentasi menggunakan pola channel (nomor channel * 100) + tipe stream:
| Channel | Arti |
|---|---|
101 | Main stream channel 1 |
102 | Sub-stream channel 1 |
103 | Transcoded stream channel 1 |
Main stream biasanya memiliki resolusi dan bitrate lebih tinggi. Sub-stream lebih ringan untuk preview banyak kamera. Pilihan ini berdampak langsung pada bandwidth, CPU transcoding, latency, dan jumlah user yang dapat dilayani.
Waktu kamera dan playback yang akurat
Playback bergantung pada timestamp. Kamera perlu menggunakan timezone lokal yang benar, misalnya GMT+07:00 untuk Jakarta/Bandung, dan sebaiknya disinkronkan melalui NTP. Tanpa sinkronisasi, user dapat meminta waktu yang salah walaupun format URL sudah benar.
Validation yang sebaiknya dilakukan server:
- Parse waktu menggunakan timezone eksplisit, bukan timezone mesin secara implisit.
- Pastikan
startTimelebih awal dariendTime. - Batasi durasi maksimal playback.
- Normalisasi input ke format yang diterima kamera.
- Jangan meneruskan nilai URL mentah ke shell command.
Lifecycle process dan reliability
Satu process FFmpeg dapat mengonsumsi CPU, memory, socket, dan koneksi kamera. Node.js perlu memperlakukan process tersebut sebagai resource yang memiliki lifecycle:
- Start ketika ada request stream yang valid.
- Simpan reference process dan client yang menggunakannya.
- Teruskan
stdoutsebagai binary, bukan string UTF-8. - Catat
stderruntuk diagnosis tanpa mengirim credential ke log publik. - Hentikan process ketika semua client disconnect atau playback selesai.
- Bersihkan process yang crash dan kirim status error yang dapat dipahami frontend.
- Terapkan timeout, retry dengan batas, dan limit jumlah stream bersamaan.
Untuk beberapa user yang menonton channel yang sama, lebih efisien memakai satu FFmpeg process bersama daripada membuat satu process per browser. Namun shared stream membutuhkan reference counting dan aturan kapan process boleh dihentikan.
Security dan deployment
RTSP URL mengandung credential sehingga tidak boleh dikirim ke browser, ditulis di repository, atau dicetak utuh ke log. Backend seharusnya menyimpan credential di environment variable atau secret manager, membangun URL hanya di server, dan memberikan browser token atau stream identifier yang tidak memuat password.
Layer yang perlu diamankan:
- Batasi akses endpoint stream dan playback dengan authentication.
- Validasi channel, waktu, dan identifier kamera dari allowlist.
- Jangan mengizinkan user memasukkan arbitrary FFmpeg argument.
- Escape atau hindari shell interpolation; gunakan
spawndengan array argument. - Batasi resource CPU, memory, bandwidth, dan jumlah process.
- Pastikan kamera tidak terbuka langsung ke internet.
Batasan pendekatan ini
Pipeline RTSP → FFmpeg → MPEG-TS → WebSocket cocok untuk R&D dan monitoring internal, tetapi bukan satu-satunya pilihan. Untuk banyak client, browser-native playback, adaptive bitrate, atau distribusi melalui CDN, HLS, WebRTC, atau media server khusus dapat lebih tepat.
FFmpeg juga bukan media server lengkap. Ia adalah media processing tool. Node.js atau media server tetap diperlukan untuk mengatur session, authorization, fan-out, monitoring, dan lifecycle client.
Penutup
Inti R&D ini adalah membuat protocol kamera yang tidak langsung dipahami browser menjadi pipeline yang dapat dikonsumsi aplikasi web. RTSP mengambil video dari Hikvision, FFmpeg melakukan processing H.265 ke H.264 dan mengemasnya sebagai MPEG-TS, lalu Node.js mengirim byte stream melalui WebSocket.
Untuk live streaming, fokusnya adalah latency dan stabilitas process. Untuk playback, fokus tambahannya adalah timestamp, timezone, validasi rentang waktu, dan penghentian process ketika rekaman selesai. Dengan memisahkan concern tersebut, aplikasi CCTV dapat dikembangkan tanpa membocorkan credential atau menjadikan setiap browser sebagai pengelola process FFmpeg sendiri.