リニア DAI ストリームで時間指定メタデータを処理する

インタラクティブ メディア広告(IMA)動的広告挿入(DAI)SDK は、ストリーミングのメディア セグメント(インバンド メタデータ)またはストリーミング マニフェスト ファイル(マニフェスト内メタデータ)に埋め込まれたメタデータ情報を使用して、視聴者の位置とクライアントサイド広告イベントをトラッキングします。メタデータは、再生されるストリームの種類に応じて異なる形式で送信されます。

動画プレーヤーは、タイミング設定されたメタデータをバッチで受信します。プレーヤーによっては、メタデータがスケジュールされた時間に表示されることもありますし、バッチで表示されることもあります。各メタデータ文字列には、トリガーするタイミングのプレゼンテーション タイムスタンプ(PTS)が関連付けられています。

メタデータをキャプチャして IMA DAI SDK に転送するのはアプリの役割です。SDK には、この情報を渡す次のメソッドがあります。

onTimedMetadata

このメソッドは、処理の準備が整ったメタデータ文字列を SDK に転送します。引数は 1 つだけです。

  • metadata: TXXX のキーと、google_ が接頭辞の文字列値を含むオブジェクト。
processMetadata

このメソッドは、指定された PTS の後に SDK によって処理されるメタデータ文字列をスケジュールします。次の引数を取ります。

  • type: 処理中のイベントのタイプを含む文字列。指定できる値は、HLS の場合は ID3、DASH の場合は urn:google:dai:2018 です。
  • data: google_ が接頭辞の文字列値、または ID3:u\0004u\000u\000u\0000TXXXu\0004u\000u\000u\0000google_xxxxxxxx 形式のバイト配列。
  • timestamp: データを処理する必要があるタイムスタンプ(秒単位)。

IMA DAI SDK でサポートされている各ストリームタイプは、次のセクションで説明するように、一意の形式のタイミング メタデータを使用します。

HLS MPEG2TS ストリーム

MPEG2TS セグメントを使用するリニア DAI HLS ストリームは、インバンド ID3 タグを使用してタイミング設定されたメタデータをビデオ プレーヤーに渡します。これらの ID3 タグは MPEG2TS セグメント内に埋め込まれ、TXXX フィールド名(カスタム ユーザー定義テキスト コンテンツ用)が付けられます。

Safari での再生

Safari では、ID3 タグが非表示トラックとして自動的に処理されるため、キュー変更イベントが正しいタイミングで発生し、各メタデータを処理できます。コンテンツやタイプに関係なく、すべてのメタデータを IMA DAI SDK に渡しても問題ありません。無関係なメタデータは自動的に除外されます。

次の例をご覧ください。

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

HLS.js は、FRAG_PARSING_METADATA イベントを介して、サンプルの配列として ID3 タグをバッチで提供します。HLS.js は、ID3 データをバイト配列から文字列に変換せず、イベントを対応する PTS にオフセットしません。IMA DAI SDK がこのデコードとフィルタリングを自動的に行うため、サンプルデータをバイト配列から文字列にデコードしたり、無関係な ID3 タグを除外したりする必要はありません。

次の例をご覧ください。

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

HLS CMAF ストリーム

共通メディア アプリケーション フレームワーク(CMAF)を使用するリニア DAI HLS ストリームは、ID3 to CMAF 標準に従って、インバンド eMSGv1 ボックスを介してタイミング設定されたメタデータを渡します。これらの eMSG ボックスは各メディア セグメントの先頭に埋め込まれ、各 ID3 eMSG にはストリーム内の最後の不連続点に対する PTS が含まれています。

HLS.js の 1.2.0 リリース時点では、推奨されるプレーヤーのどちらも、ID3 タグであるかのように CMAF を介して ID3 をユーザーに渡します。このため、次の例は HLS MPEG2TS ストリームの場合と同じです。ただし、すべてのプレーヤーでそうとは限らないため、HLS CMAF ストリームのサポートを実装する場合、eMSG を介して ID3 を解析する独自のコードを必要とする場合があります。

Safari での再生

