Manipulador de manifiestos para transmisiones de VOD

La API de Pod Serving proporciona acceso a los grupos de anuncios de video con tasa de bits adaptable preparados de modo que se puedan unir directamente en una playlist multimedia de HLS o MPEG-DASH para el usuario.

Esta guía se enfoca en la implementación de un servidor básico de manipulación de manifiestos de la entrega de Pods para las transmisiones de VOD.

Cómo recibir solicitudes del manifiesto de transmisión

Tu manipulador de manifiestos debe proporcionar un extremo de API para escuchar las solicitudes de manifiestos de la app cliente del reproductor de video. Como mínimo, este extremo debe recopilar un ID de transmisión de la app del reproductor cliente. Este ID de transmisión se usa para identificar la sesión de transmisión a Ad Manager en tus solicitudes de grupos de anuncios.

También debes recopilar otra información para identificar la transmisión de contenido adecuada, por ejemplo, un ID de contenido.

Ejemplo de extremo de solicitud del manifiesto

GET /api/stream_id/{stream_id}/video/{content_id}.{format}
Host: {your_domain}
Parámetros de ruta
stream_id El ID de transmisión de Ad Manager de la app cliente de reproductor de video
content_id Es un ID hipotético que corresponde al video de contenido en tu sistema.
format Es un parámetro hipotético que corresponde al formato de transmisión. Una de las siguientes opciones:
mpd Para transmisiones MPEG-DASH
m3u8 Para transmisiones HLS

Cómo recuperar la transmisión de contenido

Usa el Content ID recopilado de la solicitud del manifiesto para seleccionar el flujo de contenido que deseas unir con los anuncios.

Solicita manifiestos de grupos de anuncios

Para solicitar anuncios de Ad Manager, tu servidor debe hacer una solicitud POST al extremo de grupos de anuncios y pasar los perfiles de codificación, la etiqueta de anuncio y los parámetros de segmentación solicitados. Esta solicitud también incluye el ID de transmisión que recopilaste en el paso 1.

A cambio, recibes una lista de objetos de pods de anuncios que contienen archivos de manifiesto para los pods de anuncios solicitados por la etiqueta de anuncio del publicador, además de información sobre cuándo y dónde deben insertarse en tu contenido.

POST /ondemand/pods/api/v1/network/{network_code}/streams/{stream_id}/adpods
Host: dai.google.com
Content-Type: application/json
Parámetros de ruta
network_code El código de red de Ad Manager 360 del publicador.
stream_id El ID de transmisión de la app cliente de reproductor de video.

Cuerpo JSON

Parámetros corporales
encoding_profiles Required Una lista de representaciones JSON de los perfiles de codificación que deseas recibir para cada pausa publicitaria. Sigue leyendo para conocer más detalles

Para que la reproducción sea lo más fluida posible, debe coincidir con el conjunto de perfiles de codificación que se usan en la transmisión de contenido.

ad_tag Required Una etiqueta de anuncio para solicitar anuncios de VMAP.
cuepoints Optional Una lista de puntos de inserción dentro de la transmisión de contenido en los que se insertarán las pausas publicitarias durante el video. Los puntos de inserción se miden en segundos de punto flotante.

Obligatorio solo para las respuestas de VMAP que contienen anuncios durante el video que usan compensaciones de tiempo posicionales. Esto es poco común.

content_duration_seconds Optional Es la duración del contenido en segundos.

Obligatorio solo para las respuestas de VMAP que contienen anuncios durante el video con compensaciones de tiempo de porcentaje. Esto es poco común.

manifest_type Optional El formato de las transmisiones de anuncios que se solicitan, ya sea hls o dash. El valor predeterminado es hls.
dai_options Optional Opciones adicionales que controlan aspectos de la representación de los manifiestos. Sigue leyendo para conocer más detalles
Perfil de codificación
profile_name Required Es un identificador para este perfil de codificación. Este valor puede ser cualquier string que elijas, pero no puedes tener varios perfiles de codificación con el mismo nombre en la misma transmisión.
type Required El tipo de codificación de la transmisión que se describe en este perfil de codificación. Los tipos de contenido son media, iframe y subtitles.
container_type Required El formato de contenedor que usa este perfil de codificación. Los formatos de contenedor son los siguientes: mpeg2ts, fmp4cmaf y hls_packed_audio
video_settings Optional Obligatorio si el tipo de perfil de codificación es iframe. De lo contrario, solo se permite si el tipo de medio contiene video. Consulta los detalles a continuación
audio_settings Optional Obligatorio si el perfil de codificación contiene audio. Solo se permite si el tipo es multimedia. Sigue leyendo para conocer más detalles
subtitle_settings Optional Obligatorio si el perfil de codificación contiene subtítulos. Sigue leyendo para conocer más detalles
Configuración de video
codec Required La string de códec RFC6381.

Ejemplo: avc1.4d000c.

