How Tos

Publicar en almacenamiento de objetos (S3, Azure Blob)

Publica la salida HLS / TS, DASH o CMAF de un Live stream directamente en un bucket compatible S3 o en un container de Azure Blob, con un CDN por delante.

Available in: UI · API

Usa esta how-to para enviar la salida segmentada de un Live stream a almacenamiento de objetos en lugar de a un ingest de CDN. Lo cubren dos providers: S3 para cualquier bucket compatible S3 y Azure Blob Storage para un container de Azure. Ambos son Destinations normales — no hay formulario aparte ni entidad extra que crear.

Cuándo usar esto

Cuando quieres ser dueño del origen. El bucket guarda los manifests y segmentos que produce el Encoder, un CDN por delante sirve a la audiencia, y la factura de almacenamiento sustituye al contrato de ingest del CDN. Es también el camino más corto hacia un archivo que un reproductor puede leer directamente, y hacia un origen self-hosted en las instalaciones del cliente.

S3 no es específico de AWS. La misma superficie de subida firmada funciona contra AWS S3, MinIO, Ceph RGW, Wasabi, Backblaze B2, DigitalOcean Spaces y Cloudflare R2, incluidos endpoints en un puerto no estándar.

Un bucket no es un CDN. El almacenamiento de objetos es un origen: no tiene caché ni distribución geográfica, y factura cada petición. Servir la reproducción directamente desde el bucket funciona, pero pon un CDN por delante y entrega a los reproductores la URL del CDN a través del campo Playback URL del Destination.

Prerrequisitos

  • Un bucket o container ya creado. C21 Live Control no lo crea. Para S3, anota el endpoint regional, el nombre del bucket y el prefijo de clave bajo el que quieres que viva la salida; para Azure, el endpoint de la cuenta y el container.
  • Credenciales acotadas a ese prefijo. Para S3, un Access Key ID y un Secret Access Key de una identidad que pueda escribir y borrar bajo el prefijo. Para Azure, un token SAS de container (sr=c) con permiso de creación y escritura.
  • Un CDN por delante del bucket — recomendado para cualquier cosa que vaya a ver una audiencia. Su URL pública es la que va en Playback URL.
  • Un Live stream configurado cuyo Encoding produzca salida HLS / TS, DASH o CMAF.
  • Rol necesario. System Administrator para registrar el Destination; Operator (o System Administrator) para enlazarlo a un Live stream y emitir.

Restricciones a tener en cuenta

  • Solo formatos segmentados. Los Destinations de almacenamiento de objetos aceptan HLS / TS, DASH y CMAF. El provider no se ofrece en RTMP, Enhanced RTMP, SRT, STREAM, SDIOUT ni Record.
  • En S3 no hay campo de región, por diseño. La región de firma se deriva del endpoint y se corrige automáticamente — consulta Región (S3).
  • No se soportan credenciales temporales STS. Usa claves de larga duración.
  • No se soportan claves SSE-KMS por objeto. El cifrado por defecto a nivel de bucket (SSE-S3 o SSE-KMS) se aplica de forma transparente y no requiere nada aquí.
  • La storage class es la del bucket. Usa una regla de ciclo de vida para transicionar los objetos a una clase más barata.
  • El Encoder no purga Azure Blob Storage. Los segmentos antiguos permanecen en el container hasta que una regla de ciclo de vida de Azure los expire.
  • DASH y CMAF dejan huérfanos los objetos de una sesión en cada reinicio del Encoder. Sus nombres de segmento llevan un timestamp de sesión, así que un reinicio empieza una sesión de nombres nueva y los objetos de la anterior se quedan atrás — nada en el producto los sigue después. Una regla de ciclo de vida sobre el prefijo es obligatoria, no opcional. HLS no se ve afectado: sus segmentos son un contador continuo bajo una ruta fija, así que la ventana sigue rodando entre reinicios.

Vía UI

Crear el Destination

Navega: Destinations → Add destination. Rellena Name, elige el Type (HLS / TS, DASH o CMAF) y pon Provider en S3 o Azure Blob Storage. El resto del formulario se reetiqueta según el provider.

Para S3:

Etiqueta UICampo APIValor
Endpoint and bucketsettings_common.urls.primary_serverEndpoint, bucket y prefijo de clave en una sola URL, por ejemplo https://s3.eu-west-1.amazonaws.com/my-bucket/live.
Stream namesettings_common.streamSe añade al prefijo — pasa a ser el siguiente segmento de la clave.
Access Key IDsettings_common.usernameEl identificador de la clave de acceso.
Secret Access Keysettings_common.passwordEl secreto correspondiente. Se almacena cifrado; las lecturas devuelven el sentinel.
Playback URLsettings_common.urls.playerLa URL del CDN que deben usar los reproductores.

