Outil de manipulation du fichier manifeste pour les flux de vidéo à la demande

d'annonces côté serveur (SSAI) pour les flux VOD avec l'API Google Dynamic Ad Insertion (DAI) Pod Serving.

L'API Pod Serving permet d'accéder à des séries d'annonces vidéo à débit adaptatif préparées de manière à pouvoir être insérées directement dans une playlist multimédia HLS ou MPEG-DASH destinée aux utilisateurs.

Ce guide se concentre sur l'implémentation d'un serveur de manipulation de fichier manifeste Pod Serving de base pour les flux VOD.

Recevoir des demandes de fichier manifeste de flux

Votre outil de manipulation du fichier manifeste doit fournir un point de terminaison d'API pour écouter les demandes de fichier manifeste provenant de l'application cliente du lecteur vidéo. Au minimum, ce point de terminaison doit collecter un ID de flux à partir de l'application cliente du lecteur. Cet ID de flux est utilisé pour identifier la session de streaming dans vos demandes de blocs d'annonces à Ad Manager.

Vous devez également collecter d'autres informations pour identifier le flux de contenu approprié, par exemple un ID de contenu.

Exemple de point de terminaison de requête de fichier manifeste

GET /api/stream_id/{stream_id}/video/{content_id}.{format}
Host: {your_domain}
Paramètres de chemin d'accès
stream_id ID de flux Ad Manager provenant de l'application de lecteur vidéo client.
content_id ID hypothétique correspondant à la vidéo de contenu dans votre système.
format Paramètre hypothétique correspondant au format du flux. Au choix :
mpd Pour les flux MPEG-DASH
m3u8 Pour les flux HLS

Récupérer le flux de contenu

Utilisez l'ID de contenu collecté à partir de la demande de fichier manifeste pour sélectionner le flux de contenu à assembler avec les annonces.

Demander des fichiers manifestes de séries d'annonces

Pour demander des annonces à Ad Manager, votre serveur doit envoyer une requête POST au point de terminaison des groupes d'annonces, en transmettant les profils d'encodage et le tag d'annonce demandés. Cette demande inclut également l'ID de flux que vous avez collecté à l'étape 1.

En retour, vous recevez une liste d'objets de bloc d'annonces contenant les fichiers manifestes des blocs d'annonces demandés par le tag d'annonce de l'éditeur, ainsi que des informations sur le moment et l'emplacement où ils doivent être insérés dans votre contenu.

POST /ondemand/pods/api/v1/network/{network_code}/streams/{stream_id}/adpods
Host: dai.google.com
Content-Type: application/json
Paramètres de chemin d'accès
network_code Code de réseau Ad Manager 360 de l'éditeur.
stream_id ID du flux provenant de l'application de lecteur vidéo client.

Corps JSON

Paramètres corporels
encoding_profiles Required Liste des représentations JSON des profils d'encodage que vous souhaitez recevoir pour chaque emplacement publicitaire. Plus d'informations ci-dessous :

Pour que la lecture soit la plus fluide possible, cela doit correspondre à l'ensemble des profils d'encodage utilisés dans votre flux de contenu.

ad_tag Required Tag d'emplacement publicitaire permettant de demander des annonces VMAP.
cuepoints Optional Liste des points de repère dans le flux de contenu où des pauses publicitaires mid-roll seront insérées. Les points de repère sont mesurés en secondes à virgule flottante.

Obligatoire uniquement pour les réponses VMAP contenant des mid-rolls utilisant des décalages temporels positionnels. Cette situation est rare.

content_duration_seconds Optional Durée du contenu en secondes.

Obligatoire uniquement pour les réponses VMAP contenant des mid-rolls avec des décalages temporels en pourcentage. Cette situation est rare.

manifest_type Optional Format des flux d'annonces demandés, hls ou dash. La valeur par défaut est hls.
dai_options Optional Options supplémentaires permettant de contrôler la façon dont les fichiers manifestes sont affichés. Plus d'informations ci-dessous :
Profil d'encodage
profile_name Required Identifiant de ce profil d'encodage. Cette valeur peut être n'importe quelle chaîne de votre choix, mais vous ne pouvez pas avoir plusieurs profils d'encodage portant le même nom sur le même flux.
type Required Type d'encodage du flux décrit par ce profil d'encodage. Les types de contenu sont les suivants : media, iframe, subtitles.
container_type Required Format de conteneur utilisé par ce profil d'encodage. Les formats de conteneur sont les suivants : mpeg2ts, fmp4cmaf, hls_packed_audio
video_settings Optional Obligatoire si le type de profil d'encodage est iframe. Sinon, uniquement autorisé si le type de support contient une vidéo. Voir les détails ci-dessous
audio_settings Optional Obligatoire si le profil d'encodage contient de l'audio. Autorisé uniquement si le type est "media". Plus d'informations ci-dessous :
subtitle_settings Optional Obligatoire si le profil d'encodage contient des sous-titres. Plus d'informations ci-dessous :
Paramètres vidéo
codec Required Chaîne de codec RFC6381.

