Receta: transmitir una exposición de arte con varias cámaras
Poné cada sala de la galería en línea a la vez: una ingesta por cámara, páginas públicas de reproducción y embeds por sala, grabación opcional a tu propio S3, y overlays de fecha/hora y marca de agua. Un armado multicámara paso a paso.
Por qué una galería transmite
Una inauguración pasa una sola vez, en una ciudad, para quienes pueden estar en la sala. Transmitirla convierte una noche única en una apertura global y un archivo permanente — coleccionistas del exterior miran en vivo, la prensa integra un feed y la grabación pasa a ser parte del catálogo de la muestra. Para un museo o una galería, eso es alcance y procedencia por el costo de unas pocas cámaras IP.
Esta receta arma un canal en vivo por sala, todo bajo una sola app, con reproductores públicos que pegás en cualquier página.
La arquitectura en palabras
Cada cámara se vuelve una ingesta y por lo tanto una sala. Una cámara IP se tira por RTSP; un teléfono o una máquina con OBS empuja por RTMP. Cada sala obtiene una página pública /play, un iframe /embed y una playlist HLS para escala. Los overlays (una marca de agua en la esquina y un sello estilo CCTV) se dibujan sobre el reproductor, y la grabación — cuando la querés — escribe cada sala al bucket S3 de la propia app como un VOD.
1. Crear la app
export BASE="https://your-server.example.com/api/v1"
export TOKEN="sk_...." # el token global sembrado
curl -s -X POST $BASE/apps -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"gallery","displayName":"Gallery Live"}'
2. Una ingesta por sala
Tirá una cámara RTSP (la transcodificación queda activa por defecto, que es lo que HLS necesita):
curl -s -X POST $BASE/apps/gallery/ingress -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"inputType":"url","room":"hall-a","url":"rtsp://camera.local/stream"}'
Para una sala donde un curador transmite desde OBS o un teléfono, creá una ingesta RTMP:
curl -s -X POST $BASE/apps/gallery/ingress -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"inputType":"rtmp","room":"hall-b"}'
La respuesta RTMP devuelve todo lo que el codificador necesita — rtmp_url (rtmp://your-server.example.com:1935/live/<key>), stream_key, más un player_url público y un embed_iframe. Repetí una vez por cámara: hall-a, hall-b, sculpture-garden, etc. Cada ingesta cuenta contra la cuota de streams concurrentes de la app.
3. Agregar los overlays
Instalá y configurá los dos plugins player-overlay. Cada campo tiene un default, así que solo mandás lo que querés cambiar:
curl -X POST $BASE/apps/gallery/plugins/timestamp/install -H "Authorization: Bearer $TOKEN"
curl -X PATCH $BASE/apps/gallery/plugins/timestamp -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"enabled": true, "config": {"format": "datetime-24h", "position": "bottom-left", "color": "#ffffff", "showName": true}}'
curl -X POST $BASE/apps/gallery/plugins/watermark/install -H "Authorization: Bearer $TOKEN"
curl -X PATCH $BASE/apps/gallery/plugins/watermark -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"enabled": true, "config": {"text": "Museo Example", "position": "bottom-right", "opacity": 0.6}}'
Los defaults de watermark son text: "StreamHub", position: "bottom-right", opacity: 0.6; los de timestamp son format: "datetime-24h", position: "bottom-right", color: "#00e5ff", showName: true.
4. Publicar la galería pública
Cada sala ya es mirable sin token:
https://your-server.example.com/play/gallery/hall-a
https://your-server.example.com/embed/gallery/hall-a
https://your-server.example.com/hls/gallery/hall-a/index.m3u8
Armá una página simple con un iframe por sala y tenés una galería multicámara en vivo:
<iframe src="https://your-server.example.com/embed/gallery/hall-a"
width="640" height="360" frameborder="0" allowfullscreen></iframe>
5. Opcional — grabar cada sala en tu S3
Apuntá la app a tu bucket y luego iniciá una grabación por sala:
curl -X PUT $BASE/apps/gallery/s3 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"provider":"aws","bucket":"gallery-archive","region":"us-east-1","key":"AKIA...","secret":"..."}'
curl -s -X POST $BASE/apps/gallery/recording/start -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"roomName":"gallery-hall-a"}'
Para una apertura larga, poné recording.split_minutes (0, 15, 30, 60, 90 o 120) para que cada parte sea su propio VOD, y recording.snapshot_seconds para miniaturas periódicas.
Qué deberías ver
Cada cámara aparece en la pestaña "En vivo" de la app en un momento. Las páginas /play muestran el feed con el sello de hora y la marca de agua dibujados encima, y cuando egress termina una grabación, el VOD pasa a ready con una URL reproducible en tu bucket.
Resolución de problemas
- La sala RTSP nunca sale en vivo — confirmá que el servidor pueda alcanzar la URL de la cámara (un
camera.localprivado tiene que resolver desde el servidor, no solo desde tu notebook) y que la cámara hable H.264. - Faltan los overlays en la grabación — es lo esperado. Watermark y timestamp se dibujan del lado cliente solo en el reproductor; no se graban en el MP4 ni en ningún RTMP de salida. Tratalos como una capa de presentación.
Cierre
StreamHub es open source, así que una galería puede correr esto en una sola VM que controla y guardar cada grabación en su propio archivo. Si preferís delegar el aprovisionamiento de cámaras, la página de embed público y el flujo de archivado, ese es justamente el tipo de instalación llave en mano que nuestro equipo hace como servicio de consultoría.