Manipulador de manifesto para transmissões ao vivo

A API Pod Serving fornece acesso a segmentos de anúncios codificados e condicionados, preparados de maneira que possam ser agrupados diretamente em uma playlist de mídia HLS ou MPEG-DASH voltada para o usuário. Para MPEG-DASH, a API Pod Serving também fornece um modelo de manifesto para fornecer mais informações e contexto para esses segmentos de anúncios.

O foco deste guia é a implementação de um servidor básico de manipulação de manifesto de disponibilização de pod para transmissões ao vivo.

Pré-requisito: configurar eventos de transmissão ao vivo no Google Ad Manager

Antes de fazer qualquer solicitação da API de veiculação de conjuntos, é preciso criar um evento de transmissão ao vivo do Ad Manager para cada transmissão processada. É possível criar um evento de transmissão ao vivo usando LiveStreamEventService API ou a interface da Web do Google Ad Manager.

Para que um evento de transmissão ao vivo seja usado com a API Veiculação de conjunto, você precisará preencher vários atributos do evento:

  • customAssetKey: um identificador personalizado a ser usado para este evento. Precisa ser exclusivo em todos os eventos da rede.
  • adTags: URL da tag de anúncio principal gerado pelo fluxo de trabalho de programação do Ad Manager.
  • dynamicAdInsertionType: precisa ser definido como POD_SERVING_REDIRECT.
  • streamingFormat: defina como HLS ou DASH.
  • segmentUrlAuthenticationKeyIds: pelo menos uma chave HMAC usada para assinar solicitações de segmento de anúncio.
  • daiEncodingProfileIds: uma lista dos IDs de DAIEncodingProfile ativados para esse evento.
  • startDateTime: data e hora de início do evento
  • endDateTime: data e hora de término programadas do evento. Esse atributo será obrigatório se unlimitedEndDateTimeis false and ignored ifunlimitedEndDateTimeis true.unlimitedEndDateTime`: um booleano. Veja como fazer isso acima.

Receber solicitações de manifesto de stream

Seu manipulador de manifesto precisa fornecer um endpoint de API para detectar solicitações de manifesto do app cliente do player de vídeo. No mínimo, esse endpoint precisa coletar um ID de stream do app do player do cliente e retornar um manifesto de stream integrado. O ID de stream é usado para identificar a sessão de streaming para o Ad Manager.

Você também precisa coletar outras informações para identificar o fluxo de conteúdo adequado, por exemplo, um ID de conteúdo.

Exemplo de um possível endpoint de solicitação de manifesto

GET /api/video/{asset_key}/manifest.{format}
Host: {your_domain}
Parâmetros de caminho
asset_key Um ID hipotético correspondente à transmissão ao vivo solicitada no seu sistema.
format Um parâmetro hipotético correspondente ao formato de stream. Pode ser:
mpd Para streams MPEG-DASH
m3u8 Para streams HLS
Parâmetros de consulta
stream_id O código de stream do Ad Manager do app de player de vídeo do cliente.

Recuperar o stream de conteúdo

Use o Content ID coletado na solicitação do manifesto para selecionar o stream de conteúdo a ser combinado com os anúncios.

Agrupe segmentos de anúncios no fluxo de conteúdo

O agrupamento dos URLs de segmentos de anúncio varia de acordo com o formato do stream.

Streams HLS

Os streams HLS geralmente são disponibilizados como um manifesto multivariante, que contém um conjunto de links para manifestos de variantes, que correspondem a cada um dos perfis de codificação.

Observação: para simplificar, este guia presume que sua mídia HLS está codificada em um formato que combina áudio e vídeo no mesmo arquivo de segmento.

Playlists multivariantes de proxy

Você vai precisar substituir cada URL da playlist de variante na playlist multivariante original por outra chamada de endpoint para o manipulador para processar o manifesto da variante selecionada do jogador.

As etapas restantes para agrupar o HLS vão presumir que um único manifesto de variante está sendo processado.

Exemplo de um possível endpoint de solicitação de variante
GET /api/video/{asset_key}/variant/{variant_id}.m3u8
Host: {your_domain}
Parâmetros de caminho
asset_key Um ID hipotético correspondente à transmissão ao vivo solicitada no seu sistema.
variant Um parâmetro hipotético contendo um identificador para a variante específica que está sendo processada.
Parâmetros de consulta
stream_id O código de stream do Ad Manager do app de player de vídeo do cliente, usado aqui para identificar uma sessão de usuário com o manipulador de manifesto.
Exemplo de manifesto multivariante não processado
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.4d000c,mp4a.40.5"
https://cdn.{...}/1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,CODECS="avc1.4d000c,mp4a.40.5"
https://cdn.{...}/720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.4d000d,mp4a.40.5"
https://cdn.{...}/360p.m3u8
Exemplo de manifesto multivariante com proxy
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.4d000c,mp4a.40.5"
https://{manifest_manipulator}/api/video/tears_of_steel/variant/1080p.m3u8?stream_id=6e69425c-0ac5-43ef-b070-c5143ba68541:CHS
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,CODECS="avc1.4d000c,mp4a.40.5"
https://{manifest_manipulator}/api/video/tears_of_steel/variant/720p.m3u8?stream_id=6e69425c-0ac5-43ef-b070-c5143ba68541:CHS
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360,CODECS="avc1.4d000d,mp4a.40.5"
https://{manifest_manipulator}/api/video/tears_of_steel/variant/360p.m3u8?stream_id=6e69425c-0ac5-43ef-b070-c5143ba68541:CHS

Identificar segmentos de intervalo de anúncio e inserir descontinuidades

Ao processar o manifesto da variante, acompanhe o horário de início, a duração e o índice do próximo intervalo de anúncio, até que o manifesto dinâmico que está sendo processado contenha segmentos que serão substituídos pelo conteúdo do anúncio.

Os intervalos de anúncio podem ser delineados dos segmentos de conteúdo de maneiras diferentes, dependendo do seu codificador. Uma maneira comum de delinear um intervalo de anúncio é preceder os segmentos de anúncio com uma tag #EXT-X-CUE-OUT e seguir com uma tag #EXT-X-CUE-IN.

Para separar os intervalos de anúncio hospedados pelo Google dos seus segmentos de conteúdo, é necessário inserir tags #EXT-X-DISCONTINUITY no início e no final de cada intervalo de anúncio. Se essas tags de descontinuidade não aparecerem no manifesto final, a reprodução vai falhar.

Os URIs do segmento de anúncio inseridos não estão criptografados. Se o conteúdo estiver criptografado, também será necessário remover a criptografia especificando #EXT-X-KEY:METHOD=NONE antes do primeiro segmento de anúncio de cada intervalo de anúncio e, em seguida, adicioná-lo novamente após o intervalo.

Exemplo de manifesto (original)
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0

#EXTINF:5.005,
contentorigin.com/1.ts
#EXTINF:5.005,
contentorigin.com/2.ts
#EXT-X-CUE-OUT:15.000
#EXTINF:5.005,
contentorigin.com/3.ts
#EXTINF:5.005,
contentorigin.com/4.ts
#EXTINF:5.005,
contentorigin.com/5.ts
#EXTINF:5.000,d
contentorigin.com/6.ts
#EXT-X-CUE-IN
#EXTINF:5.005,
contentorigin.com/7.mp4
#EXTINF:5.005,
contentorigin.com/8.mp4
Manifesto com descontinuidades inseridas
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0

#EXTINF:5.005,
contentorigin.com/1.ts
#EXTINF:5.005,
contentorigin.com/2.ts
#EXTINF:5.005,
#EXT-X-DISCONTINUITY
{... New segments will go here ...}
#EXT-X-DISCONTINUITY
#EXTINF:5.005,
contentorigin.com/7.mp4
#EXTINF:5.005,
contentorigin.com/8.mp4

Processar segmentos de conjunto de anúncios

Para cada segmento em um conjunto de anúncios, é preciso acompanhar alguns valores adicionais:

  • segment_number: índice do segmento no conjunto de anúncios, começando com zero. Ou "init" para iniciar um segmento de mp4.
  • segment_duration: duração do segmento atual em milissegundos. Esse valor precisa ser o mesmo para todos os segmentos, exceto o último do conjunto.
  • segment_offset: deslocamento do trecho calculado somando a duração do segmento anterior ao deslocamento em milissegundos.
  • last: valor booleano que identifica o último segmento em um conjunto de anúncios. O padrão é "false".

Criar URLs de segmento de anúncio

Substitua cada segmento do intervalo de anúncio por um URL do seguinte formato:

/linear/pods/v1/seg/network/{network_code}/custom_asset/{custom_asset_key}/pod/{pod_id}/profile/{profile_name}/{segment_number}.(ts|mp4|vtt|aac|ac3|eac3)
Parâmetros de caminho
network_code É o código da rede do Ad Manager 360 para esta rede.
custom_asset_key É a chave do recurso de transmissão ao vivo personalizada especificada na API LiveStreamEventService ou na página da transmissão ao vivo na interface da Web do Ad Manager 360.
pod_id Identificador do intervalo de anúncio. Precisa ser um número inteiro a partir de 1 e aumentando em um para cada intervalo de anúncio.

Esse valor precisa ser o mesmo para todos os usuários que visualizam o mesmo intervalo de anúncio no evento atual.

profile_name Identificador do perfil solicitado
segment_number O índice desse segmento no conjunto de anúncios atual, começando em zero.
Ao usar o contêiner MP4, o segmento de inicialização pode ser solicitado configurando "segment_number" como "init".
Parâmetros de consulta
stream_id Obrigatório O parâmetro stream_id do usuário retornado da solicitação de criação de stream.
sd Obrigatório segment_duration
so Opcional segment_offset

Se so estiver ausente, presume-se que todos os segmentos anteriores tenham a mesma duração e que o deslocamento do trecho seja calculado com base em segment_number e sd.

pd Obrigatório, exceto para eventos com intervalos de anúncio sem duração ativados A duração (em milissegundos) do intervalo de anúncio. Também conhecido como ad_pod_duration.
auth-token Obrigatório Um token HMAC assinado e codificado por URL para este conjunto de anúncios.
last Opcional Booleano que indica o último segmento do intervalo de anúncio. O padrão é "false".

Os valores dos parâmetros de consulta devem ser devidamente codificados para serem seguros para URL. Isso é especialmente importante para o campo auth-token, já que pode conter os caracteres /, + e =.

Exemplo de manifesto (após a substituição do segmento)
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0

#EXTINF:5.005,
contentorigin.com/1.ts
#EXTINF:5.005,
contentorigin.com/2.ts
#EXT-X-DISCONTINUITY
#EXTINF:5.005,
https://dai.google.com/linear/pods/v1/seg/network/6062/custom_asset/iYdOkYZdQ1KFULXSN0Gi7g/pod/1/profile/devrel4628000/0.ts?sd=5005&so=0&pd=18015&auth-token=custom_asset_key%3DiYdOkYZdQ1KFULXSN0Gi7g~cust_params%3D~exp%3D1489680000~network_code%3D6062~pd%3D180000~pod_id%3D5~hmac%3D44bf78223c240cbc5bae3cdfd794bfc6971b6583cd296f44ef3a46944605cf9a&stream_id=fe6c9136-09a4-4ff6-862e-daee1dea0e1b:MRN2
#EXTINF:5.005,
https://dai.google.com/linear/pods/v1/seg/network/6062/custom_asset/iYdOkYZdQ1KFULXSN0Gi7g/pod/1/profile/devrel4628000/1.ts?sd=5005&so=5005&pd=18015&auth-token=custom_asset_key%3DiYdOkYZdQ1KFULXSN0Gi7g~cust_params%3D~exp%3D1489680000~network_code%3D6062~pd%3D180000~pod_id%3D5~hmac%3D44bf78223c240cbc5bae3cdfd794bfc6971b6583cd296f44ef3a46944605cf9a&stream_id=fe6c9136-09a4-4ff6-862e-daee1dea0e1b:MRN2
#EXTINF:5.005,
https://dai.google.com/linear/pods/v1/seg/network/6062/custom_asset/iYdOkYZdQ1KFULXSN0Gi7g/pod/1/profile/devrel4628000/2.ts?sd=5005&so=10010&pd=18015&auth-token=custom_asset_key%3DiYdOkYZdQ1KFULXSN0Gi7g~cust_params%3D~exp%3D1489680000~network_code%3D6062~pd%3D180000~pod_id%3D5~hmac%3D44bf78223c240cbc5bae3cdfd794bfc6971b6583cd296f44ef3a46944605cf9a&stream_id=fe6c9136-09a4-4ff6-862e-daee1dea0e1b:MRN2
#EXTINF:3.000,
https://dai.google.com/linear/pods/v1/seg/network/6062/custom_asset/iYdOkYZdQ1KFULXSN0Gi7g/pod/1/profile/devrel4628000/3.ts?sd=3000&so=15015&pd=18015&auth-token=custom_asset_key%3DiYdOkYZdQ1KFULXSN0Gi7g~cust_params%3D~exp%3D1489680000~network_code%3D6062~pd%3D180000~pod_id%3D5~hmac%3D44bf78223c240cbc5bae3cdfd794bfc6971b6583cd296f44ef3a46944605cf9a&stream_id=fe6c9136-09a4-4ff6-862e-daee1dea0e1b:MRN2&last=true
#EXT-X-DISCONTINUITY
#EXTINF:5.005,
contentorigin.com/7.mp4
#EXTINF:5.005,
contentorigin.com/8.mp4

Parabéns! Agora você está veiculando uma transmissão ao vivo com segmentos de anúncio fornecidos pela API DAI Pod Serving.

Streams DASH

Os streams do DASH são fornecidos como um arquivo MPD, que contém todas as codificações de stream em um único arquivo, em que o conteúdo é representado como uma série de pontos.

Modelo de período de solicitação

Solicite um modelo de período do Google Ad Manager. Esse modelo se tornará seu período de intervalo de anúncio assim que as macros que ele contém forem preenchidas.

É preciso solicitar esse modelo apenas uma vez por sessão de stream e armazená-lo em cache para reutilização em cada intervalo de anúncio.

Endpointhf de solicitação de modelo de período
GET /linear/pods/v1/dash/network/{network_code}/custom_asset/{custom_asset}/pods.json
Host: dai.google.com
Content-Type: application/json
Parâmetros de caminho
network_code É o código de rede do Ad Manager 360 do editor.
custom_asset A chave do recurso personalizado do evento de transmissão ao vivo no Google Ad Manager.
Parâmetros de consulta
stream_id O código de stream do Ad Manager do player de vídeo do cliente.
JSON de resposta
dash_period_template A string XML do modelo de período.
segment_duration_ms A duração de cada segmento de mídia do anúncio no modelo de período, em milissegundos.
Exemplo de solicitação (cURL)
curl https://dai.google.com/linear/pods/v1/dash/network/21775744923/custom_asset/tears_of_steel/pods.json?stream-id=cc59197a-44c0-4be2-a8cc-9a6fdb80158f:DLS
Exemplo de resposta
{"dash_period_template":"<Period id="adpod-$$pod-id$$" $$period-start$$ $$period-duration$$> <BaseURL>https://dai.google.com/linear/pods/v1/seg/event/{event_code}/pods/$$pod-id$$/profile/</BaseURL>
 <SegmentTemplate initialization="$RepresentationID$/init.mp4?stream_id={a-stream-id}&amp;sd=5000&pd=$$pod-duration$$&amp;cust_params=$$cust_params$$&amp;auth_token=$$token$$" media="$RepresentationID$/$Number$.mp4?stream_id={a-stream-id}&amp;sd=5000&pd=$$pod-duration$$&amp;cust_params=$$cust_params$$&amp;scte35=$$scte35$$&amp;auth_token=$$token$$" startNumber="1" presentationTimeOffset="0">
  <SegmentTimeline>
    <S t="0" d="5" r="$$number-of-repeated-segments$$"/>
  </SegmentTimeline>
  </SegmentTemplate>
  <AdaptationSet id="0" width="1280" height="720" frameRate="30" contentType="video" subsegmentAlignment="true" startWithSAP="1">
    <InbandEventStream schemeIdUri="https://developer.apple.com/streaming/emsg-id3"/>
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
    <Representation mimeType="video/mp4" codecs="avc1.640029" id="a943ff679a2f3e71d9181a21b7542122g" bandwidth="3200000"/>
    <Representation mimeType="video/mp4" codecs="avc1.640029" id="abbbd80q4w5ce2fs28308rd1f4g4bat0" bandwidth="1500000"/>
  </AdaptationSet>
  <AdaptationSet id="1" contentType="audio"> <Representation audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.2" id="a87ff679a2f3e71d9181a67b7542122c" bandwidth="95000"/>

    <Representation audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.2" id="eccbc87e4b5ce2fe28308fd9f2a7baf3" bandwidth="127000"/>
  </AdaptationSet>
</Period>",
"segment_duration_ms":5000}

Preencher o modelo de período

O modelo de período contém várias macros que precisam ser substituídas em cada intervalo de anúncio. Todas as macros precisam ser substituídas. As macros não utilizadas precisam ser substituídas por uma string vazia ("").

Macro Descrição Exemplo
$$pod-id$$ O índice do conjunto de anúncios que este período representa. Esse valor precisa corresponder ao mesmo pod em todas as sessões do espectador. 1
$$period-start$$ A hora em que o período começa na MPD atual. Um atributo opcional que precisa ser substituído por start="###", em que ### é o tempo de apresentação em que o intervalo de anúncio começa. Se o horário de início do período não for informado, essa macro precisará ser substituída por uma string vazia. start="PT2H33M30S"
$$period-duration$$ A duração do período de anúncio completo. Um atributo opcional que precisa ser substituído por duration="###", em que ### é a duração do período do anúncio no formato de duração DASH padrão. Se a duração do período não for fornecida, essa macro precisará ser substituída por uma string vazia. duration="PT15S"
$$pod-duration$$ A duração esperada dos anúncios a serem decididos para este conjunto, em milissegundos. 15000
$$number-of-repeated-segments$$ Esse valor é calculado dividindo a duração do período do anúncio (em milissegundos) pelo valor de segment_duration_ms e arredondando para o número inteiro mais próximo. 3
$$cust_params$$ Essa macro pode ser substituída pelos parâmetros de segmentação personalizada exclusivos do intervalo de anúncio atual, se fornecido. O valor precisa ser formatado conforme descrito neste artigo da Central de Ajuda do Ad Manager. Se nenhum parâmetro personalizado for necessário, essa macro precisará ser substituída por uma string vazia. &cust_params=section%3Dblog%26anotherKey%3Dvalue1%2Cvalue2
$$scte35$$ Essa macro precisa ser substituída por um valor scte35 exclusivo do intervalo de anúncio, se um for fornecido. Se nenhuma informação scte35 for necessária, essa macro precisará ser substituída por uma string vazia. /DAqAAAAAAAA///wDwVAAAT2f0/+ecF1mQABC/8ACgAIQ1VFSQAAAAsuZVlR
$$token$$ Um token HMAC (em inglês) assinado e codificado por URL. Esse token é obrigatório. custom_asset_key%3DiYdOkYZdQ1KFULXSN0Gi7g~exp%3D1489680000~network_code%3D6062~pd%3D180000~pod_id%3D5~hmac%3D6a8c44c72e4718ff63ad2284edf2a8b9e319600b430349d31195c99b505858c9
Modelo de período bruto, contendo macros
<Period id="adpod-$$pod-id$$" $$period-start$$ $$period-duration$$>
  <BaseURL>
    https://dai.google.com/linear/pods/v1/seg/event/{event_code}/pods/$$pod-id$$/profile/
  </BaseURL>
  <SegmentTemplate initialization="$RepresentationID$/init.mp4?stream_id=cc59197a-44c0-4be2-a8cc-9a6fdb80158f:DLS&amp;sd=5000&pd=$$pod-duration$$&amp;cust_params=$$cust_params$$&amp;auth_token=$$token$$" media="$RepresentationID$/$Number$.mp4?stream_id=ç√&amp;sd=5000&pd=$$pod-duration$$&amp;cust_params=$$cust_params$$&amp;scte35=$$scte35$$&amp;auth_token=$$token$$" startNumber="1" presentationTimeOffset="0">  
    <SegmentTimeline>
      <S t="0" d="5" r="$$number-of-repeated-segments$$"/>
    </SegmentTimeline>
  </SegmentTemplate>
  <AdaptationSet id="0" width="1280" height="720" frameRate="30" contentType="video" subsegmentAlignment="true" startWithSAP="1">
    <InbandEventStream schemeIdUri="https://developer.apple.com/streaming/emsg-id3"/>
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
    <Representation mimeType="video/mp4" codecs="avc1.640029" id="a943ff679a2f3e71d9181a21b7542122g" bandwidth="3200000"/>
    <Representation mimeType="video/mp4" codecs="avc1.640029" id="abbbd80q4w5ce2fs28308rd1f4g4bat0" bandwidth="1500000"/>
  </AdaptationSet>
  <AdaptationSet id="1" contentType="audio"> <Representation audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.2" id="a87ff679a2f3e71d9181a67b7542122c" bandwidth="95000"/>
    <Representation audioSamplingRate="48000" mimeType="audio/mp4" codecs="mp4a.40.2" id="eccbc87e4b5ce2fe28308fd9f2a7baf3" bandwidth="127000"/>
  </AdaptationSet>
</Period>
Período do anúncio preenchido
<Period id="pod-0" start="PT5H50M12S">
  <BaseURL>
    https://dai.google.com/linear/pods/v1/seg/event/M-nTcApTRTi6CEGIt4GYMw/pod/0/profile/
  </BaseURL>
  <SegmentTemplate startNumber="0" media="1080p/0.mp4?stream_id=cc59197a-44c0-4be2-a8cc-9a6fdb80158f:DLS&amp;sd=5000&amp;pd=30000&amp;cust_params=&amp;auth-token=&amp;scte35=" initialization="$RepresentationID$/init.mp4?stream_id=cc59197a-44c0-4be2-a8cc-9a6fdb80158f:DLS&amp;pd=30000&amp;cust_params=&amp;auth-token=&amp;scte35=">
    <SegmentTimeline>
      <S d="5" r="1"/>
    </SegmentTimeline>
  </SegmentTemplate>
  <AdaptationSet mimeType="video/mp4" scanType="progressive" contentType="video">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
    <Representation width="768" height="432" frameRate="30" codecs="avc1.42c01e" id="fmp4-video-1200k" bandwidth="1300000">
      <InbandEventStream schemeIdUri="https://developer.apple.com/streaming/emsg-id3"/>
    </Representation>
  </AdaptationSet>
  <AdaptationSet mimeType="audio/mp4" scanType="progressive" contentType="audio">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
      <Representation audioSamplingRate="48000" codecs="mp4a.40.2" id="fmp4-audio-128kbps" bandwidth="128000">
      <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
    </Representation>
  </AdaptationSet>
</Period>

Insira o período preenchido no manifesto DASH

Por fim, substitua o período adequado no manifesto bruto pelo período do anúncio recém-preenchido e retorne o manifesto integrado final ao cliente de vídeo que fez a solicitação para reprodução.

Exemplo de manifesto de conteúdo bruto
<?xml version="1.0"?>
  <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:DASH:schema:MPD:2011" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="static" mediaPresentationDuration="PT0H9M56.46S">
    <BaseURL>
      http://example.com/tears_of_steel/
    </BaseURL>
    <Period start="PT0S">
      <AdaptationSet bitstreamSwitching="true">

        <Representation id="0" codecs="avc1" mimeType="video/mp4" width="1920" height="1080" startWithSAP="1" bandwidth="500000">
          <SegmentBase>
            <Initialization sourceURL="segments/1080/1.m4s" range="0-862"/>
          </SegmentBase>
          <SegmentList duration="15">
            <SegmentURL media="segments/1080p/2.m4s" mediaRange="863-7113"/>
            <SegmentURL media="segments/1080p/3.m4s" mediaRange="7114-14104"/>
            <SegmentURL media="segments/1080p/4.m4s" mediaRange="14105-17990"/>
            ...
          </SegmentList>
        </Representation>

        <Representation id="1" codecs="avc1" mimeType="video/mp4" width="1280" height="720" startWithSAP="1" bandwidth="250000">
          <SegmentBase>
            <Initialization sourceURL="segments/720p/1.m4s" range="0-864"/>
          </SegmentBase>
          <SegmentList duration="15">
            <SegmentURL media="segments/720p/2.m4s" mediaRange="865-11523"/>
            <SegmentURL media="segments/720p/3.m4s" mediaRange="11524-25621"/>
            <SegmentURL media="segments/720p/4.m4s" mediaRange="25622-33693"/>
            ...
          </SegmentList>
        </Representation>

        <Representation id="1" codecs="avc1" mimeType="video/mp4" width="640" height="480" startWithSAP="1" bandwidth="100000">
          <SegmentBase>
            <Initialization sourceURL="segment/480p/1.m4s" range="0-865"/>
          </SegmentBase>
          <SegmentList duration="15">
            <SegmentURL media="segment/480p/2.m4s" mediaRange="866-26970"/>
            <SegmentURL media="segment/480p/3.m4s" mediaRange="26971-72543"/>
            <SegmentURL media="segment/480p/4.m4s" mediaRange="72544-95972"/>
            ...
          </SegmentList>
        </Representation>
        ...
      </AdaptationSet>
    </Period end>
  </MPD>
Exemplo de manifesto integrado
<?xml version="1.0"?>
  <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:DASH:schema:MPD:2011" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011" profiles="urn:mpeg:dash:profile:isoff-main:2011" type="static" mediaPresentationDuration="PT0H9M56.46S">
    <BaseURL>
      http://example.com/tears_of_steel/
    </BaseURL>
    
    <Period id="pod-0" start="PT5H50M12S">
  <BaseURL>
    https://dai.google.com/linear/pods/v1/seg/event/M-nTcApTRTi6CEGIt4GYMw/pod/0/profile/
  </BaseURL>
  <SegmentTemplate startNumber="0" media="1080p/0.mp4?stream_id=cc59197a-44c0-4be2-a8cc-9a6fdb80158f:DLS&amp;sd=5000&amp;pd=30000&amp;cust_params=&amp;auth-token=&amp;scte35=$$scte35$$" initialization="$RepresentationID$/init.mp4?stream_id=cc59197a-44c0-4be2-a8cc-9a6fdb80158f:DLS&amp;pd=30000&amp;cust_params=&amp;auth-token=&amp;scte35=$$scte35$$">
    <SegmentTimeline>
      <S d="5" r="1"/>
    </SegmentTimeline>
  </SegmentTemplate>
  <AdaptationSet mimeType="video/mp4" scanType="progressive" contentType="video">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
    <Representation width="768" height="432" frameRate="30" codecs="avc1.42c01e" id="fmp4-video-1200k" bandwidth="1300000">
      <InbandEventStream schemeIdUri="https://developer.apple.com/streaming/emsg-id3"/>
    </Representation>
  </AdaptationSet>
  <AdaptationSet mimeType="audio/mp4" scanType="progressive" contentType="audio">
    <Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
      <Representation audioSamplingRate="48000" codecs="mp4a.40.2" id="fmp4-audio-128kbps" bandwidth="128000">
      <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
    </Representation>
  </AdaptationSet>
</Period>
    
</MPD>

Parabéns! Agora você está veiculando uma transmissão ao vivo DASH com segmentos de anúncio fornecidos pela API DAI Pod Serving.

Outros recursos