Exemple : avc1.4d000c

bitrate Required Entier représentant le débit vidéo maximal de ce profil en octets par seconde.
frames_per_second Required FPS (images par seconde) de la vidéo, sous forme de nombre à virgule flottante.
resolution Required Valeur encodée au format JSON contenant la largeur et la hauteur de la vidéo en pixels.

Exemple : {"width": 640, "height": 320}

Paramètres audio
codec Required Chaîne de codec RFC6381.

Exemple : mp4a.40.5

bitrate Required Entier représentant le débit audio maximal de ce profil en octets par seconde.

Exemple : 300000

channels Required Nombre entier représentant le nombre de canaux audio, y compris les canaux basse fréquence.
sample_rate Required Nombre entier représentant le taux d'échantillonnage audio en hertz.

Exemple : 4800

Paramètres des sous-titres
format Required Format de fichier utilisé par les sous-titres intégrés. Les valeurs autorisées sont webvtt ou ttml.
language Optional Langue des sous-titres sous forme de chaîne de langue RFC5646. Si elle est fournie, cette valeur n'est utilisée que pour le rendu DASH.

Exemple : en-us

Options d'insertion dynamique d'annonces
dash_profile Optional Profil MPEG-DASH à appliquer aux fichiers manifestes de séries d'annonces. Ce paramètre n'est utilisé que pour les fichiers manifeste DASH. Les valeurs autorisées sont live ou on-demand. La valeur par défaut est on-demand.

La valeur live correspond au profil MPEG-DASH "urn:mpeg:dash:profile:isoff-live:2011".

La valeur on-demand correspond au profil MPEG-DASH urn:mpeg:dash:profile:isoff-on-demand:2011.

ad_pod_timeout Optional Durée maximale (en secondes) pour sélectionner des annonces et créer des séries d'annonces. Une fois ce délai écoulé, Ad Manager renvoie les annonces déjà sélectionnées dans la réponse ad_pods et arrête le traitement.
sam_id Optional Spécifie une autre clé de débogage qui peut être utilisée pour rechercher des sessions dans l'outil de contrôle de l'activité des flux.

Réponse

Paramètres de réponse
valid_for Durée de validité de ces playlists de blocs d'annonces au format dhms (jours, heures, minutes, secondes).
valid_until Date et heure jusqu'à laquelle ces playlists de blocs d'annonces sont valides, sous la forme d'une chaîne de date et heure ISO8601, au format yyyy-MM-dd'T'hh:mm:ss.sssssssss[+|-]hh:mm.
ad_pods Liste des blocs d'annonces sélectionnés pour ce flux.
Série d'annonces
manifest_uris Pour les flux HLS uniquement. Map des ID de profil d'encodage vers les URI de fichier manifeste HLS.
mpd_uri Pour les flux DASH uniquement. URI du fichier MPD DASH.
type Type de bloc d'annonces. Les types de séries d'annonces sont les suivants : pre, mid ou post.
start Uniquement pour les séries d'annonces vidéo mid-roll. Position dans le flux où cette série d'annonces doit être insérée, en secondes (nombre à virgule flottante).
duration Durée de cette série d'annonces en secondes (nombre à virgule flottante).
midroll_index Uniquement pour les séries d'annonces vidéo mid-roll. Index de la série d'annonces vidéo mid-roll en cours. L'indexation commence par 1.

Exemple de requête (cURL)

curl -X POST \
     -d '@request-body.json' \
     -H 'Content-Type: application/json' \
  https://dai.google.com/ondemand/pods/api/v1/network/21775744923/streams/6e69425c-0ac5-43ef-b070-c5143ba68541:CHS/adpods

Exemple de corps de la requête

Il s'agit du contenu de request-body.json référencé dans l'appel cURL ci-dessus.

