Processar metadados cronometrados em streams da DAI linear

O SDK de Inserção de anúncios dinâmicos (DAI) do Interactive Media Ads (IMA) depende informações de metadados incorporadas em segmentos de mídia da transmissão (metadados em banda), ou no arquivo de manifesto de streaming (metadados no manifesto) para rastrear posições e eventos de anúncio do lado do cliente. Os metadados são enviados em formatos diferentes, dependendo do tipo de transmissão.

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

Seu app é responsável por capturar e encaminhar metadados ao SDK de 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 do Vertex AI Pipelines. Ele usa um único argumento:

  • metadata: um objeto que contém uma chave de TXXX com uma string associada. com o prefixo google_.
processMetadata

Esse método programa strings de metadados para serem processadas pelo SDK após o evento o PTS especificado. Ele usa os seguintes argumentos:

  • type: uma string que contém o tipo de evento que está sendo processado. Aceito os valores são ID3 para HLS ou urn:google:dai:2018 para DASH
  • data: um valor de string prefixado por google_ ou uma matriz de bytes que decodifica de acordo com essa string.
  • timestamp: o carimbo de data/hora em segundos em que os dados precisam ser processados.

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

Streams HLS MPEG2TS

Os streams HLS da DAI linear que usam segmentos MPEG2TS transmitem metadados cronometrados ao de vídeo do YouTube por meio de tags ID3 em banda. Essas tags ID3 são incorporadas MPEG2TS e recebem o nome de campo TXXX (para textos personalizados definidos pelo usuário conteúdo).

Reprodução no Safari

O Safari processa tags ID3 automaticamente, como uma faixa oculta, ou seja, os eventos cuechange. disparar no momento certo para processar cada parte dos metadados. Não há problema em passar todos os metadados para o SDK de DAI do IMA, independentemente do conteúdo ou tipo. Irrelevantes os metadados 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. HLS.js não converte os dados ID3 de matrizes de bytes para strings e não desloca eventos para o PTS correspondente. Não é necessário para decodificar os dados de amostra da matriz de bytes para string ou para filtrar tags ID3 irrelevantes, já que o SDK de DAI do IMA realiza essa decodificação 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 do HLS CMAF

Streams HLS da DAI linear usando a passagem do Common Media Application Framework (CMAF) metadados cronometrados por meio de caixas eMSGv1 em banda seguindo as orientações de ID3 a CMAF padrão. Estas caixas eMSG são incorporado no início de cada segmento de mídia, com cada eMSG ID3 contendo um PTS relativo à última descontinuidade no stream.

A partir da versão 1.2.0 do HLS.js, nossos dois players sugeridos passam ID3 pelo CMAF, para o usuário, como se fossem tags ID3. Por esse motivo, a os exemplos a seguir são os mesmos dos streams HLS MPEG2TS. No entanto, isso pode não ocorrer com todos os jogadores. Por isso, implementar o suporte para a HLS CMAF de streaming podem exigir um código exclusivo para analisar o ID3 com o eMSG.

Reprodução no Safari

O Safari trata os metadados ID3 com eMSG como eventos pseudoID3, fornecendo-os em lotes, automaticamente, como uma faixa oculta, de modo que eventos cuechange sejam disparados no momento certo para processar cada metadado. Não há problema em transmitir todos os metadados para o SDK de DAI do IMA, sejam relevantes para o momento ou não. Qualquer um 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 os metadados ID3 com eMSG como pseudoID3 , fornecendo-os em lotes, por meio do evento FRAG_PARSING_METADATA como uma matriz de amostras. O HLS.js não converte os dados ID3 de matrizes de bytes às strings e não desloca eventos para o PTS correspondente. Não é necessário para decodificar os dados de amostra da matriz de bytes para a string, já que o SDK de DAI do IMA realiza essa decodificação 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 de DASH

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

DASH.js

A Dash.js fornece manipuladores de eventos personalizados nomeados de acordo com o valor de schemeIdUri de cada fluxo de eventos. Esses gerenciadores personalizados são acionados em lotes, deixando você processar o valor PTS para cronometrar corretamente o evento. O SDK de DAI do IMA lida com 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);
});
...

Tocador shaka

O Shaka Player mostra eventos como parte do evento timelineregionenter. Valor devido incompatibilidade de formatação com o Shaka Player, o valor de metadados deve ser recuperados brutos, por meio da propriedade de detalhe eventElement.attributes['messageData'].value:

Veja um exemplo:

player.addEventListener('timelineregionenter', function(event) {
  const detail = event.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;
    streamManager.processMetadata("urn:google:dai:2018", mediaId, pts);
  }
});
...

Disponibilização de conjuntos

Para a disponibilização de pods, há diferentes configurações para transmitir cronometrados metadados, dependendo dos seguintes critérios:

  • Tipo de transmissão ao vivo ou VOD
  • Formato de transmissão 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, escute o evento FRAG_PARSING_METADATA de HLS.js para receber metadados ID3 e transmiti-los ao SDK com StreamManager.processMetadata().

Para reproduzir o vídeo automaticamente depois que tudo estiver carregado e pronto, ouça o o evento MANIFEST_PARSED de 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, faça o seguinte: você precisa usar strings diferentes para detectar metadados ID3 de transmissões ao vivo ou VOD. streams:

  • 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, Detecte 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 streams DASH)

Se você estiver usando o player de Shaka para reprodução de transmissão ao vivo, use a string 'emsg' para detectar eventos de metadados. Em seguida, use os dados da mensagem do evento na 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 transmissões VOD (formato de streams DASH)

Se você estiver usando o player de Shaka para Reprodução de stream de VOD, use a string 'timelineregionenter' para detectar eventos de metadados. Em seguida, use os dados da mensagem do evento na 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);
       }
}