Safari では、ID3 から eMSG のメタデータが疑似 ID3 イベントとして扱われ、非表示トラックとしてバッチで自動的に提供されます。これにより、各メタデータを処理するために、cuechange イベントが適切なタイミングでトリガーされます。タイミングに関連しているかどうかにかかわらず、すべてのメタデータを IMA DAI SDK に渡しても問題ありません。DAI 以外のメタデータは自動的に除外されます。

次の例をご覧ください。

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

バージョン 1.2.0 以降、HLS.js は ID3 から eMSG のメタデータを疑似 ID3 イベントとして扱い、FRAG_PARSING_METADATA イベントを介してサンプルの配列としてバッチで提供します。HLS.js は、ID3 データをバイト配列から文字列に変換しません。また、イベントを対応する PTS にオフセットしません。IMA DAI SDK がこのデコードを自動的に行うため、サンプルデータをバイト配列から文字列にデコードする必要はありません。

次の例をご覧ください。

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

DASH ストリーム

リニア DAI DASH ストリームは、カスタム schemeIdUriurn:google:dai:2018 を使用して、イベント ストリームのマニフェスト イベントとしてメタデータを渡します。これらのストリームの各イベントには、テキスト ペイロードと PTS が含まれています。

DASH.js

Dash.js には、各イベント ストリームの schemeIdUri 値にちなんで命名されたカスタム イベント ハンドラが用意されています。これらのカスタム ハンドラはバッチで発生するため、PTS 値を処理してイベントのタイミングを適切に設定するのはユーザーの責任となります。IMA DAI SDK では、streamManager メソッド processMetadata() を使用して、この処理を自動化できます。

次の例をご覧ください。

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

Shaka Player は、timelineregionenter イベントの一部としてイベントを表示します。Shaka Player との形式の非互換性のため、メタデータ値は詳細プロパティ eventNode.attributes['messageData'] を使用して未加工で取得する必要があります。

次の例をご覧ください。

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);
  }
});
...

連続広告配信

Pod サービングの場合、次の条件に応じて、時間指定メタデータを渡すためのさまざまな構成があります。

  • ライブまたは VOD のストリームタイプ
  • HLS または DASH の配信形式
  • 使用しているプレーヤーのタイプ
  • 使用されている DAI バックエンドのタイプ

HLS ストリーム形式(ライブ ストリームと VOD ストリーム、HLS.js プレーヤー)

HLS.js プレーヤーを使用している場合は、HLS.js FRAG_PARSING_METADATA イベントをリッスンして ID3 メタデータを取得し、StreamManager.processMetadata() を使用して SDK に渡します。

すべてのコンテンツが読み込まれて準備が整ったら動画を自動的に再生するには、HLS.js MANIFEST_PARSED イベントをリッスンして再生をトリガーします。

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(DASH ストリーム形式、ライブ ストリームと VOD ストリームのタイプ)

DASH.js プレーヤーを使用している場合は、ライブ ストリームまたは VOD ストリームの ID3 メタデータをリッスンするために、異なる文字列を使用する必要があります。

  • ライブ配信: 'https://developer.apple.com/streaming/emsg-id3'
  • VOD ストリーム: 'urn:google:dai:2018'

StreamManager.processMetadata() を使用して ID3 メタデータを SDK に渡します。

すべての読み込みが完了して準備ができたら動画コントロールを自動的に表示するには、DASH.js MANIFEST_LOADED イベントをリッスンします。

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(DASH ストリーム形式)

ライブ配信の再生に Shaka Player を使用している場合は、文字列 'emsg' を使用してメタデータ イベントをリッスンします。次に、イベント メッセージ データを使用して 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});
}

VOD ストリームを使用した Shaka Player(DASH ストリーム形式)

VOD ストリームの再生に Shaka プレーヤーを使用している場合は、文字列 'timelineregionenter' を使用してメタデータ イベントをリッスンします。次に、イベント メッセージ データを使用して、文字列 'urn:google:dai:2018' とともに StreamManager.processMetadata() を呼び出します。

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);
       }
}