{
  "encoding_profiles": [
   {
     "profile_name": "1080p",
     "type": "media",
     "container_type": "mpeg2ts",
     "video_settings": {
       "codec": "avc1.4d000c",
       "bitrate": 5000000,
       "frames_per_second": 30.0,
       "resolution": {
         "width": 1920,
         "height": 1080
       }
     },
     "audio_settings": {
       "codec": "mp4a.40.5",
       "bitrate": 300000,
       "channels": 2,
       "sample_rate": 48000
     }
   },
   {
     "profile_name": "360p",
     "type": "media",
     "container_type": "mpeg2ts",
     "video_settings": {
       "codec": "avc1.4d000d",
       "bitrate": 1000000,
       "frames_per_second": 30.0,
       "resolution": {
         "width": 640,
         "height": 360
       }
     },
     "audio_settings": {
       "codec": "mp4a.40.5",
       "bitrate": 64000,
       "channels": 2,
       "sample_rate": 48000
     }
   },
   {
     "profile_name": "subtitles-webvtt",
     "type": "subtitles",
     "subtitle_settings": {
       "format": "webvtt"
     }
   }
 ],
 "ad_tag": "https://pubads.g.doubleclick.net/gampad/ads?...",
 "manifest_type": "hls"
}

Exemple de réponse

{
  "valid_for": "8h0m0s",
  "valid_until": "2023-03-24T08:30:26.839717986-07:00",
  "ad_pods": [
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/0/profile/1080p.m3u8",
        "360p": "https://{...}/pod/0/profile.m3u8",
        "subtitles-webvtt": "https://{...}/pod/0/profile/subtitles-en.vtt"
      },
      "type": "pre",
      "duration": 10.0
    },
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/1/profile/1080p.m3u8",
        "360p": "https://{...}/pod/1/profile.m3u8",
        "subtitles-webvtt": "https://{...}/pod/1/profile/subtitles-en.vtt"
      },
      "type": "mid",
      "start": 15.0,
      "duration": 15.0,
      "midroll_index": 1
    },
    {
      "manifest_urls":{
        ]"1080p": "https://{...}/pod/2/profile/1080p.m3u8",
        "360p": "https://{...}/pod/2/profile.m3u8",
        "subtitles-webvtt": "https://{...}/pod/0/profile/subtitles-en.vtt""
      },
      "type": "post",
      "duration": 10.0
    }
  ]
}

Insérer des blocs d'annonces dans le contenu

Le processus d'insertion de blocs d'annonces dans vos flux de contenu varie en fonction de votre implémentation, du format du flux et des fonctionnalités que vous choisissez d'implémenter à partir des spécifications du format. Les workflows suivants sont des suggestions pour gérer ce processus. Les détails précis de votre implémentation peuvent varier en fonction des besoins de votre entreprise et de vos flux de contenu.

Flux HLS

Si vous assemblez un flux au format HLS, votre flux de contenu sera une playlist multivariante de liens vers des fichiers manifestes de flux distincts, un pour chaque profil d'encodage. Vos pods d'annonces doivent être insérés dans chacun de ces fichiers manifestes de variantes. Pour ce faire, vous pouvez par exemple préparer tous les fichiers manifestes des variantes et les transmettre à un réseau de diffusion de contenu (CDN) pour l'hébergement. La playlist multivariante finale est un ensemble de liens vers ces fichiers manifestes hébergés sur le CDN.

Parcourir les profils d'encodage

Pour chaque profil d'encodage, rassemblez tous les fichiers manifestes de série d'annonces associés à partir de la réponse d'Ad Manager, ainsi que leurs heures de début associées. Pour les pods d'annonces pré-roll, définissez l'heure de début sur 0. Pour les post-rolls, utilisez la durée du contenu comme heure de début du bloc d'annonces. Identifiez le flux de variante dans la playlist multivariante qui correspond aux paramètres audio et vidéo de chaque profil d'encodage.

