Processar metadados cronometrados

Selecione a plataforma:HTML5 Roku

O SDK de inserção dinâmica de anúncios (DAI, na sigla em inglês) do Interactive Media Ads (IMA) depende de informações de metadados incorporadas nos segmentos de mídia do stream (metadados na banda) ou no arquivo de manifesto de streaming (metadados no manifesto) para rastrear as posições dos espectadores e os eventos de anúncios do lado do cliente. Os metadados são enviados em formatos diferentes, dependendo do tipo de stream que está sendo reproduzido.

O player de vídeo recebe metadados com carimbo de data/hora em lotes. Dependendo do player, os metadados podem ser exibidos no horário programado ou em lotes. Cada string de metadados tem um carimbo de data/hora de apresentação (PTS) associado para quando ela deve ser acionada.

Seu app é responsável por capturar metadados e encaminhá-los ao SDK DAI do IMA. O SDK oferece os seguintes métodos para transmitir essas informações:

onTimedMetadata

Esse método encaminha strings de metadados prontas para serem processadas para o SDK. Ele usa um único argumento:

  • metadata: um objeto que contém uma chave de TXXX com um valor de string associado prefixado por google_.
processMetadata

Esse método agenda o processamento de strings de metadados pelo SDK após o PTS especificado. Ele usa os seguintes argumentos:

  • type: uma string que contém o tipo de evento que está sendo processado. Os valores aceitos são ID3 para HLS ou urn:google:dai:2018 para DASH.
  • data: um valor de string com o prefixo google_ ou uma matriz de bytes que segue este formato: ID3:u\0004u\000u\000u\0000TXXXu\0004u\000u\000u\0000google_xxxxxxxx.
  • timestamp: o carimbo de data/hora em segundos em que os dados devem ser processados.

Cada tipo de stream compatível com o SDK do IMA DAI usa uma forma exclusiva de metadados com carimbo de data/hora, conforme descrito nas seções a seguir.

Transmissões HLS MPEG2TS

Os streams HLS de DAI linear que usam segmentos MPEG2TS transmitem metadados com carimbo de data/hora para o player de vídeo usando tags ID3 no canal. Essas tags ID3 são incorporadas aos segmentos MPEG2TS e recebem o nome de campo TXXX (para conteúdo de texto personalizado definido pelo usuário).

Reprodução no Safari

O Safari processa tags ID3 automaticamente, como uma faixa oculta, para que os eventos cuechange sejam acionados no momento certo para processar cada parte dos metadados. Não há problema em transmitir todos os metadados para o SDK de DAI do IMA, independente do conteúdo ou tipo. Metadados irrelevantes são filtrados automaticamente.

Veja um exemplo:

videoElement.textTracks.addEventListener('addtrack', (e) => {
  const track = e.track;
  if (track.kind === 'metadata') {
    track.mode = 'hidden';
    track.addEventListener('cuechange', () => {
      for (const cue of track.activeCues) {
        const metadata = {};
        metadata[cue.value.key] = cue.value.data;
        streamManager.onTimedMetadata(metadata);
      }
    });
  }
});
...

HLS.js

O HLS.js fornece tags ID3 em lotes pelo evento FRAG_PARSING_METADATA, como uma matriz de amostras. O HLS.js não traduz os dados ID3 de matrizes de bytes para strings e não compensa os eventos para os PTS correspondentes. Não é necessário decodificar os dados de amostra de matriz de bytes para string nem filtrar tags ID3 irrelevantes, já que o SDK de DAI do IMA realiza essa decodificação e filtragem automaticamente.

Veja um exemplo:

hls.on(Hls.Events.FRAG_PARSING_METADATA, (e, data) => {
  if (streamManager && data) {
    data.samples.forEach((sample) => {
      streamManager.processMetadata('ID3', sample.data, sample.pts);
    });
  }
});
...

Transmissões HLS CMAF

Os fluxos HLS de DAI linear que usam o Common Media Application Framework (CMAF) transmitem metadados com carimbo de data/hora por caixas eMSGv1 em banda seguindo o padrão ID3 por CMAF. Essas caixas eMSG são incorporadas no início de cada segmento de mídia, e cada eMSG ID3 contém um PTS relativo à última descontinuidade no stream.