bitrate Required Es un número entero que representa la tasa de bits de video máxima de este perfil en bytes por segundo.
frames_per_second Required Es la cantidad de FPS de punto flotante del video.
resolution Required Es un valor codificado en JSON que contiene el "ancho" y la "altura" del video en píxeles.

Ejemplo: {"width": 640, "height": 320}.

Configuración de audio
codec Required La string de códec RFC6381.

Ejemplo: mp4a.40.5.

bitrate Required Es un número entero que representa la tasa de bits de audio máxima de este perfil en bytes por segundo.

Ejemplo: 300000.

channels Required Es un número entero que representa la cantidad de canales de audio, incluidos los canales de baja frecuencia.
sample_rate Required Es un número entero que representa la tasa de muestreo de audio en hercios.

Ejemplo: 4800.

Configuración de subtítulos
format Required El formato de archivo que usan los subtítulos dentro de la banda. Los valores admitidos son webvtt o ttml.
language Optional El idioma del subtítulo como una cadena de idioma RFC5646. Si se proporciona, este valor solo se usa para el procesamiento de DASH.

Ejemplo: en-us.

Opciones de DAI
dash_profile Optional Es el perfil de MPEG-DASH que se aplicará a los manifiestos de grupos de anuncios. Esta configuración solo se usa para los manifiestos de DASH. Los valores permitidos son live o on-demand. El valor predeterminado es on-demand.

El valor live corresponde al perfil de MPEG-DASH "urn:mpeg:dash:profile:isoff-live:2011".

El valor on-demand corresponde al perfil de MPEG-DASH urn:mpeg:dash:profile:isoff-on-demand:2011.

ad_pod_timeout Optional El tiempo máximo que se dedica a seleccionar anuncios y crear grupos de anuncios, en segundos de punto flotante. Una vez transcurrido ese tiempo, Ad Manager mostrará todos los anuncios que ya estén seleccionados en la respuesta ad_pods y dejará de procesar.
sam_id Optional Especifica una clave de depuración alternativa que se puede usar para buscar sesiones en la supervisión de actividad de transmisión.

Respuesta

Parámetros de respuesta
valid_for La duración de la validez de estas playlists del grupo de anuncios, en formato dhms (días, horas, minutos y segundos).
valid_until Es la fecha y la hora hasta la cual estas playlists de grupos de anuncios son válidas como una cadena de fecha y hora ISO8601 en formato yyyy-MM-dd'T'hh:mm:ss.sssssssss[+|-]hh:mm.
ad_pods Es una lista de grupos de anuncios seleccionados para esta transmisión.
Grupo de anuncios
manifest_uris Solo para transmisiones HLS. Mapa de los IDs de perfil de codificación para los URI del manifiesto de HLS.
mpd_uri Solo para transmisiones DASH. El URI de la MPD de DASH.
type Es el tipo de grupo de anuncios. Los tipos de grupos de anuncios son pre, mid o post.
start Solo para grupos de anuncios durante el video. Es la posición en la transmisión en la que se debe insertar este grupo de anuncios, en segundos de punto flotante.
duration Es la duración de este grupo de anuncios, expresada en segundos de punto flotante.
midroll_index Solo para grupos de anuncios durante el video. Es el índice del grupo de anuncios actual de anuncios durante el video. La indexación comienza con 1.

Ejemplo de solicitud (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

Ejemplo de cuerpo de la solicitud

Este es el contenido de request-body.json al que se hace referencia en la llamada cURL anterior.

{
  "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"
}

Ejemplo de respuesta

{
  "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
    }
  ]
}

Une grupos de anuncios en el contenido

El proceso de unir grupos de anuncios a tus transmisiones de contenido varía según la implementación, el formato de transmisión y las funciones que elijas implementar a partir de las especificaciones del formato. Los siguientes flujos de trabajo son sugerencias para controlar este proceso. Los detalles precisos de tu implementación pueden variar según las necesidades de tu empresa y los flujos de contenido.

Transmisiones HLS

Si estás uniendo una transmisión en formato HLS, tu transmisión de contenido será una playlist de múltiples variantes de vínculos a manifiestos de transmisión separados, uno para cada perfil de codificación. Tus grupos de anuncios deben insertarse en cada uno de los manifiestos de estas variantes. Una forma de hacerlo es preparar todos los manifiestos de variantes y pasarlos a una red de distribución de contenidos (CDN) para alojarlos. La playlist final de múltiples variantes es un conjunto de vínculos a estos manifiestos alojados en CDN.

Realiza iteraciones en perfiles de codificación

Para cada perfil de codificación, recopila todos los manifiestos de Pods de anuncios asociados a partir de la respuesta de Ad Manager, junto con sus horas de inicio asociadas. Para los grupos de anuncios previos al video, establece la hora de inicio en 0. Para los anuncios al final del video, usa la duración del contenido como la hora de inicio del grupo de anuncios. Identifica la transmisión de variantes en la playlist de múltiples variantes que coincida con la configuración de audio y video de cada perfil de codificación.