Para Azure Blob Storage:

Etiqueta UICampo APIValor
Primary serversettings_common.urls.primary_serverhttps://<account>.blob.core.windows.net/<container>/<prefix>.
Stream namesettings_common.streamSe añade al prefijo, igual que arriba.
SAS tokensettings_common.passwordEl SAS de container. Con o sin el ? inicial — se aceptan ambos. No hay usuario: el SAS es toda la autorización.
Playback URLsettings_common.urls.playerLa URL del CDN que deben usar los reproductores.

Acertar con la URL

Los dos estilos de direccionamiento de S3 se aceptan y no hace falta nada para distinguirlos:

path-style            https://s3.eu-west-1.amazonaws.com/my-bucket/live
virtual-hosted-style  https://my-bucket.s3.eu-west-1.amazonaws.com/live
self-hosted           https://minio.example.com:9000/my-bucket/live

Con Stream name channel-1, la primera forma escribe my-bucket/live/channel-1/index.m3u8 y sus segmentos al lado.

Usa un endpoint regional. El global s3.amazonaws.com responde con una redirección a la región propia del bucket, y una petición redirigida ya no cuadra con su firma. El editor avisa de esto bajo el campo, y también de un endpoint que no sea https o que no lleve bucket en la ruta. Los avisos no bloquean el guardado.

Enlazar el Destination a un Live stream

Abre el Live stream de destino en el editor de Live streams y añade el nuevo Destination bajo Destinations — directamente o a través de un Destination group. Guarda.

Arrancar el Live stream

Arranca la emisión desde On air. El Destination pasa a activo en el indicador por Destination de la fila on-air, y los objetos empiezan a aparecer bajo el prefijo.

Vía API

Todas las llamadas usan la cabecera bearer estándar Authorization: Bearer <YOUR_API_TOKEN>.

AcciónMétodo + pathoperationId
Listar el catálogo de providersGET /c21apiv2/publishing/providersgetPublishingProviders
Crear un DestinationPOST /c21apiv2/publishingsaddPublishing
Actualizar un DestinationPUT /c21apiv2/publishings/{publishingId}updatePublishing
curl -X POST "https://<your-host>/c21apiv2/publishings" \
  -H "Authorization: Bearer <YOUR_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Origin bucket — Channel 1",
    "type": "HLS / TS",
    "settings_common": {
      "provider": "S3",
      "stream": "channel-1",
      "username": "<Access Key ID>",
      "password": "<Secret Access Key>",
      "urls": {
        "primary_server": "https://s3.eu-west-1.amazonaws.com/my-bucket/live",
        "player": "https://cdn.example.com/live/channel-1/index.m3u8"
      }
    }
  }'

La variante Azure es la misma llamada con "provider": "Azure Blob Storage", la URL del container en primary_server, el token SAS en password y sin username.

Las credenciales son write-only. Toda ruta de lectura devuelve el sentinel •••••••• cuando hay un valor almacenado y una cadena vacía cuando no lo hay; reenviar el sentinel en una escritura preserva el valor almacenado, así que un PUT que solo cambia el stream name no necesita tener el secreto a mano.

Consulta API → Overview para el envelope estándar y Paginación y errores para el manejo de errores.

Región (S3)

SigV4 ata una firma a una región, y el Encoder la deduce en vez de pedir algo que el propio endpoint puede declarar. En este orden:

  1. La respuesta del propio endpoint. Un sondeo sin firmar sobre el bucket devuelve la región junto con su denegación, así que esto resuelve correctamente incluso con credenciales que solo puedan escribir objetos.
  2. El hostname, para los proveedores que la codifican en una etiqueta — s3.<region>.amazonaws.com, s3.<region>.wasabisys.com, <region>.digitaloceanspaces.com y *.r2.cloudflarestorage.com (que firma como auto).
  3. us-east-1, que es lo que acepta una implementación S3 sin región configurada.
  4. Corrección. Si el almacenamiento rechaza la petición por cabecera de autorización malformada, su respuesta nombra la región que espera; el Encoder la adopta, registra la corrección y vuelve a firmar. Una región mal configurada cuesta por tanto una petición, no una caída.

La región en uso se reporta en el log del Encoder cuando arranca la publicación.

Preparar el bucket

Política IAM (AWS S3)