A partir da versão 1.2.0 do HLS.js, os dois players sugeridos transmitem ID3 pelo CMAF ao usuário como se fossem tags ID3. Por isso, os exemplos a seguir são os mesmos das transmissões HLS MPEG2TS. No entanto, isso pode não acontecer com todos os players. Por isso, a implementação do suporte a streams HLS CMAF pode exigir um código exclusivo para analisar ID3 por eMSG.

Reprodução no Safari

O Safari trata o ID3 por metadados eMSG como pseudo eventos ID3, fornecendo-os em lotes, automaticamente, como uma faixa oculta, para que os eventos cuechange sejam acionados no momento certo para processar cada parte dos metadados. Não há problema em transmitir todos os metadados para o SDK de DAI da IMA, sejam eles relevantes para o tempo ou não. Todos os metadados não relacionados à DAI são filtrados automaticamente.

Veja um exemplo:

videoElement.textTracks.addEventListener('addtrack', (e) => {
  const track = e.track;
  if (track.kind === 'metadata') {
    track.mode = 'hidden';
    track.addEventListener('cuechange', () => {
      for (const cue of track.activeCues) {
        const metadata = {};
        metadata[cue.value.key] = cue.value.data;
        streamManager.onTimedMetadata(metadata);
      }
    });
  }
});
...

HLS.js

A partir da versão 1.2.0, o HLS.js trata o ID3 por metadados eMSG como pseudo eventos ID3, fornecendo-os em lotes, pelo evento FRAG_PARSING_METADATA, como uma matriz de amostras. O HLS.js não traduz os dados ID3 de matrizes de bytes para strings e não compensa os eventos para os PTS correspondentes. Não é necessário decodificar os dados de amostra de matriz de bytes para string, já que o SDK de DAI do IMA faz isso automaticamente.

Veja um exemplo:

hls.on(Hls.Events.FRAG_PARSING_METADATA, (e, data) => {
  if (streamManager && data) {
    data.samples.forEach((sample) => {
      streamManager.processMetadata('ID3', sample.data, sample.pts);
    });
  }
});
...

Streams DASH

Os fluxos DASH de DAI linear transmitem metadados como eventos de manifesto em um fluxo de eventos com o valor urn:google:dai:2018 schemeIdUri personalizado. Cada evento nesses fluxos contém um payload de texto e o PTS.

DASH.js

O Dash.js fornece manipuladores de eventos personalizados nomeados de acordo com o valor schemeIdUri de cada stream de eventos. Esses manipuladores personalizados são disparados em lotes, deixando para você processar o valor de PTS para definir o tempo correto do evento. O SDK do IMA DAI pode fazer isso para você com o método streamManager, processMetadata().

Veja um exemplo:

const dash = dashjs.MediaPlayer().create();
dash.on('urn:google:dai:2018', (payload) => {
  const mediaId = payload.event.messageData;
  const pts = payload.event.calculatedPresentationTime;
  streamManager.processMetadata('urn:google:dai:2018', mediaId, pts);
});
...

Shaka Player

O Shaka Player mostra eventos como parte do evento timelineregionenter. Devido a uma incompatibilidade de formatação com o Shaka Player, o valor de metadados precisa ser recuperado sem tratamento, usando a propriedade de detalhes eventNode.attributes['messageData'].

Veja um exemplo:

player.addEventListener('timelineregionenter', function(event) {
  const detail = event.detail;
  if ( detail.eventNode.attributes &&
       detail.eventNode.attributes['messageData']) {
    const mediaId = detail.eventNode.attributes['messageData'];
    const pts = detail.startTime;
    streamManager.processMetadata("urn:google:dai:2018", mediaId, pts);
  }
});
...

Veiculação de conjuntos

Para veiculação de pods, há diferentes configurações para transmitir metadados com carimbo de data/hora, dependendo dos seguintes critérios:

  • Tipo de transmissão ao vivo ou VOD
  • Formato de stream HLS ou DASH
  • O tipo de player usado
  • O tipo de back-end da DAI usado

Formato de transmissão HLS (transmissões ao vivo e VOD, player HLS.js)

Se você estiver usando um player HLS.js, detecte o evento FRAG_PARSING_METADATA do HLS.js para receber metadados ID3 e transmiti-los ao SDK com StreamManager.processMetadata().

