wandres.dev
IMAGES Y STREAM · medios en el edge

Cloudflare Stream: vídeo bajo demanda y en directo

El vídeo no es una imagen grande: exige transcodificar a varias calidades, empaquetarlas en segmentos, publicar un manifiesto y dejar que el reproductor cambie de escalón según la red del espectador. Stream toma ese trabajo entero por contrato. Vemos la subida y el estado de codificación, las entradas en vivo con ingesta RTMPS y SRT y su grabación automática, la reproducción adaptativa por HLS y DASH frente al reproductor embebido, y por qué facturar minutos en vez de bytes cambia por completo cómo se razona el coste de un catálogo de vídeo.

⏱ 20 min

El vídeo se parece a una imagen solo hasta que intentas servirlo. Un fichero de vídeo útil no es un fichero: es una familia de codificaciones a distintas resoluciones y tasas de bits, troceada en segmentos de pocos segundos, descrita por un manifiesto que el reproductor consulta para saltar de un escalón a otro cuando la red del espectador se estrecha en mitad de un túnel. Construir esa maquinaria a mano —una granja de transcodificación, un empaquetador, un almacén de renditions, un reproductor que implemente bien la lógica adaptativa— es un proyecto de varios trimestres y una guardia permanente. Stream propone lo mismo que Images pero un orden de magnitud más arriba: tú subes o emites el original, y todo lo demás pasa a ser un contrato en vez de un repositorio.

🎯 Al terminar esta lección sabrás
  • Subir un vídeo y leer su estado de codificación hasta que queda listo para reproducirse.
  • Crear una entrada en vivo, emitir por RTMPS o SRT y activar la grabación automática.
  • Distinguir el reproductor embebido de un reproductor propio alimentado por HLS o DASH.
  • Razonar el coste en minutos almacenados y minutos entregados, sin transferencia por gigabyte.

Subir un vídeo y olvidarse del transcodificado

Antes de la mecánica conviene fijar qué desaparece. Un vídeo servido con dignidad exige varias codificaciones a resoluciones y tasas de bits distintas, un troceado en segmentos de pocos segundos y un manifiesto que las describa; sin eso, o sirves una calidad única que se atasca en cuanto la red flaquea, o sirves un fichero enorme que tarda una eternidad en empezar. Stream toma ese trabajo entero por contrato: tú entregas un original y recibes la escalera completa, sin decidir perfiles, sin dimensionar codificadores y sin escribir un empaquetador.

Hay cuatro caminos de entrada y conviene conocerlos porque resuelven situaciones distintas: la subida directa de un fichero, el protocolo reanudable tus para piezas grandes o redes malas, la ingesta a partir de un enlace del que Cloudflare descarga el original, y las subidas de un solo uso que hará el cliente y que ocupan la lección siguiente. La ingesta por enlace es la más cómoda cuando el vídeo ya está en un bucket tuyo.

curl --request POST \
  https://api.cloudflare.com/client/v4/accounts/$CUENTA/stream/copy \
  --header "Authorization: Bearer $TOKEN" \
  --data '{"url":"https://mi-bucket.ejemplo.com/clase-07.mp4","meta":{"name":"Clase 07"}}'

Lo que devuelve esa llamada no es un vídeo listo, y ese matiz es el que estructura toda la integración. Devuelve un identificador y un estado, porque detrás va a ocurrir un trabajo real: descargar, analizar, transcodificar a varias calidades y empaquetar. El estado recorre una secuencia previsible —descargando, en cola, en proceso, listo o con error— y hay un indicador booleano que resume lo único que tu interfaz necesita saber para decidir si puede pintar un reproductor o debe pintar un aviso de que el vídeo se está preparando.

Consultar ese estado en bucle es la solución obvia y la mala. La buena es suscribir un webhook: Cloudflare avisa cuando el vídeo queda listo o cuando falla, la notificación trae el identificador, y tu sistema pasa de preguntar cada pocos segundos a reaccionar una vez. Esa diferencia deja de ser cosmética en cuanto tienes miles de subidas al día.

Estado Qué está pasando Qué debe pintar tu interfaz
Descargando Se recupera el original desde el enlace que diste Un aviso de recepción, sin reproductor
En cola | en proceso Se transcodifica la escalera de calidades Progreso estimado, sin reproductor
Listo Hay manifiestos válidos y miniatura El reproductor, ya
Con error La codificación falló y no habrá vídeo Un mensaje accionable y la vía de reintento

