Manipulador de manifiestos para transmisiones de VOD

La API de Publicación de grupos de anuncios proporciona acceso a grupos de anuncios de video con tasa de bits adaptable preparados de manera tal que se puedan unir directamente a una playlist de contenido multimedia HLS o MPEG-DASH para usuarios.

Esta guía se enfoca en implementar un servidor básico de manipulación de manifiestos de Pod Serving para transmisiones de VOD.

Cómo recibir solicitudes de manifiesto de transmisión

Tu manipulador de manifiestos debe proporcionar un extremo de API para escuchar 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 en Ad Manager en tus solicitudes de grupos de anuncios.

También debes recopilar otra información para identificar el flujo de contenido adecuado, por ejemplo, un ID de contenido.

Ejemplo de extremo de solicitud de 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 del reproductor de video cliente
content_id Un ID hipotético que corresponde al video de contenido de tu sistema.
format Es un parámetro hipotético que corresponde al formato de transmisión. Una de las siguientes opciones:
mpd Para transmisiones de MPEG-DASH
m3u8 Para transmisiones HLS

Cómo recuperar la transmisión de contenido

Usa el ID de contenido recopilado de la solicitud de manifiesto para seleccionar la transmisión de contenido que se unirá con los anuncios.

Solicita manifiestos de grupos de anuncios

Para solicitar anuncios de Ad Manager, tu servidor debe realizar una solicitud POST al extremo de los grupos de anuncios y pasar los perfiles de codificación y la etiqueta de anuncio 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 grupo de anuncios que contienen archivos de manifiesto para los grupos de anuncios solicitados por la etiqueta de anuncio del publicador y la información sobre cuándo y dónde se deben insertar 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 Es el ID de flujo de la app de reproductor de video cliente.

Cuerpo JSON

Parámetros del cuerpo
encoding_profiles Required Es 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 tu transmisión de contenido.

ad_tag Required Una etiqueta de anuncio para solicitar anuncios de VMAP.
cuepoints Optional Es 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.

Es obligatorio solo para las respuestas de VMAP que contienen anuncios durante el video con compensaciones de tiempo posicionales. Esto no es común.

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

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

manifest_type Optional Es el formato de las transmisiones de anuncios que se solicitan, ya sea hls o dash. El valor predeterminado es hls.
dai_options Optional Son opciones adicionales que controlan aspectos de cómo se renderizan 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 cadena que elijas, pero no puedes tener varios perfiles de codificación con el mismo nombre en la misma transmisión.
type Required Es el tipo de codificación de la transmisión que describe este perfil de codificación. Los tipos de contenido son media, iframe y subtitles.
container_type Required Es 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 Es obligatorio si el tipo de perfil de codificación es iframe. De lo contrario, solo se permite si el tipo de contenido multimedia 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 media. 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 cadena 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 Los FPS de punto flotante del video.
resolution Required Es un valor con codificación 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 cadena 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 Es el formato de archivo que usan los subtítulos integrados en la transmisión. Los valores admitidos son webvtt o ttml.
language Optional Es el idioma de los subtítulos como una cadena de idioma RFC5646. Si se proporciona, este valor solo se usa para la renderización 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. Este parámetro de configuración solo se usa para manifiestos DASH. Los valores permitidos son live o on-demand. El valor predeterminado es on-demand.

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

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

ad_pod_timeout Optional Es el tiempo máximo que se puede dedicar a seleccionar anuncios y crear grupos de anuncios, expresado en segundos de punto flotante. Una vez transcurrido este tiempo, Ad Manager muestra los anuncios que ya se seleccionaron en la respuesta ad_pods y detiene el procesamiento.
sam_id Optional Especifica una clave de depuración alternativa que se puede usar para buscar sesiones en el supervisor de actividad de transmisión.

Respuesta

Parámetros de respuesta
valid_for Es la duración durante la cual estas playlists de grupos de anuncios son válidas en formato dhms (días, horas, minutos y segundos).
valid_until Es la fecha y hora hasta la que 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. Un mapa de IDs de perfiles de codificación a URIs de manifiestos de HLS.
mpd_uri Solo para transmisiones DASH. Es el URI del 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 en segundos de punto flotante.
midroll_index Solo para grupos de anuncios durante el video. Es el índice del grupo de anuncios durante el video actual. El indexado 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 a 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
    }
  ]
}

Cómo unir grupos de anuncios al contenido

El proceso de unir grupos de anuncios a tus transmisiones de contenido varía según la implementación, el formato de la 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 la implementación pueden variar según las necesidades de tu empresa y tus flujos de contenido.

Transmisiones HLS

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

Iteración sobre perfiles de codificación

Para cada perfil de codificación, recopila todos los manifiestos de grupos de anuncios asociados 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 variante en la playlist de varias 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
Ejemplo 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

Cómo insertar anuncios en cada manifiesto de variante

Para cada transmisión de variantes, revisa los segmentos del manifiesto de contenido y mantén un total general 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, insértala en la ubicación actual del manifiesto de contenido. Continúa con este proceso hasta que se hayan procesado todos los grupos de anuncios y los flujos 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 pase final por el manifiesto combinado para corregir los números de secuencia de contenido multimedia, la duración del contenido, los números de secuencia de discontinuidad y cualquier otra etiqueta que deba actualizarse para tener en cuenta los nuevos segmentos de anuncios. Una vez que se hayan corregido las discrepancias con el estándar, envía cada manifiesto de variante específica del usuario a tu CDN para su alojamiento.

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 grupo 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 grupo de anuncios para restablecer la encriptación del contenido.

Ejemplo 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 indica 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 indica 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 variante cosida

Este sería el manifiesto de variante cosida resultante, 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 completado, junto con los detalles del perfil de codificación coincidentes, y reúne los resultados en un nuevo manifiesto multivariante. Este manifiesto específico del usuario se muestra como la respuesta a la solicitud de manifiesto que recibiste en el paso 1.

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

Si unes una transmisión en formato MPEG DASH, solo debes producir un archivo. Esto puede facilitar la unión de transmisiones DASH en comparación con HLS.

Un archivo de descripción de presentación multimedia (MPD) de MPEG DASH preparado de forma correcta debe consistir en varios períodos, cada uno de los cuales contiene varias representaciones. Cada representación debe coincidir con uno de tus perfiles de codificación. Cada grupo de anuncios que se muestra desde Ad Manager también es un archivo MPD que contiene una secuencia de períodos con representaciones coincidentes.

Para unir estos archivos MPD, primero toma nota de las horas de inicio de cada grupo de anuncios. Para los anuncios previos al video, inserta los períodos de los grupos de anuncios previos al video antes de cualquier período de contenido. Para los anuncios al final del video, inserta los períodos de los grupos de anuncios al final del video después de todos los períodos del contenido. Itera sobre los períodos del MPD de contenido y haz un seguimiento del tiempo de reproducción transcurrido de todos los períodos de contenido procesados. Cuando llegues a un límite entre períodos que corresponda a la hora de inicio de un grupo de anuncios, inserta los períodos del archivo MPD del grupo de anuncios durante el video coincidente en ese límite.

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

MPD de ejemplo 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 de 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

Envía 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