Saltar al contenido principal

Recomendaciones de capacidad — Streaming y grabación vstation

Documento de referencia con la arquitectura y dimensionamiento más óptimos para vstation, basado en las simulaciones stream-load-sim y mediamtx-recording-sim.


Resumen ejecutivo​

CapaRecomendación principal
Streaming en vivoLiveKit SFU + ingesta WHIP H.264 passthrough (sin transcode)
GrabaciónMediaMTX con pull directo desde cámaras/NVR — sin relay ffmpeg en vstation
SeparaciónDos pipelines independientes: vivo ≠ grabación
GPU servidorNo requerida en ninguno de los dos casos (stream copy / passthrough)

Principio clave: no duplicar tráfico ni procesos. El relay ffmpeg en vstation es válido para decenas de cámaras; a escala (200 ingestas de vivo o 1300+ grabaciones) debe eliminarse o externalizarse.


Arquitectura recomendada​

┌─────────────────────────────────────────────────────────────────────────┐
│ STREAMING EN VIVO │
│ Cámara RTSP ──► GStreamer WHIP (vstation) ──► LiveKit SFU ──► Browser │
│ Solo cámaras que alguien está viendo (on-demand ingest) │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│ GRABACIÓN │
│ Cámara RTSP ──► MediaMTX (pull directo) ──► MinIO (segmentos) │
│ vstation: ILM, retención, playback — NO relay ffmpeg │
└─────────────────────────────────────────────────────────────────────────┘

1. Streaming en vivo (operadores)​

Escenario de referencia​

  • 20 usuarios concurrentes
  • 10 streams abiertos por usuario
  • Streams distintos por operador (--layout varied) → hasta 200 cámaras únicas en ingesta
  • Perfil: H.264 passthrough (VSTATION_INGEST_MODE=whip, cámaras H.264 nativas)

Configuración óptima (.env)​

VSTATION_INGEST_MODE=whip
VSTATION_H265_PASSTHROUGH=false # solo si cámaras H.265; preferir cámaras H.264 nativas
LIVEKIT_URL=wss://...
LIVEKIT_API_URL=https://...
LIVEKIT_API_KEY=...
LIVEKIT_API_SECRET=...
VariableValor recomendadoMotivo
VSTATION_INGEST_MODEwhipMenor latencia que RTMP/ffmpeg legacy
Perfil de cámaraH.264 nativoEvita transcode (~45% CPU/cámara con H.265)
adaptiveStream / dynacastfalse (ya en cliente)Calidad fija para CCTV

Dimensionamiento servidor (200 ingestas activas, H.264)​

ComponenteRAMCPUGPU
Infra (app + postgres + redis + nginx)0.8 GB0.1 cores0%
Ingesta WHIP (200 cámaras)17.6 GB16 cores0%
LiveKit SFU (200 suscripciones)1.4 GB0.6 cores0%
Total servidor~27 GB~21 cores0%

Servidor sugerido (con ~25% headroom): 34 GB RAM, 27 cores, 1 Gbps+ egress.

Clientes (20 operadores)​

Por operadorTotal 20 usuarios
~537 MB RAM navegador~10.7 GB
Decode GPU HW ~30%~600% agregado
10 tiles × 720p–1080p—

Requisito operador: GPU con decode H.264 hardware, ≥8 GB RAM en el PC, Chrome/Edge recientes.

Ancho de banda streaming​

DirecciónMbps
Ingress (cámaras → servidor)~300
Egress (SFU → clientes)~300

Qué evitar en streaming​

  • Transcode H.265→H.264 con 200 cámaras activas → ~90 cores CPU solo en ingesta
  • Mosaico compartido asumido cuando cada operador ve cámaras distintas — subestima ingesta 20×
  • Firefox si alguna cámara usa H.265 passthrough (pantalla negra)

Simular otro escenario​

npm run stream:sim
npx tsx scripts/stream-load-sim.ts --users 20 --streams 10 --layout varied
npx tsx scripts/stream-load-sim.ts --layout shared --unique-cameras 10 # videowall común
npx tsx scripts/stream-load-sim.ts --profile h265_transcode --cores 64 # peor caso HEVC

2. Grabación continua (MediaMTX)​

Escenario de referencia​

  • 1300–1500 cámaras grabando simultáneamente
  • Segmentos 30s (considerar 60s para reducir IOPS)
  • Retención 30 días
  • Bitrate 1000–1500 kbps por cámara

Configuración óptima — modo pull (implementado en vstation)​

En vstation — vstation sincroniza paths en MediaMTX vía API cuando recordingEnabled=true:

VSTATION_RECORDING_MODE=pull
MEDIAMTX_RTSP_URL=
MEDIAMTX_API_URL=http://mediamtx:9997
MEDIAMTX_MINIO_ENDPOINT=http://minio:9000
MEDIAMTX_MINIO_ACCESS_KEY=...
MEDIAMTX_MINIO_SECRET_KEY=...
VSTATION_FASTSTART_WORKER=false

vstation crea/actualiza paths ingest/camera-{id} con source = URL RTSP de la cámara y record: true. No hace falta editar mediamtx.yml a mano por cada cámara.