El límite de tamaño por fichero es holgado —del orden de treinta gigabytes—, pero conviene no acercarse a él con una subida simple. Para piezas grandes o redes poco fiables, el protocolo reanudable trocea la carga y permite retomarla donde se cortó, y ese detalle marca la diferencia entre una subida que falla al noventa por ciento y una que termina. Es la misma decisión que veremos con más detalle en la lección siguiente, cuando quien sube no es tu servidor sino el usuario final.

Desde un Worker hay además un binding que evita las llamadas autenticadas: sube desde una URL, consulta y edita metadatos, y genera tokens de reproducción firmados sin que tengas que custodiar una clave de firma. Es la vía natural cuando el vídeo lo produce tu propio sistema y no una persona.

const video = await env.STREAM.upload(urlDelOriginal);
const token = await env.STREAM.video(video.uid).generateToken();
await env.STREAM.video(video.uid).update({ meta: { name: "Clase 07" } });
ℹ️
La ingesta y la codificación no se facturan

Subir el original y transcodificarlo a toda la escalera de calidades es gratis, y el ancho de banda de reproducción ya va incluido en los minutos entregados: no hay una línea de salida de datos escondida. Las múltiples calidades que Stream genera por cada original tampoco consumen almacenamiento adicional —se cuenta la duración del original, no la suma de sus derivadas—.

Directo: entradas en vivo, ingesta y grabación

El directo se organiza alrededor de un objeto persistente llamado entrada en vivo. No es una emisión: es un punto de conexión estable con su propio identificador, su URL de ingesta y su clave secreta, que sobrevive a todas las emisiones que pasen por él. Esa distinción es lo que permite dedicar una entrada a un creador o a un programa recurrente y que la página del canal apunte siempre al mismo sitio.

curl --request POST \
  https://api.cloudflare.com/client/v4/accounts/$CUENTA/stream/live_inputs \
  --header "Authorization: Bearer $TOKEN" \
  --data '{"meta":{"name":"canal-principal"},"recording":{"mode":"automatic"},"deleteRecordingAfterDays":90}'

La respuesta trae la URL RTMPS y la clave que el emisor pega en su programa de emisión. Hay una segunda vía de ingesta, SRT, que soporta códecs más modernos y facilita subtítulos y varias pistas de audio; el protocolo elegido no cambia nada aguas abajo. El ajuste que más consecuencias tiene es el modo de grabación: en automático, la emisión queda disponible en directo y además se conserva como vídeo bajo demanda cuando termina, lo cual convierte cada directo en un elemento del catálogo sin ninguna acción por tu parte. Apagado, ni se graba ni se puede ver.

Otros parámetros afinan el comportamiento. Un tiempo de espera de desconexión decide cuántos segundos de caída se toleran antes de considerar que empezó una emisión nueva. Un plazo de borrado automático de grabaciones, entre treinta días y unos tres años, evita que el archivo crezca para siempre. Y un modo de baja latencia en pruebas activa una variante del protocolo que recorta segundos a costa de exigirle más disciplina al emisor.

Del lado del emisor hay requisitos que no son negociables y que conviene documentar a tus creadores antes de la primera queja: solo se aceptan vídeo H.264 y audio AAC, los grupos de imágenes deben ser cerrados, el intervalo entre fotogramas clave debe quedar entre dos y ocho segundos, y una tasa de bits constante da mejor experiencia que una variable. Ese intervalo de fotogramas clave es además la palanca directa de latencia: más corto significa que el espectador ve antes lo que ocurre, y también que la codificación es menos eficiente. Es un compromiso del vídeo, no una limitación de la plataforma.

Dos límites más conviene tenerlos escritos antes de prometer nada a nadie. Una emisión que se alargue más de siete días se graba solo hasta ese punto, así que un canal permanente necesita cortes deliberados si quieres archivo completo. Y las marcas de agua, que sí funcionan sobre vídeo bajo demanda, todavía no se aplican al directo. Hay además una palanca operativa muy útil y poco conocida: la entrada en vivo se puede deshabilitar por API, lo que rechaza cualquier conexión entrante y te da una forma programática de cortar la emisión de un creador sin borrar nada.