Exemple de tableau de séries d'annonces
"ad_pods": [
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/0/profile/1080p.m3u8",
        "360p": "https://{...}/pod/0/profile/360p.m3u8",
        "subtitles-en": "https://{...}/pod/0/profile/subitles-en.vtt"
      },
      "type": "pre",
      "duration": 10.0
    },
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/1/profile/1080p.m3u8",
        "360p": "https://{...}/pod/1/profile/360p.m3u8",
        "subtitles-en": "https://{...}/pod/1/profile/subitles-en.vtt"
      },
      "type": "mid",
      "start": 15.0,
      "duration": 15.0,
      "midroll_index": 1
    },
    {
      "manifest_urls":{
        "1080p": "https://{...}/pod/2/profile/1080p.m3u8",
        "360p": "https://{...}/pod/2/profile/360p.m3u8",
        "subtitles-en": "https://{...}/pod/2/profile/subitles-en.vtt"
      },
      "type": "post",
      "duration": 10.0
    }
  ]
Exemple de playlist de contenu multivariant
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="https://{...}/subitles-en.vtt"
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.4d000c,mp4a.40.5"
https://{...}/1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.4d000d,mp4a.40.5"
https://{...}/360p.m3u8
Exemple de données de variantes collectées
Encoding profile: "1080p"
Profile settings: {...}
Content manifest: https://{...}/1080p.m3u8
Ad pods (start time -> manifest):
    0 -> https://{...}/pod/0/profile/1080p.m3u8
   15 -> https://{...}/pod/1/profile/1080p.m3u8
  600 -> https://{...}/pod/2/profile/1080p.m3u8

Insérer des annonces dans le fichier manifeste de chaque variante

Pour chaque flux de variante, parcourez les segments du fichier manifeste de contenu en conservant un total cumulé du temps de contenu écoulé. Lorsque vous arrivez à la position de début d'une série d'annonces, extrayez la liste des segments du fichier manifeste de la série d'annonces, entourez-la de deux balises #EXT-X-DISCONTINUITY et insérez-la à l'emplacement actuel dans le fichier manifeste du contenu. Répétez cette procédure jusqu'à ce que tous les pods publicitaires et flux de variantes aient été traités.

Les fichiers manifestes obtenus doivent être conformes à la norme HLS. Par conséquent, selon les fonctionnalités de la spécification que votre fichier manifeste de contenu intègre, vous devrez peut-être effectuer une dernière vérification du fichier manifeste combiné pour corriger les numéros de séquence média, la durée du contenu, les numéros de séquence de discontinuité et toutes les autres balises qui doivent être mises à jour pour tenir compte des nouveaux segments d'annonces. Une fois que vous avez corrigé les éventuelles incohérences avec la norme, envoyez chaque fichier manifeste de variante spécifique à l'utilisateur à votre CDN pour l'hébergement.

Si votre fichier manifeste de contenu est chiffré, vous devez stocker la dernière clé de chiffrement trouvée avant le début du bloc d'annonces actuel dans une balise #EXT-X-KEY. Ensuite, vous devez ajouter le tag #EXT-X-KEY:METHOD=NONE pour supprimer le chiffrement avant le premier segment de chaque bloc d'annonces. Enfin, vous devez ajouter une copie du tag #EXT-X-KEY stocké avant le premier segment de contenu après chaque bloc d'annonces, afin de restaurer le chiffrement du contenu.

Exemple de données de variantes collectées
Encoding profile: "1080p"
Content manifest: https://{...}/1080p.m3u8
Ad pods (start time -> manifest):
    0 -> https://dai.google.com/{...}pod/0/profile/1080p.m3u8
   15 -> https://dai.google.com/{...}pod/1/profile/1080p.m3u8
  600 -> https://dai.google.com/{...}pod/2/profile/1080p.m3u8
Exemple de fichier manifeste de contenu

Il s'agit du contenu du fichier manifeste https://{...}/1080p.m3u8 listé dans les données de variantes collectées.

#EXTM3U
{...}
#EXTINF:5.000,
https://{...}/1080p/content-segment-0.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-1.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-2.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-3.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-4.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-5.ts
{...}
Exemple de fichier manifeste de série d'annonces

Il s'agit du contenu du fichier manifeste https://dai.google.com/{...}/pod/1/profile/1080p.m3u8 listé dans les données de variantes collectées.

#EXTM3U
{...}
#EXTINF:5.000,
https://dai.google.com/{...}/0.ts
#EXTINF:5.000,
https://dai.google.com/{...}/1.ts
#EXTINF:5.000,
https://dai.google.com/{...}/2.ts
Exemple de fichier manifeste de variante assemblée

Il s'agit du fichier manifeste de la variante assemblée résultante, transmis au CDN et hébergé à l'adresse https://cdn.{...}/{userid}/1080p.m3u8.