Dale al Destination su propia identidad, con nada más que los verbos que usa y acotada al prefijo que escribe. No reutilices una clave administrativa.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublishSegments",
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::my-bucket/live/*"
    },
    {
      "Sid": "RegionDiscovery",
      "Effect": "Allow",
      "Action": "s3:GetBucketLocation",
      "Resource": "arn:aws:s3:::my-bucket"
    }
  ]
}

En la práctica s3:DeleteObject no es opcional: sin él la ventana en directo no se purga nunca y el bucket crece mientras el canal siga emitiendo. Un borrado rechazado se reporta en el log del Encoder.

Acceso público

No se envía ninguna cabecera de ACL, así que los objetos son privados y cómo se sirven es una decisión del bucket:

  • Recomendado: mantener el bucket privado y poner CloudFront por delante con Origin Access Control.
  • Como alternativa, una política de bucket que conceda s3:GetObject sobre el prefijo.

Los buckets creados desde abril de 2023 tienen las ACL deshabilitadas, así que una ACL public-read sería rechazada de plano — por eso no se envía ninguna.

CORS

La reproducción en navegador necesita CORS en el bucket, o en el CDN. Una política mínima permite GET y HEAD desde el origen del reproductor.

Regla de ciclo de vida

La ventana en directo la mantiene el propio Encoder: según cada segmento sale de la ventana, se borra del bucket. Eso mantiene acotado un canal en marcha — medido en un canal de referencia en 81 objetos .ts estables, planos en el tiempo.

Aun así, una regla de ciclo de vida sobre el prefijo es obligatoria para DASH y CMAF, cuyos nombres de segmento por sesión dejan huérfanos los objetos de la sesión anterior en cada reinicio, y para Azure Blob Storage, que el Encoder no purga nunca. Expira el prefijo a los pocos días; además sale más barato que un borrado por objeto.

Qué lleva cada objeto

El almacenamiento de objetos conserva exactamente lo que declaró la subida y lo sirve así durante toda la vida del objeto, de modo que el tipo de medio y la caducidad de caché se fijan en el momento de subir:

ObjetoContent-TypeCache-Control
.m3u8application/vnd.apple.mpegurlno-cache, max-age=1
.mpdapplication/dash+xmlno-cache, max-age=1
.tsvideo/MP2Tpublic, max-age=31536000, immutable
.m4s, .mp4, .cmfvvideo/mp4public, max-age=31536000, immutable
.cmfaaudio/mp4public, max-age=31536000, immutable
.vtttext/vttpublic, max-age=31536000, immutable

Los manifests se reescriben en cada segmento y no deben cachearse. Los segmentos y los init segments son inmutables — sus nombres llevan el número de segmento o el timestamp de sesión — así que esa caducidad larga es lo que hace asequible la combinación bucket más CDN.

Coste

Cada segmento de cada rendition es una subida, y cada segmento que sale de la ventana es un borrado. Con segmentos de 2 s y cinco renditions eso son aproximadamente 9.000 subidas por hora y Destination, escalando linealmente con el número de renditions. En un hyperscaler son céntimos por hora, pero son recurrentes — dimensiónalo antes de apuntar un canal 24/7 a un bucket. Segmentos más largos lo reducen proporcionalmente.

Verificar

  • Los objetos aparecen bajo <prefijo>/<stream name>/ en una o dos duraciones de segmento desde el arranque.
  • El número de objetos se estabiliza en vez de crecer sin límite: en un canal de referencia, 81 objetos .ts en HLS y 351 por rendition en DASH, planos en el tiempo.
  • El manifest es accesible por la URL de CDN guardada en Playback URL, y un reproductor abierto sobre esa URL reproduce el live edge.
  • Parar el Live stream detiene las subidas; los objetos ya escritos permanecen hasta que la regla de ciclo de vida los expire.

Resolución de problemas

El código de error del propio proveedor de almacenamiento se refleja en el log del Encoder, en vez de un estado HTTP a secas.

SíntomaCausa
403 SignatureDoesNotMatchSecret Access Key incorrecto.
403 AccessDeniedLa clave es válida; la política no permite escribir en ese prefijo.
404 NoSuchBucketNombre de bucket incorrecto, o a la ruta de la URL le falta el segmento del bucket.
Una corrección de región registradaInformativo: la región de firma se corrigió automáticamente en la primera petición.
El bucket crece y se registran fallos de borradoA la política le falta s3:DeleteObject.
Azure: todas las subidas devuelven 404 ResourceNotFoundEl SAS llegó truncado, o tiene alcance de blob en vez de container (sr=c).
Los objetos llegan pero la reproducción fallaRevisa CORS en el bucket o en el CDN, y que Playback URL apunte al CDN.
La reproducción sirve un manifest obsoletoUna caché por delante del bucket está ignorando el Cache-Control del manifest.

Un SAS de container de Azure llega a unos 160 caracteres y su firma es lo último que lleva, así que cualquier truncamiento por el camino elimina en silencio justo la parte que autoriza la petición — y todas las subidas responden 404 ResourceNotFound. Pégalo entero.

FAQ

Copyright © 2026