Une Entrée, Des Centaines de Programmes — Opérer des Canaux FAST 24/7 sur MediaLive
Un canal FAST 24/7 diffuse des centaines de programmes uniques par jour, chaque jour, et ce, indéfiniment. AWS MediaLive limite un canal à 20 entrées attachées (input attachments). La conception naïve — une entrée par vidéo — épuise les emplacements avant midi et force un redémarrage du canal qui met le flux en direct hors ligne. Nous avons résolu ce problème avec une seule entrée dynamique qui dessert tous les programmes que le canal diffusera, et une couche d'orchestration au niveau du programme qui assure l'auto-réparation de la chronologie à travers les déploiements, les défaillances partielles et les modifications de l'opérateur.
Ceci est l'histoire d'ingénierie de la façon dont cette orchestration fonctionne réellement.
Aperçu rapide
| Aspect | Détail |
|---|---|
| Domaine | Orchestration de canaux FAST 24/7 sur AWS MediaLive |
| Entrées attachées par canal | 1 dynamique + 1 écran de remplissage (slate) (+ SRT optionnel) — bien en deçà de la limite de 20 entrées |
| Identité par programme | `programId` hexadécimal de 8 octets intégré dans chaque nom d'action |
| Seuil de remplissage avec écran (slate) | Les intervalles ≥ 6 secondes déclenchent une action de commutation d'écran (slate-switch) |
| Capacité d'ordonnancement | 1500 actions par canal (limite stricte d'AWS, vérifiée en pré-déploiement) |
| Auto-réparation | Un balayage des actions orphelines (orphan-action sweep) s'exécute après chaque déploiement |
| Statut | En production |
Le Problème Commercial
Un canal FAST est un service 24/7. Les opérateurs programment une semaine ou un mois complet de vidéos uniques à l'avance, et le canal doit diffuser chacune d'elles à la bonne seconde — changer de source proprement, maintenir le filigrane stable, émettre des marqueurs de pause publicitaire, remplir les éventuels intervalles avec un écran de remplissage (slate) de la marque de la station. Le spectateur ne devrait jamais voir d'écran noir, de logo bloqué ou le programme de la semaine dernière en boucle.
Cette orchestration doit survivre à tout ce que les opérateurs lui font subir : modifier la programmation de demain, ajouter des pauses publicitaires en milieu de semaine, redéployer après un seul programme échoué, enchaîner deux clics de Déployer. Le système applique chaque modification de manière atomique sur le canal en direct ou récupère proprement. « Le canal est maintenant dans un état que personne ne comprend » n'est pas un résultat acceptable sur une infrastructure qui diffuse en direct.
Une Introduction Ă MediaLive en 60 Secondes
AWS MediaLive est un encodeur cloud longue durée. Vous lui donnez une ou plusieurs entrées (flux source ou URL de fichiers) et un ordonnancement (schedule) d'actions synchronisées — passer à cette entrée, activer cette incrustation, insérer ce marqueur. L'encodeur fonctionne en continu, exécutant les actions à leurs horodatages programmés et émettant un manifeste HLS que le lecteur du spectateur consomme.
Deux limites AWS façonnent tout le processus en aval :
- 20 entrées attachées (input attachments) par canal. Limite stricte. Un canal "Top 20 films", conçu naïvement avec une entrée par vidéo, atteint la limite au 21e film.
- 1500 actions d'ordonnancement (schedule actions) par canal. Également une limite stricte. Chaque programme comprend plusieurs actions (changement d'entrée, filigrane par rendu, marqueurs publicitaires, changement d'écran de remplissage), de sorte que le plafond réel est plus proche de quelques centaines de programmes à un instant donné.
Ces deux limites sont importantes pour un canal 24/7 qui est censé diffuser du contenu unique indéfiniment.
Pourquoi les Approches Naïves Échouent
Les approches évidentes échouent chacune de différentes manières :
- « Une entrée par programme. » atteint la limite de 20 attachements dès le premier jour. Ajouter davantage nécessite de recréer le canal — et la recréation du canal prend 60 à 90 secondes, pendant lesquelles le flux en direct est interrompu. Inacceptable pour un service 24/7.
- « Recréer le canal à chaque déploiement. » Même problème, à chaque déploiement. Les spectateurs subissent une coupure à chaque modification de la programmation. Ce n'est pas une option réaliste pour un canal censé être en direct.
- « Pré-encoder toute la semaine dans un seul fichier géant en boucle. » Tue le modèle d'édition. Vous voulez réorganiser pour demain ? Ré-encodez toute la semaine. Vous voulez insérer une publicité ? Ré-encodez. La raison même pour laquelle les canaux FAST fonctionnent commercialement est la programmation dynamique et l'insertion publicitaire par pause — tout graver dans un seul fichier exclut ces deux possibilités.
- « Exécuter plusieurs canaux en parallèle. » Nécessite que le lecteur bascule entre eux, multiplie le coût d'AWS, et interrompt le pipeline audio, MediaPackage et CDN. Ne résout pas tant le problème qu'il ne le multiplie.
Le levier dont nous disposions était une fonctionnalité unique documentée par AWS — le $urlPath$ placeholder sur une entrée dynamique — et la liberté de construire l'orchestration que nous souhaitions par-dessus.
Pourquoi c'est important. L'astuce n'est pas d'utiliser $urlPath$. AWS le documente. L'astuce est de construire une couche d'orchestration auto-réparatrice par-dessus, qui survit aux déploiements partiels, aux modifications de l'opérateur et aux tentatives concurrentes — sans jamais laisser le canal en direct dans un état que personne ne peut décrire depuis l'UI.
Notre Solution
Un canal MediaLive unique. Une entrée dynamique liée à l'URL exacte $urlPath$. Une entrée d'écran de remplissage (slate input) pour combler les intervalles. À chaque limite de programme, une action InputSwitchScheduleActionSettings remplace l'URL de l'entrée dynamique par le chemin S3 réel de ce programme. Le canal n'a jamais besoin d'un nouvel attachement d'entrée, n'a jamais besoin d'un redémarrage, et ne se déconnecte jamais.
Le travail intéressant est la couche d'orchestration qui s'exécute au-dessus de cette seule entrée — nommer chaque action avec un ID de programme pour que les actions orphelines puissent être nettoyées après une défaillance, remplir les intervalles ≥ 6 secondes avec un écran de remplissage (slate) afin que le spectateur ne voie jamais d'image figée, activer le filigrane un instant mesuré après chaque commutation d'entrée pour que l'incrustation ne clignote pas à travers les images en cours de mise en mémoire tampon, et effectuer une vérification pré-déploiement (preflight) par rapport au plafond de 1500 actions afin que les déploiements échouent dans l'UI au lieu de échouer en cours de route sur AWS.
Schéma 1 · Architecture du Canal
Architecture
- Entrée d'écran de remplissage (Slate input) — un actif statique attaché au canal pour combler les intervalles entre les programmes.
- Entrée dynamique — créée une fois avec Sources: [{ Url: "$urlPath$" }], Type: MP4_FILE. L'URL est un placeholder ; le chemin réel est fourni par programme au moment de l'ordonnancement.
- Orchestrateur Lambda (fastChannel-lambda-fun/index.js) — gère chaque activité qui apparaît sur le canal. Génère un programId hexadécimal de 8 octets par programme et étiquette chaque action liée avec celui-ci.
- Ordonnancement MediaLive (MediaLive schedule) — une liste unique et ordonnée d'actions, toutes passant par une seule BatchUpdateScheduleCommand. Limitée à 1500 actions par AWS.
- Vérification pré-déploiement du backend (Backend preflight) (schedule.service.ts) — appelle le GET_SCHEDULE_COUNT de Lambda avant chaque déploiement et refuse de procéder si les nouvelles actions dépassent la limite.
Balayage des orphelins (Orphan sweep) (sweepIncompleteProgramGroups) — s'exécute après chaque déploiement. Regroupe les actions par programId, supprime tout groupe auquel il manque son action input-switch d'ancrage.
Décisions d'Ingénierie Clés
1. Une entrée dynamique, une surcharge d'URL par programme
L'entrée dynamique est créée avec Sources: [{ Url: "$urlPath$" }]. À chaque limite de programme, la fonction Lambda émet une action InputSwitchScheduleActionSettings qui fournit UrlPath: [program.videoUrl] — l'URL S3 réelle du fichier MP4 de ce programme. MediaLive substitue le placeholder au moment de l'exécution et extrait les données de la source réelle.
Un seul attachement d'entrée dessert désormais tous les programmes que le canal diffusera — offrant un nombre effectivement illimité de vidéos uniques sur la durée de vie du canal, limité seulement par la limite d'actions d'ordonnancement par déploiement à un moment donné. La limite de 20 entrées cesse d'être une contrainte, et le canal n'a jamais besoin d'un redémarrage pour ajouter du nouveau contenu.
Schéma 2 · Surcharge d'URL d'Entrée Dynamique