#EXTM3U
{...}
#EXTINF:5.000,
https://{...}/1080p/content-segment-0.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-1.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://dai.google.com/{...}/0.ts
#EXTINF:5.000,
https://dai.google.com/{...}/1.ts
#EXTINF:5.000,
https://dai.google.com/{...}/2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.000,
https://{...}/1080p/content-segment-3.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-4.ts
#EXTINF:5.000,
https://{...}/1080p/content-segment-5.ts
{...}

Créer une playlist de multivariantes

Collectez les adresses CDN pour chaque fichier manifeste de variante terminé, ainsi que les détails du profil d'encodage correspondant, et rassemblez les résultats dans un nouveau fichier manifeste multivariantes. Ce fichier manifeste spécifique à l'utilisateur est renvoyé en réponse à la demande de fichier manifeste que vous avez reçue à l'étape 1.

Exemple de playlist de multivariantes finale
#EXTM3U
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs0",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="https://cdn.{...}-subitles-en.vtt"
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.4d000c,mp4a.40.5"
https://cdn.{...}/{userid}/1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.4d000d,mp4a.40.5"
https://cdn.{...}/{userid}/360p.m3u8

Flux MPEG-DASH

Si vous assemblez un flux au format MPEG-DASH, vous n'avez besoin de produire qu'un seul fichier. Cela peut faciliter l'assemblage des flux DASH par rapport à HLS.

Un fichier de description de présentation multimédia MPEG-DASH (MPD) correctement préparé doit comporter plusieurs périodes, chacune contenant plusieurs représentations. Chaque représentation doit correspondre à l'un de vos profils d'encodage. Chaque série d'annonces renvoyée par Ad Manager est également un fichier MPD contenant une séquence de périodes avec des représentations correspondantes.

Pour assembler ces fichiers MPD, commencez par noter les heures de début de chaque bloc d'annonces. Pour les pré-rolls, insérez les périodes de bloc d'annonces pré-roll avant toute période de contenu. Pour les annonces post-roll, insérez les périodes de série d'annonces post-roll après toutes les périodes de contenu. Itérez sur les périodes du fichier MPD du contenu, en gardant une trace de la durée de lecture écoulée pour toutes les périodes de contenu traitées. Lorsque vous atteignez une limite entre des périodes qui correspond à l'heure de début d'une série d'annonces, insérez les périodes du fichier MPD de la série d'annonces mid-roll correspondante à cette limite.

Le fichier MPD final assemblé doit être entièrement conforme aux spécifications MPEG-DASH. Vous devrez peut-être l'examiner une dernière fois pour corriger les heures de début des périodes, ajuster la durée de la présentation multimédia afin de tenir compte des nouvelles périodes d'annonces insérées et résoudre tout autre conflit qui aurait pu survenir lors du processus d'assemblage.

Exemple de contenu MPD

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H10M00.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
  <ProgramInformation moreInformationURL="http://.../info">
    <Title>Example Stream</Title>
  </ProgramInformation>
  <Period duration="PT0H0M15.000S" id="content-period-1">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-2">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-3">
    ...
  </Period>
  ...
</MPD>

Exemple de fichier JSON pour un bloc d'annonces

[{
  "mpd_uri": "https://{...}pod/1.mpd",
  "type": "mid",
  "start": 15.0,
  "duration": 15.0,
  "midroll_index": 1
}]

Exemple de fichier MPD pour un pod d'annonces

Il s'agit du contenu de mpd_uri à partir du JSON du bloc d'annonces ci-dessus.

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H0M15.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
  <ProgramInformation moreInformationURL="http://.../info">
    <Title>Ad Pod 1</Title>
  </ProgramInformation>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-1">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-2">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-3">
    ...
  </Period>
  ...
</MPD>

Exemple de fichier MPD assemblé

Servez-le en réponse à la demande initiale de fichier manifeste du flux.

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H10M15.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011">
  <ProgramInformation moreInformationURL="http://.../info">
    <Title>Example Stream</Title>
  </ProgramInformation>
  <Period duration="PT0H0M15.000S" id="content-period-1">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-1">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-2">
    ...
  </Period>
  <Period duration="PT0H0M5.000S" id="ad-pod-1-period-3">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-2">
    ...
  </Period>
  <Period duration="PT0H0M15.000S" id="content-period-3">
    ...
  </Period>
  ...
</MPD>

Ressources supplémentaires