Loading page...Загружаем страницу...正在加载页面...
AtlasRepo

How do I get an HLS stream from an IP camera?

Description and use

Developers expose HLS streams from IP cameras by transcoding RTSP with ffmpeg for on‑premise use and obtaining vendor‑provided HLS handles for off‑site viewers, ensuring secure access and robust error handling.

Problem

Developers need to expose live camera feeds to web clients using HLS while respecting security, latency, and control requirements.

Outcome

The approach enables secure, low‑latency HLS delivery for both LAN and off‑site viewers, with clear separation of concerns, robust error handling, and telemetry for monitoring.

Workflow

  • 1. Store camera RTSP URL in a secret store on the server.
  • 2. For on‑premise cameras, run ffmpeg to transcode RTSP to HLS, outputting .m3u8 and segments to a secure directory.
  • 3. Serve HLS over HTTPS with an expiring path; set segment duration and list size as knobs.
  • 4. For off‑site viewers, bind camera to database, authorize user, and request a vendor live handle via POST /sites/.../cameras/.../live.
  • 5. Return JSON with handle and expiry; client destroys player on route change.
  • 6. In the React app, fetch the live handle, handle HTTP errors (403 DENIED, 409 OFFLINE, other MEDIA), and initialize the player.
  • 7. Log telemetry (cameraId, actorId, sourceKind, code, firstFrameMs) without persisting RTSP URLs or vendor secrets.
  • 8. Implement tests to ensure no RTSP leakage, correct RBAC, handle refresh after revocation, and proper error states.
  • 9. Monitor packager health (TCP reachability, process status, playlist mtime) and vendor API health (bind, mint, revoke).

Evidence

I do not ask an IP camera for HLS. I ask it for RTSP, or I ask a vendor live API that already packaged the camera into HTTP.

Source

ffmpeg -rtsp_transport tcp -i "$CAMERA_RTSP" -c:v copy -c:a aac -f hls -hls_time 2 -hls_list_size 6 /var/origin/live/cam.m3u8

Source

POST /sites/site_12/cameras/cam_4/live Cookie: session=... 201 { "handle": "ply_…", "expiresAt": "…" } 403 { "code": "DENIED" } 409 { "code": "OFFLINE" }

Source

  • Record date: 2026-09-22T09:30:37.296Z