flowchart LR
Emisor[programa de emision] -->|rtmps o srt| Entrada[entrada en vivo]
Entrada --> Codif[codificacion automatica en escalera]
Codif --> Manif[manifiesto hls y dash]
Manif --> Player[reproductor del espectador]
Codif --> Grab[grabacion como video bajo demanda]
Grab --> Cat[catalogo]

Reproducción adaptativa y el reproductor

Cada vídeo y cada entrada en vivo tienen su propio manifiesto en los dos formatos estándar de la industria, y ahí acaba la magia: cualquier reproductor compatible sabe consumirlos. El manifiesto lista las calidades disponibles, y la lógica adaptativa del reproductor estima el ancho de banda del espectador y elige el escalón, cambiando sobre la marcha sin cortar la reproducción.

<iframe
  src="https://customer-CODIGO.cloudflarestream.com/ID_DEL_VIDEO/iframe"
  style="border: none"
  height="720"
  width="1280"
  allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;"
  allowfullscreen="true"
></iframe>

Hay además una palanca poco conocida para forzar una calidad concreta desde el propio manifiesto, pensada para cuando tu reproductor no expone su lógica adaptativa. Úsala como último recurso: casi siempre es preferible configurar el reproductor, porque tú desarrollas con fibra y buena parte de tus espectadores no.

El reproductor embebido es cero trabajo y cubre la mayoría de los casos, incluidos directos y grabaciones. Si necesitas control sobre la interfaz, la analítica o los subtítulos, tomas el manifiesto y lo pasas a tu reproductor propio en web, en iOS o en Android. Hay una regla que no se puede saltar y que rompe integraciones a menudo: los manifiestos son documentos vivos que pueden cambiar en cualquier momento, así que no se cachean, no se proxifican y no se copian; se leen siempre desde el origen.

Al apuntar el reproductor hay una decisión de producto escondida. Si usas el identificador de la entrada en vivo, la página muestra siempre la emisión activa y un aviso cuando no hay ninguna: es lo que quieres en la página de un canal. Si usas el identificador del vídeo, la página muestra una emisión concreta y después su grabación: es lo que quieres en la página de un evento con fecha.

Alrededor de la reproducción hay un conjunto de piezas que suelen darse por supuestas y que también vienen resueltas: miniaturas generadas a partir de un instante que eliges, subtítulos que subes por pista e idioma, pistas de audio adicionales para doblajes, marcas de agua aplicadas a la codificación, recortes de un fragmento como vídeo independiente y descarga en fichero cuando el producto la necesita. Nada de eso exige tocar el original ni volver a codificar tú.

El control de acceso tiene dos palancas complementarias. La primera exige un token firmado para ver el vídeo, con caducidad y con la posibilidad de fijar restricciones dentro del propio token; es lo que separa un catálogo de pago de uno abierto. La segunda limita desde qué dominios se permite la reproducción, lo que corta el uso más molesto y menos sofisticado: incrustar tu reproductor en otra web y servirse de tu factura. Cuando esas opciones se fijan en una entrada en vivo, se heredan a todas las grabaciones que salgan de ella.

🎚️

Escalera adaptativa

Cada original se codifica a varias calidades. El reproductor sube y baja de escalón según la red, sin cortar.

📡

Entrada, no emisión

La entrada en vivo es un punto de conexión estable. Las emisiones pasan por ella y cada una genera su propio vídeo.

🎬

Grabar es un ajuste

En modo automático, el directo queda como vídeo bajo demanda al terminar. El catálogo se llena solo.

⏱️

Se cuenta duración

Almacenamiento y entrega se miden en minutos. El tamaño del fichero y la resolución no entran en la factura.

Minutos, no bytes

El modelo de coste tiene dos ejes y ninguno es la transferencia. Los minutos almacenados se compran por adelantado en tramos y se consumen por la duración de los originales y de las grabaciones, con independencia del tamaño del fichero: un máster de treinta gigabytes y un montaje comprimido de la misma duración cuestan lo mismo. Los minutos entregados se facturan a posteriori por lo que se consume realmente, sumando a través de todos los espectadores; dos personas viendo media hora son sesenta minutos.

