RAM
~30 MB
CPU
10–25%
Latencia
4–12 s
Complejidad
Mínima
Contexto
Baseline
Diagrama de Arquitectura
┌──────────────────────────────────────────────────────┐
│ Raspberry Pi 3B (Debian / Docker) │
│ │
│ ┌────────────┐ ┌────────┐ ┌─────────┐│
│ │ 🎥 Cam │─v4l2──▶│ ffmpeg │──.ts─▶│ /var/ ││
│ │ CSI/USB │ │ │ .m3u8│ www/ ││
│ │ 🎤 Mic USB │─ALSA──▶│ (~30MB)│──────▶│ stream/ ││
│ └────────────┘ └────────┘ └────┬────┘│
│ │ │
│ ┌────┴────┐│
│ │ Oasis ││
│ │ :3000 ││
│ │ static ││
│ └────┬────┘│
└───────────────────────────────────────────────┼─────┘
│
┌──────────┴──────────┐
│ Navegador (cero JS)│
│ │
│ <video │
│ src="/stream/ │
│ live.m3u8" │
│ autoplay muted │
│ playsinline │
│ controls> │
│ </video> │
└─────────────────────┘
El concepto
Sin servidor media, sin node-datachannel, sin paquetes npm para media. Solo ffmpeg escribiendo segmentos HLS a disco y Oasis sirviéndolos como ficheros estáticos. Es la arquitectura de mínima complejidad: un solo comando ffmpeg + un directorio estático. Funciona en Chrome/Safari sin JS.
El Comando
ffmpeg -f v4l2 -i /dev/video0 \
-f alsa -i default \
-c:v libx264 -preset ultrafast -tune zerolatency \
-c:a aac -b:a 64k \
-f hls -hls_time 2 -hls_list_size 5 \
-hls_flags delete_segments \
/var/www/stream/live.m3u8
Un solo comando. Captura vídeo (V4L2) y audio (ALSA), codifica H.264 + AAC, genera segmentos HLS de 2 s con ventana deslizante de 5 segmentos (~10 s). Borra segmentos antiguos automáticamente.
HTML del Consumidor
<video src="/stream/live.m3u8"
autoplay muted playsinline controls>
</video>
Oasis sirve /var/www/stream/ como directorio estático. El browser consume el .m3u8 nativamente (Safari siempre; Chrome 142+ con soporte MSE mejorado). Sin JS, sin WebSocket, sin signaling.
Parámetros ffmpeg explicados
| Parámetro | Valor | Por qué |
| -f v4l2 -i /dev/video0 | Captura V4L2 | Funciona con CSI (vía bcm2835-v4l2) y USB |
| -f alsa -i default | Captura ALSA | Micrófono USB, device por defecto |
| -c:v libx264 | Encode H.264 sw | ultrafast = mínimo CPU; alt: h264_v4l2m2m (HW) |
| -preset ultrafast | Velocidad máx. | Calidad baja pero ~10% CPU vs ~40% con medium |
| -tune zerolatency | Sin buffer | Reduce latencia encode ~200 ms |
| -c:a aac -b:a 64k | Audio AAC | Compatible con HLS; 64k suficiente para voz |
| -hls_time 2 | Segmentos de 2 s | Balance latencia/overhead. Mín. práctico ~1 s |
| -hls_list_size 5 | Ventana 5 seg. | ~10 s de buffer. Evita acumulación infinita |
| -hls_flags delete_segments | Borrar viejos | Evita llenar la microSD |
CSI vs USB: variante del comando
| CSI | USB (MJPEG) | USB (H.264 HW) |
| Encode | rpicam-vid→pipe o libx264 | libx264 / h264_v4l2m2m | -c:v copy (passthrough) |
| CPU | ~5% (HW) / ~15% (SW) | ~15–25% | ~3% |
| Nota | Alt: rpicam-vid --codec h264 -o - | ffmpeg -f h264 -i - … | Decode MJPEG + encode H.264 | Mejor caso USB |
rpicam-vid -t 0 --codec h264 --inline -w 1280 -h 720 -o - | \
ffmpeg -f h264 -i - -f alsa -i default \
-c:v copy -c:a aac -b:a 64k \
-f hls -hls_time 2 -hls_list_size 5 \
-hls_flags delete_segments \
/var/www/stream/live.m3u8
ffmpeg -f v4l2 -input_format mjpeg -video_size 1280x720 \
-i /dev/video0 -f alsa -i default \
-c:v h264_v4l2m2m -b:v 1M -c:a aac -b:a 64k \
-f hls -hls_time 2 -hls_list_size 5 \
-hls_flags delete_segments \
/var/www/stream/live.m3u8
Lo que obtienes
| ✔ Tienes | ✘ No tienes |
| Vídeo + audio en browser sin JS | Latencia baja (4–12 s mínimo) |
| Complejidad mínima absoluta | Audio/vídeo bidireccional |
| Funciona sobre Tor (HTTP puro) | MJPEG (solo HLS) |
| ~20 líneas de código total | Snapshots JPEG nativos |
| Safari nativo, Chrome 142+ | WebRTC / P2P real |
| Sin dependencias nuevas (ffmpeg ya instalado) | Multi-protocolo (solo HLS) |
Comparativa directa
| Arq. 4 (ffmpeg→HLS) | Arq. 1 (go2rtc) | Arq. 6 (µStreamer) |
| Complejidad | Mínima | Baja | Baja |
| Latencia vídeo | 4–12 s | 100–300 ms | 100–300 ms |
| Latencia audio | 4–12 s | 200 ms–2 s | ~200 ms (Mumble) |
| Bidireccional | ✘ | ✔ WHEP | ✔ (Mumble) |
| ffmpeg | Sí (permanente) | No | No |
| Escrit. µSD | ⚠ Constante | No | No |
| Tor | ✔ (HTTP puro) | ⚠ TURN | ⚠ HTTP solo |
| Formatos | Solo HLS | MJPEG+HLS+WHEP+RTSP | Solo MJPEG |
| RAM | ~30 MB | ~20–40 MB | ~5–15 MB |
| Binario extra | No (ffmpeg existe) | Sí (~15 MB Go) | Sí (~1 MB C) |
Riesgos Críticos
| Riesgo | Impacto | Mitigación |
| Escritura constante a microSD |
ALTO — segmentos .ts cada 2 s → desgaste flash, especialmente en RPi solar sin UPS |
Montar /var/www/stream en tmpfs (RAM): mount -t tmpfs -o size=20m tmpfs /var/www/stream |
| Latencia inherente HLS (4–12 s) |
Alto — inaceptable para vigilancia o interacción en tiempo real |
Reducir hls_time a 1 s (ayuda poco). Para <1 s necesitas MJPEG → Arq. 1/6 |
| ffmpeg CPU constante |
Medio — encode SW ~15–25% CPU permanente mientras haya stream |
h264_v4l2m2m para HW encode (CSI: rpicam-vid pipe, USB: v4l2m2m) |
| Sin bidireccionalidad |
Medio — no hay canal de vuelta para audio ni datos |
Añadir Mumble para audio retorno → se convierte en Arq. 3 |
| Firefox no soporta HLS nativo |
Bajo — Firefox requiere JS (hls.js) para HLS→MSE |
Aceptar limitación o añadir MJPEG fallback → ya no es Arq. 4 |
tmpfs: mitigar escritura a SD
tmpfs /var/www/stream tmpfs defaults,noatime,size=20m 0 0
mount -t tmpfs -o size=20m tmpfs /var/www/stream
Con 5 segmentos × 2 s a ~500 KB/seg = ~5 MB rotando. 20 MB de tmpfs es sobrado. Coste: 20 MB de RAM extra (~50 MB total para Arq. 4). Pero elimina el riesgo de desgaste flash.
systemd (si se necesita)
[Unit]
Description=ffmpeg HLS streaming
After=network-online.target
RequiresMountsFor=/var/www/stream
[Service]
Type=simple
User=ffmpeg
Group=video,audio
ExecStartPre=/bin/mkdir -p /var/www/stream
ExecStart=/usr/bin/ffmpeg \
-f v4l2 -i /dev/video0 \
-f alsa -i default \
-c:v libx264 -preset ultrafast -tune zerolatency \
-c:a aac -b:a 64k \
-f hls -hls_time 2 -hls_list_size 5 \
-hls_flags delete_segments \
/var/www/stream/live.m3u8
Restart=on-failure
RestartSec=5
MemoryMax=80M
CPUQuota=40%
[Install]
WantedBy=multi-user.target
¿Cuándo elegir Arq. 4?
Casi nunca. La Arq. 4 existe como baseline teórico — demuestra que se puede hacer streaming con cero infraestructura nueva. Pero en la práctica:
- Si quieres baja latencia → Arq. 1 (go2rtc) o Arq. 6 (µStreamer)
- Si quieres bidireccional → Arq. 3 (Mumble) o Arq. 1 (WHEP)
- Si quieres mínima RAM → Arq. 6 (µStreamer, ~10 MB)
- Si quieres Tor → Arq. 3 (Mumble TCP)
- Si no quieres instalar nada nuevo y ffmpeg ya está → Arq. 4 ✔
Su único caso válido: un prototipo rápido para demostrar que el pipeline funciona antes de elegir la arquitectura real.
ffmpeg
HLS
.m3u8
.ts
estático
tmpfs
ultrafast
zero-infra
baseline
baseline