Compromis délibéré. Une entrée dynamique ne pré-valide pas l'URL — MediaLive ne résout le placeholder qu'au moment du changement, de sorte qu'une erreur 404 apparaît comme une erreur côté flux plutôt qu'un rejet au moment du déploiement. Nous acceptons ce coût en échange de la simplicité architecturale d'une seule entrée. La validation ffprobe distincte du backend détecte les sources malformées avant le déploiement.
2. Les noms d'actions étiquetés par programme permettent l'auto-réparation
Chaque action émise par la fonction Lambda porte le programId hexadécimal de 8 octets du programme dans son nom : input-switch-${programId}, watermark-on-${programId}-${rendition}, ad-break-start-${programId}-${i}, program-end-${programId}, slate-switch-${programId}.
Après chaque déploiement, sweepIncompleteProgramGroups liste chaque action actuellement sur le canal, les regroupe par leur programId intégré, et supprime tout groupe auquel il manque son action input-switch d'ancrage. C'est le chemin de nettoyage pour les déploiements partiels échoués, les modifications concurrentes, et toute autre condition qui pourrait laisser le canal avec la moitié des actions d'un programme bloquées.
L'encodage du nom de l'action est l'intégralité du mécanisme d'identité. MediaLive lui-même n'a aucune notion de « programme » — la couche d'orchestration en projette un sur lui via des conventions de nommage.
Pourquoi c'est important. Sans l'ID de programme intégré dans chaque nom d'action, le balayage des orphelins n'aurait aucun moyen de savoir quelles actions appartiennent ensemble. Le nettoyage au niveau des actions supprimerait soit trop (réinitialisation complète du canal), soit trop peu (filigranes bloqués qui ne s'éteignent jamais). La convention de nommage est le modèle de données.
3. La règle des 6 secondes pour l'écran de remplissage (slate)
Les programmes se succèdent rarement parfaitement — il y a presque toujours un intervalle de quelques secondes entre la fin d'un fichier MP4 et le début du programme suivant planifié. L'orchestration émet une action de commutation d'écran de remplissage (slate-switch) chaque fois que cet intervalle est ≥ 6 secondes (MIN_SLATE_GAP_MS = 6000).
Le seuil n'est pas arbitraire. MediaLive impose un espacement minimum de 5 secondes entre deux actions d'ordonnancement ; émettre un slate-switch plus proche que cela de l'input-switch du programme suivant provoque un rejet. La règle des 6 secondes donne à MediaLive l'intervalle requis et laisse à la couche d'orchestration une seconde de marge de sécurité pour la dérive d'horloge. En dessous de 6 secondes, nous laissons la dernière image du programme précédent se figer brièvement plutôt que de risquer un rejet de déploiement.
4. Filigrane par rendu avec délai d'activation mesuré
Le filigrane est une action StaticImageOutputActivate émise par rendu de sortie (1080p, 720p, 480p, 360p) — soit quatre actions par programme. Chaque action se déclenche 1 500 ms après le changement d'entrée (input-switch) de ce programme.
Le délai existe car les premières images après un changement d'entrée sont encore en cours de mise en mémoire tampon ; activer l'incrustation au moment exact du changement peut produire un bref scintillement alors que l'incrustation est appliquée sur une image pas encore entièrement rendue. 1 500 ms était la valeur qui a constamment produit une activation propre sur les quatre rendus lors des tests. C'est une constante mesurée, et non un paramètre MediaLive documenté — et elle se trouve à un seul endroit dans le code, de sorte que tout ajustement futur ne nécessite qu'une modification d'une ligne.
Compromis délibéré. Les actions d'incrustation par rendu coûtent 4 fois plus en nombre d'actions qu'une seule incrustation globale. Nous acceptons ce coût car le chemin par rendu permet à chaque sortie d'obtenir un filigrane dimensionné précisément pour ses dimensions en pixels, plutôt que de laisser MediaLive redimensionner une seule incrustation sur les quatre. Le résultat est un logo visiblement plus net sur les sorties SD — et cela laisse suffisamment de budget d'actions pour des centaines de programmes avant que la limite de 1500 ne devienne critique.
5. Le plafond de 1500 actions, vérifié en pré-déploiement dans l'UI
AWS impose une limite stricte de 1500 actions d'ordonnancement par canal MediaLive. Avec environ 7 à 8 actions par programme (changement d'entrée + 4 filigranes + 2 marqueurs publicitaires + écran de remplissage occasionnel), le canal peut gérer environ 180 à 200 programmes actifs, selon la densité des publicités et la fréquence des écrans de remplissage. C'est un plafond réel pour les déploiements à long terme, et le nombre exact dépend de la complexité de chaque programme.
Avant chaque déploiement, le backend appelle le GET_SCHEDULE_COUNT de Lambda, qui compte les actions en direct sur le canal via DescribeScheduleCommand et retourne { liveCount, capacity: 1500 }. Si liveCount + (newPrograms × 8) dépassait 1500, le backend lève une erreur SCHEDULE_ACTION_CAP_EXCEEDED avec le nombre exact de marge — avant de soumettre quoi que ce soit à MediaLive. L'opérateur voit la limite dans l'UI avec des conseils pour effacer d'abord les programmes passés. Le déploiement ne se heurte jamais à un échec partiel.
Schéma 3 · Chronologie des Actions d'un Programme

Résultats
- Un seul canal MediaLive diffuse un nombre effectivement illimité de programmes uniques tout au long de sa vie, sur un seul attachement d'entrée dynamique. La limite de 20 entrées n'est plus une contrainte à prendre en compte — la capacité à tout moment est régie par la limite d'actions d'ordonnancement, et non par la limite d'entrées.
- L'orchestration du canal est auto-réparatrice : chaque déploiement se termine par un balayage des orphelins, de sorte que les déploiements partiels échoués ne peuvent pas laisser l'ordonnancement dans un état incohérent.
- La capacité d'ordonnancement est limitée et visible. Les opérateurs voient le plafond de 1500 actions dans l'UI avant de cliquer, et non comme un rejet AWS opaque en cours de déploiement.
- La convention de nommage par ID de programme constitue toute la couche d'identité — et c'est une chaîne de caractères. Pas de nouvelle infrastructure, pas de stockage supplémentaire, pas de dépendances. La projection la plus simple possible d'un « programme » sur la liste d'actions plate de MediaLive.
Pile Technologique : AWS MediaLive · AWS Lambda · NestJS · MongoDB · TypeScript · Node 18 · AWS SDK v3 (@aws-sdk/client-medialive)

