Manipulador de manifiestos para transmisiones de VOD

La API de Pod Serving proporciona acceso a grupos de anuncios de video con tasa de bits adaptable preparados de tal manera que se puedan unir directamente a una lista de reproducción multimedia HLS o MPEG-DASH orientada al usuario.

Esta guía se enfoca en la implementación de un servidor de manipulación básico del manifiesto de Publicación de Pods para transmisiones de VOD.

Cómo recibir solicitudes de manifiesto de transmisión

El manipulador de manifiestos debe proporcionar un extremo de API para escuchar las solicitudes de manifiesto 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 las solicitudes de grupos de anuncios.

También debes recopilar otra información para identificar la transmisión de contenido adecuada, como 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 de acceso
stream_id Es el ID de transmisión de Ad Manager de la aplicación de reproductor de video del cliente.
content_id Un ID hipotético que corresponde al video de contenido de tu sistema.
format Un parámetro hipotético que corresponde al formato de transmisión. Uno de los siguientes:
mpd Para transmisiones MPEG-DASH
m3u8 Para transmisiones HLS

Recuperar la transmisión de contenido

Usa el Content ID que se recopiló en la solicitud del manifiesto para seleccionar el flujo de contenido que se unirá con los anuncios.

Solicitar manifiestos de grupos de anuncios

Para solicitar anuncios de Ad Manager, tu servidor debe realizar una solicitud POST al extremo de grupos de anuncios pasando 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 grupos de anuncios que contienen archivos de manifiesto para los grupos 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 de acceso
network_code Es 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 Es una lista de puntos de inserción en 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.

Solo es obligatorio para las respuestas de VMAP que contienen anuncios durante el video con compensaciones de tiempo posicionales. Este problema 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 percentage. Este problema es poco común.

manifest_type Optional Corresponde al 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 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 Es 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, 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 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 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 Un número entero que representa la tasa de bits de video máxima para este perfil en bytes por segundo.
frames_per_second Required Indica el punto flotante de FPS 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 Un número entero que representa la tasa de bits de audio máxima para 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 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 Formato de archivo que usan los subtítulos dentro de la banda. Los valores admitidos son webvtt o ttml.
language Optional El idioma de los subtítulos como una string de idioma RFC 5646. 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. 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 Es 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á los anuncios que ya se hayan seleccionado en la respuesta ad_pods y dejará de procesarse.
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 Es la duración válida en formato dhms (días, horas, minutos y segundos) de estas playlists de grupos de anuncios.
valid_until Corresponde a la fecha y hora hasta la que estas playlists de grupos de anuncios son válidas como una string 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. Es un 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 durante el video actual. 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 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 unión de grupos de anuncios a tus transmisiones de contenido varía según tu 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 las transmisiones de contenido.

Transmisiones HLS

Si unes una transmisión en formato HLS, tu transmisión de contenido será una lista de reproducción de múltiples variantes 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 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 el hosting. La playlist final de múltiples variantes es un conjunto de vínculos a estos manifiestos alojados en CDN.

Cómo iterar en perfiles de codificación

Para cada perfil de codificación, recopila todos los manifiestos de grupos 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
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

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 inicial 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 del manifiesto de contenido. Continúa este proceso hasta que se procesen 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 repaso del manifiesto combinado para corregir los números de secuencias de medios, la duración del contenido, los números de secuencia de discontinuidad y cualquier otra etiqueta que deban actualizarse para tener en cuenta los segmentos de anuncios nuevos. 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 hosting.

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.

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 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 del grupo de anuncios

Este es el contenido del manifiesto https://dai.google.com/{...}/pod/1/profile/1080p.m3u8 que aparece 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 unida

Este sería el manifiesto de la variante unida 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
{...}

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 de 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 el formato MPEG DASH, solo necesitas producir un único archivo. Esto puede hacer que las transmisiones DASH sean más fáciles de unir que las que se realizan con HLS.

Un archivo de descripción de presentación multimedia (MPD) MPEG DASH preparado correctamente debe constar de varios puntos, cada uno con 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 puntos 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 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 del grupo de anuncios al final del video después de todos los períodos de contenido. Itera durante los períodos en la MPD de contenido y haz 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 períodos del archivo MPD del grupo de anuncios durante el video coincidente 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 sobre el archivo final una vez más para corregir cualquier hora de inicio del 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 podría haber surgido del 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 unida

Actúa 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