Para reproduzir o vídeo automaticamente depois que tudo for carregado e estiver pronto, ouça o evento MANIFEST_PARSED do HLS.js para acionar a reprodução.

function loadStream(streamID) {
  hls.loadSource(url);
  hls.attachMedia(videoElement);
  
  // Timed metadata is passed HLS stream events to the streamManager.
  hls.on(Hls.Events.FRAG_PARSING_METADATA, parseID3Events);
  hls.on(Hls.Events.MANIFEST_PARSED, startPlayback);
}

function parseID3Events(event, data) {
  if (streamManager && data) {
    // For each ID3 tag in the metadata, pass in the type - ID3, the
    // tag data (a byte array), and the presentation timestamp (PTS).
    data.samples.forEach((sample) => {
      streamManager.processMetadata('ID3', sample.data, sample.pts);
    });
  }
}

function startPlayback() {
  console.log('Video Play');
  videoElement.play();
}

DASH.js (formato de transmissões DASH, tipo de transmissão ao vivo e VOD)

Se você estiver usando um player DASH.js, use strings diferentes para detectar metadados ID3 em transmissões ao vivo ou de VOD:

  • Transmissões ao vivo: 'https://developer.apple.com/streaming/emsg-id3'
  • Streams de VOD: 'urn:google:dai:2018'

Transmita os metadados ID3 para o SDK com StreamManager.processMetadata().

Para mostrar automaticamente os controles de vídeo depois que tudo estiver carregado e pronto, ouça o evento MANIFEST_LOADED do DASH.js.

const googleLiveSchema = 'https://developer.apple.com/streaming/emsg-id3';
const googleVodSchema = 'urn:google:dai:2018';
dashPlayer.on(googleLiveSchema, processMetadata);
dashPlayer.on(googleVodSchema, processMetadata);
dashPlayer.on(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);

function processMetadata(metadataEvent) {
  const messageData = metadataEvent.event.messageData;
  const timestamp = metadataEvent.event.calculatedPresentationTime;

  // Use StreamManager.processMetadata() if your video player provides raw
  // ID3 tags, as with dash.js.
  streamManager.processMetadata('ID3', messageData, timestamp);
}

function loadlistener() {
  showControls();

  // This listener must be removed, otherwise it triggers as addional
  // manifests are loaded. The manifest is loaded once for the content,
  // but additional manifests are loaded for upcoming ad breaks.
  dashPlayer.off(dashjs.MediaPlayer.events.MANIFEST_LOADED, loadlistener);
}

Shaka Player com transmissões ao vivo (formato de transmissões DASH)

Se você estiver usando o Shaka Player para reprodução de transmissões ao vivo, use a string 'emsg' para detectar eventos de metadados. Em seguida, use os dados da mensagem de evento na sua chamada para StreamManager.onTimedMetadata().

shakaPlayer.addEventListener('emsg', (event) => onEmsgEvent(event));

function onEmsgEvent(metadataEvent) {
  // Use StreamManager.onTimedMetadata() if your video player provides
  // processed metadata, as with Shaka player livestreams.
  streamManager.onTimedMetadata({'TXXX': metadataEvent.detail.messageData});
}

Shaka Player com streams de VOD (formato de streams DASH)

Se você estiver usando o Shaka Player para reprodução de stream de VOD, use a string 'timelineregionenter' para detectar eventos de metadados. Em seguida, use os dados da mensagem de evento na sua chamada para StreamManager.processMetadata() com a string 'urn:google:dai:2018'.

shakaPlayer.addEventListener('timelineregionenter', (event) => onTimelineEvent(event));

function onTimelineEvent(metadataEvent) {
  const detail = metadataEvent.detail;
  if ( detail.eventElement.attributes &&
       detail.eventElement.attributes['messageData'] &&
       detail.eventElement.attributes['messageData'].value ) {
        const mediaId = detail.eventElement.attributes['messageData'].value;
        const pts = detail.startTime;
        // Use StreamManager.processMetadata() if your video player provides raw
        // ID3 tags, as with Shaka player VOD streams.
        streamManager.processMetadata('urn:google:dai:2018', mediaId, pts);
       }
}