Ejemplo de array de grupos de anuncios
"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
    }
  ]
Ejemplo de playlist de contenido de múltiples variantes
#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
Ejemplos de datos de variantes recopilados
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

Inserta anuncios en el manifiesto de cada variante

Para la transmisión de cada variante, revisa los segmentos del manifiesto de contenido y mantén un total activo del tiempo de contenido transcurrido. Cuando llegues a la posición de inicio de un grupo de anuncios, extrae la lista de segmentos del manifiesto del grupo de anuncios, une la lista de segmentos en dos etiquetas #EXT-X-DISCONTINUITY y, luego, inserta la lista en la ubicación actual en el manifiesto de contenido. Continúa con este proceso hasta que se hayan procesado todos los grupos de anuncios y las transmisiones de variantes.

Los manifiestos resultantes deben cumplir con el estándar HLS. Por lo tanto, según las funciones de la especificación que incorpore tu manifiesto de contenido, es posible que debas realizar un último pase por el manifiesto combinado para corregir los números de las secuencias de medios, la duración del contenido, los números de la secuencia de discontinuidad y cualquier otra etiqueta que deban actualizarse para tener en cuenta los nuevos segmentos de anuncios. Una vez que se hayan corregido las discrepancias con el estándar, envía el manifiesto de cada variante específica del usuario a tu CDN para alojarla.

Si el manifiesto de contenido está encriptado, debes almacenar la última clave de encriptación que se encontró antes del inicio del grupo de anuncios actual en una etiqueta #EXT-X-KEY. Luego, debes agregar la etiqueta #EXT-X-KEY:METHOD=NONE para quitar la encriptación antes del primer segmento de cada Pod de anuncios. Por último, debes agregar una copia de la etiqueta #EXT-X-KEY almacenada antes del primer segmento de contenido después de cada Pod de anuncios para restablecer la encriptación de contenido.

Ejemplos de datos de variantes recopilados
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
Ejemplo de manifiesto de contenido

Este es el contenido del manifiesto https://{...}/1080p.m3u8 que se incluye en los datos de variantes recopilados.

#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
{...}
Ejemplo de manifiesto de grupo de anuncios

Este es el contenido del manifiesto https://dai.google.com/{...}/pod/1/profile/1080p.m3u8 que se enumera en los datos de variantes recopilados.

#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
Ejemplo de manifiesto de una variante unida

Este sería el manifiesto resultante de la variante unida, que se pasa a la CDN y se aloja en 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
{...}

Cómo crear una playlist de múltiples variantes

Recopila las direcciones de CDN de cada manifiesto de variante completo, junto con los detalles del perfil de codificación que coincida, y ensambla los resultados en un manifiesto de múltiples variantes nuevo. Este manifiesto específico para el usuario se muestra como respuesta a la solicitud del manifiesto que recibiste en el paso 1.

Ejemplo de playlist final de múltiples variantes
#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

Transmisiones MPEG DASH

Si estás uniendo una transmisión en formato MPEG DASH, solo necesitas producir un solo archivo. Esto puede hacer que las transmisiones DASH sean más fáciles de unir que las de HLS.

Un archivo de descripción de presentación multimedia (MPD) MPEG DASH preparado correctamente debe constar de varios puntos, y cada uno de ellos contiene varias representaciones. Cada representación debe coincidir con uno de tus perfiles de codificación. Cada grupo de anuncios que muestra Ad Manager es también un archivo MPD que contiene una secuencia de períodos con representaciones coincidentes.

Para unir estos archivos MPD, comienza por tomar nota de los tiempos de inicio de cada grupo de anuncios. Para los anuncios previos al video, inserta los períodos del grupo de anuncios previos al video antes de cualquier período de contenido. Para los anuncios al final del video, inserta los períodos de grupos de anuncios al final del video después de todos los períodos de contenido. Itera los períodos en la MPD de contenido y realiza un seguimiento del tiempo de reproducción transcurrido para todos los períodos de contenido procesados. Cuando alcances un límite entre períodos que correspondan a la hora de inicio de un grupo de anuncios, inserta los puntos del archivo MPD del grupo de anuncios durante el video correspondiente en ese límite.

El archivo MPD final unido debe cumplir por completo con las especificaciones MPEG_DASH, por lo que es posible que debas iterar en el archivo final una vez más, corregir los tiempos de inicio de cualquier período, corregir la duración de la presentación multimedia para tener en cuenta los períodos del anuncio insertados recientemente y resolver cualquier otro conflicto que pueda haber surgido en el proceso de unión.

Ejemplo de MPD de contenido

<?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>

Ejemplo de JSON de grupo de anuncios

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

Ejemplo de MPD del grupo de anuncios

Este es el contenido de mpd_uri del JSON del grupo de anuncios anterior.

<?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>

Ejemplo de MPD unido

Ofrécele esto como respuesta a la solicitud inicial del manifiesto de transmisión.

<?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>

Recursos adicionales