Modo legacy relay: define VSTATION_RECORDING_MODE=relay y MEDIAMTX_RTSP_URL para volver al ffmpeg por cámara.

Prefijo MinIO: recordings/camera-{id}/. Grupos: recordingEnabled=true activa path + ILM en MinIO.

Dimensionamiento — topología directa (1400 cámaras @ 1000 kbps)​

ComponenteRAMCPUGPU
vstation-app (sin relays)0.3 GB0.1 cores0%
MediaMTX (1400 paths)17 GB8 cores0%
MinIO3 GB1 core0%
Total servidor~20 GB~10 cores0%

Servidor sugerido: 25 GB RAM, 13 cores, ≥3 Gbps red, NVMe/RAID (>500 MB/s sostenido).

Almacenamiento y red (1400 cámaras)​

Métrica@ 1000 kbps@ 1500 kbps
Escritura sostenida~175 MB/s~263 MB/s
TB/día~14 TB~22 TB
TB (30 días)~420 TB~650 TB
Segmentos/hora (30s)~168 000~168 000

Ajuste de segmentos (sin código)​

PATCH /api/mediamtx/config
Content-Type: application/json

{ "recordSegmentDuration": "60s" }

Reduce a la mitad los archivos/hora y la carga en MinIO.

Qué evitar en grabación​

Anti-patrónImpacto (1400 cams)
Relay ffmpeg en vstation~48 GB RAM, ~25 cores extra + tráfico duplicado
VSTATION_FASTSTART_WORKER=true a escalaPicos CPU por re-mux MP4
Disco < 500 MB/s sostenidoCaídas de grabación
Segmentos 30s con 1500 cams~180k archivos/hora → IOPS alto

Simular otro escenario​

npm run recording:sim
npx tsx scripts/mediamtx-recording-sim.ts --cameras-min 1300 --cameras-max 1500
npx tsx scripts/mediamtx-recording-sim.ts --topology direct --bitrate-kbps 1000
npx tsx scripts/mediamtx-recording-sim.ts --segment-sec 60 --retention-days 30

3. Comparativa: relay vs directo (grabación)​

AspectoRelay ffmpeg (actual)Directo MediaMTX (óptimo)
Procesos vstation1 × cámara0
RAM vstation (1400 cams)~48 GB~0.3 GB
CPU vstation~25 cores~0.1 core
Saltos de redCámara → vstation → MTXCámara → MTX
Cambios de código—Ninguno (solo config)
Control on/off desde UIAutomáticoManual vía MediaMTX config/API

4. Comparativa: streaming shared vs varied​

AspectoMosaico compartido (10 cams)Streams distintos por usuario (200 cams)
Suscripciones WebRTC200200
Ingestas activas10200
RAM servidor~3.4 GB~27 GB
CPU servidor~1.7 cores~21 cores
Egress~300 Mbps~300 Mbps

La diferencia está en ingesta, no en el SFU. Si cada operador ve cámaras distintas, dimensionar por usuarios × streams.


5. Checklist de despliegue óptimo​

Streaming​

  • Cámaras H.264 nativas donde sea posible
  • VSTATION_INGEST_MODE=whip
  • LiveKit SFU dimensionado separado del app server si >50 ingestas concurrentes
  • Simular con --layout varied si operadores no comparten mosaico
  • PCs operador con GPU decode y ≥8 GB RAM

Grabación​

  • VSTATION_RECORDING_MODE=pull y MEDIAMTX_RTSP_URL vacío
  • MEDIAMTX_API_URL apuntando a MediaMTX :9997
  • MinIO con NVMe, ILM por recordings/camera-{id}/
  • recordSegmentDuration ≥ 60s a escala
  • VSTATION_FASTSTART_WORKER=false con >500 cámaras

Infraestructura compartida​

  • cadvisor (:8080) + node-exporter para medir en staging
  • Validar plan/límites LiveKit antes de >150 suscripciones WebRTC
  • Red dedicada o VLAN para tráfico RTSP (no mezclar con egress WebRTC sin QoS)

6. Matriz de decisión rápida​

PreguntaRespuesta óptima
¿Transcode H.265 en vivo?No — usar cámaras H.264 o H.265 passthrough solo si todos los clientes lo soportan
¿Relay ffmpeg para grabación?No a partir de ~200 cámaras — pull directo en MediaMTX
¿GPU en servidor?No para passthrough/copy
¿Dónde poner CPU de ingesta?Servidor LiveKit/vstation separado del nodo MediaMTX/MinIO
¿Cuánta red?Streaming ~300 Mbps + Grabación ~1.5–2 Gbps (escala independiente)

7. Scripts de validación​

ScriptComandoUso
Streamingnpm run stream:simOperadores, LiveKit, ingesta WHIP
Grabaciónnpm run recording:simMediaMTX, MinIO, almacenamiento

Ambos soportan --json, --help y parámetros CLI documentados.


Valores orientativos para CCTV 720p–1080p. Validar siempre en staging con métricas reales (cadvisor, iostat, MediaMTX /v3/paths/list).