Las consecuencias prácticas de esa unidad son poco intuitivas y conviene tenerlas presentes. Un directo sin espectadores no cuesta entrega, pero su grabación sí ocupa almacenamiento. El precargado y el búfer del reproductor cuentan como entregados aunque el espectador se marche, mientras que lo que se reproduce desde la caché del navegador —un vídeo corto en bucle, por ejemplo— no vuelve a contar. Y quedarse sin almacenamiento no degrada nada de lo publicado: simplemente impide subir vídeos nuevos o iniciar directos hasta que compres más o borres.

Hay además dos comportamientos que no consumen nada y que conviene conocer para no sobredimensionar la compra: los vídeos que quedaron en estado de error no ocupan almacenamiento, y los ficheros de descarga que Stream genera a partir de un original tampoco. La cuenta se hace siempre sobre duración de contenido reproducible, redondeada al segundo.

💡
La precarga es la fuga de factura más habitual

Un reproductor configurado para precargar agresivamente en una página con veinte vídeos empieza a descargar segmentos de los veinte aunque el visitante solo vea uno, y esos segmentos se facturan como entregados. Precargar solo metadatos, o no precargar nada hasta que el usuario interactúe, suele recortar la factura de entrega de forma inmediata sin que nadie note diferencia en la experiencia.

Stream no vende almacenamiento ni ancho de banda: vende que el problema del vídeo deje de existir en tu organigrama

Conviene mirar de frente lo que se está comprando aquí, porque la unidad de facturación lo delata y casi nadie lo lee. Que el precio se exprese en minutos y no en gigabytes no es una simplificación comercial: es la declaración de que lo que se te vende no es capacidad, sino la desaparición de una función de ingeniería. Piensa en lo que hace falta para servir vídeo adaptativo por tu cuenta. Necesitas una granja de transcodificación, y con ella decisiones sobre códecs, perfiles, tasas de bits y cuántos escalones tiene la escalera. Necesitas un empaquetador que trocee en segmentos coherentes y escriba manifiestos válidos para dos protocolos que llevan una década sin ponerse de acuerdo. Necesitas almacenar no un fichero sino seis u ocho derivados por original, y decidir cuándo se purgan. Necesitas una CDN configurada con reglas distintas para segmentos y para manifiestos, porque los primeros son inmutables y los segundos no. Necesitas un reproductor que implemente bien la heurística adaptativa en cuatro plataformas cuyos motores de vídeo se comportan de forma distinta. Y necesitas a alguien que entienda todo eso a las tres de la mañana cuando el directo del evento anual se congela. La factura por minuto compra la desaparición de esa lista entera, y por eso resulta cara si la comparas contra el coste del disco y barata si la comparas contra el coste de la nómina que la lista implica. La comparación honesta no es contra R2 más ancho de banda; es contra R2 más ancho de banda más transcodificación más empaquetado más reproductor más el trimestre de calendario que se va en ponerlo en pie y los que se van en mantenerlo. Ahí está también el criterio para saber cuándo deja de tener sentido: en el momento en que el vídeo es tu producto y no un componente de tu producto, esa función de ingeniería es exactamente donde vive tu ventaja competitiva, y externalizarla equivale a externalizar la parte del sistema que te distingue. Mientras el vídeo sea un medio para vender otra cosa —cursos, documentación, marketing, prueba social—, pagar por minuto es casi siempre la decisión correcta, porque el minuto que compras no es de disco: es del ingeniero que no vas a contratar.

⚔️ Pon en pie un canal y mide lo que cuesta
  1. Sube un vídeo por enlace, registra su identificador y suscribe un webhook para enterarte de que quedó listo sin consultar en bucle.
  2. Crea una entrada en vivo con grabación automática, emite dos minutos desde tu equipo y comprueba que aparece una grabación reproducible en el catálogo.
  3. Reproduce la misma emisión apuntando al identificador de la entrada y al del vídeo. Describe con precisión qué ve el espectador en cada caso cuando la emisión termina.
  4. Baja el intervalo de fotogramas clave del emisor y mide el cambio en la latencia percibida. Explica qué has pagado a cambio.
  5. Estima el coste mensual de un catálogo tuyo real: minutos almacenados, minutos entregados y reproducciones medias por pieza. Compáralo con lo que costaría montar la escalera de codificación por tu cuenta.