Xử lý siêu dữ liệu đã hẹn giờ trong luồng DAI tuyến tính

SDK Chèn quảng cáo động (DAI) của Quảng cáo trên phương tiện truyền thông tương tác (IMA) dựa vào thông tin siêu dữ liệu được nhúng trong các phân đoạn nội dung nghe nhìn của luồng (siêu dữ liệu trong băng tần) hoặc trong tệp kê khai phát trực tuyến (siêu dữ liệu trong tệp kê khai) để theo dõi vị trí của người xem và các sự kiện quảng cáo phía máy khách. Siêu dữ liệu được gửi ở nhiều định dạng, tuỳ thuộc vào loại luồng đang phát.

Trình phát video nhận siêu dữ liệu theo thời gian theo lô. Tuỳ thuộc vào trình phát, siêu dữ liệu có thể xuất hiện theo thời gian đã lên lịch hoặc theo lô. Mỗi chuỗi siêu dữ liệu có một dấu thời gian trình bày (PTS) liên kết cho thời điểm kích hoạt chuỗi đó.

Ứng dụng của bạn chịu trách nhiệm thu thập siêu dữ liệu và chuyển tiếp siêu dữ liệu đó đến SDK DAI IMA. SDK cung cấp các phương thức sau để truyền thông tin này:

onTimedMetadata

Phương thức này chuyển tiếp các chuỗi siêu dữ liệu đã sẵn sàng để xử lý đến SDK. Hàm này nhận một đối số duy nhất:

  • metadata: một đối tượng chứa khoá TXXX với giá trị chuỗi liên kết có tiền tố là google_.
processMetadata

Phương thức này lên lịch để SDK xử lý các chuỗi siêu dữ liệu sau khi có PTS được chỉ định. Phương thức này có các đối số sau:

  • type: một chuỗi chứa loại sự kiện đang được xử lý. Các giá trị được chấp nhận là ID3 cho HLS hoặc urn:google:dai:2018 cho DASH
  • data: một giá trị chuỗi có tiền tố là google_ hoặc một mảng byte theo định dạng ID3:u\0004u\000u\000u\0000TXXXu\0004u\000u\000u\0000google_xxxxxxxx này.
  • timestamp: dấu thời gian tính bằng giây khi dữ liệu cần được xử lý.

Mỗi loại luồng mà SDK IMA DAI hỗ trợ đều sử dụng một dạng siêu dữ liệu theo thời gian riêng biệt, như mô tả trong các phần sau.

Luồng HLS MPEG2TS

Luồng DAI HLS truyền hình truyền thống sử dụng các phân đoạn MPEG2TS sẽ truyền siêu dữ liệu được tính giờ đến trình phát video thông qua thẻ ID3 trong băng tần. Các thẻ ID3 này được nhúng trong các phân đoạn MPEG2TS và được đặt tên trường là TXXX (dành cho nội dung văn bản tuỳ chỉnh do người dùng xác định).

Phát trong Safari

Safari tự động xử lý thẻ ID3 dưới dạng một bản nhạc ẩn, vì vậy, các sự kiện cuechange sẽ kích hoạt vào đúng thời điểm để xử lý từng phần siêu dữ liệu. Bạn có thể truyền tất cả siêu dữ liệu đến SDK IMA DAI, bất kể nội dung hoặc loại. Siêu dữ liệu không liên quan sẽ tự động bị lọc bỏ.

Ví dụ:

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 cung cấp thẻ ID3 theo lô thông qua sự kiện FRAG_PARSING_METADATA, dưới dạng một mảng gồm các mẫu. HLS.js không dịch dữ liệu ID3 từ mảng byte thành chuỗi và không bù trừ các sự kiện cho PTS tương ứng. Bạn không cần giải mã dữ liệu mẫu từ mảng byte sang chuỗi hoặc lọc ra các thẻ ID3 không liên quan, vì SDK IMA DAI sẽ tự động thực hiện việc giải mã và lọc này.

Ví dụ:

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

Luồng HLS CMAF

Luồng DAI HLS truyền hình truyền thống sử dụng Khung ứng dụng đa phương tiện phổ biến (CMAF) sẽ truyền siêu dữ liệu được định thời gian thông qua các hộp eMSGv1 trong băng tần theo tiêu chuẩn ID3 thông qua CMAF. Các hộp eMSG này được nhúng vào đầu mỗi phân đoạn nội dung nghe nhìn, trong đó mỗi eMSG ID3 chứa một PTS tương ứng với điểm gián đoạn cuối cùng trong luồng.

Kể từ bản phát hành 1.2.0 của HLS.js, cả hai trình phát được đề xuất của chúng tôi đều chuyển ID3 thông qua CMAF đến người dùng như thể đó là thẻ ID3. Vì lý do này, các ví dụ sau đây giống như đối với luồng HLS MPEG2TS. Tuy nhiên, điều này có thể không xảy ra với tất cả trình phát, vì vậy, việc triển khai tính năng hỗ trợ cho luồng HLS CMAF có thể yêu cầu mã riêng để phân tích cú pháp ID3 thông qua eMSG.

Phát trong Safari

Safari coi siêu dữ liệu ID3 thông qua eMSG là các sự kiện ID3 giả, tự động cung cấp các sự kiện đó theo lô dưới dạng một bản nhạc ẩn, chẳng hạn như các sự kiện cuechange được kích hoạt vào đúng thời điểm để xử lý từng phần siêu dữ liệu. Bạn có thể truyền tất cả siêu dữ liệu đến SDK IMA DAI, cho dù siêu dữ liệu có liên quan đến thời gian hay không. Mọi siêu dữ liệu không liên quan đến DAI sẽ tự động bị lọc ra.

Ví dụ:

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

Kể từ phiên bản 1.2.0, HLS.js coi ID3 thông qua siêu dữ liệu eMSG là các sự kiện ID3 giả, cung cấp các sự kiện này theo lô thông qua sự kiện FRAG_PARSING_METADATA dưới dạng một mảng mẫu. HLS.js không dịch dữ liệu ID3 từ mảng byte sang chuỗi và không bù sự kiện cho PTS tương ứng. Bạn không cần giải mã dữ liệu mẫu từ mảng byte thành chuỗi, vì SDK IMA DAI sẽ tự động thực hiện việc giải mã này.

Ví dụ:

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

Luồng DASH

Luồng DAI DASH tuyến tính truyền siêu dữ liệu dưới dạng sự kiện tệp kê khai trong luồng sự kiện có giá trị schemeIdUri tuỳ chỉnh là urn:google:dai:2018. Mỗi sự kiện trong các luồng này chứa một tải trọng văn bản và PTS.

DASH.js

Dash.js cung cấp trình xử lý sự kiện tuỳ chỉnh được đặt tên theo giá trị schemeIdUri của mỗi luồng sự kiện. Các trình xử lý tuỳ chỉnh này sẽ kích hoạt theo lô, bạn có thể xử lý giá trị PTS để định thời gian chính xác cho sự kiện. SDK IMA DAI có thể xử lý việc này cho bạn bằng phương thức streamManager, processMetadata().

Ví dụ:

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 hiển thị các sự kiện trong sự kiện timelineregionenter. Do định dạng không tương thích với Shaka Player, giá trị siêu dữ liệu phải được truy xuất thô thông qua thuộc tính chi tiết eventNode.attributes['messageData'].

Ví dụ:

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

Phân phát theo nhóm

Đối với việc phân phát Pod, có nhiều cấu hình để truyền siêu dữ liệu theo thời gian tuỳ thuộc vào các tiêu chí sau:

  • Loại luồng phát trực tiếp hoặc VOD
  • Định dạng luồng HLS hoặc DASH
  • Loại trình phát đang được sử dụng
  • Loại phần phụ trợ DAI đang được sử dụng

Định dạng luồng HLS (Luồng phát trực tiếp và VOD, trình phát HLS.js)

Nếu bạn đang sử dụng trình phát HLS.js, hãy nghe sự kiện FRAG_PARSING_METADATA HLS.js để lấy siêu dữ liệu ID3 và truyền sự kiện đó đến SDK bằng StreamManager.processMetadata().

Để tự động phát video sau khi mọi thứ đã tải xong và sẵn sàng, hãy nghe sự kiện MANIFEST_PARSED HLS.js để kích hoạt quá trình phát.

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 (Định dạng luồng DASH, Loại luồng phát trực tiếp và VOD)

Nếu đang sử dụng trình phát DASH.js, bạn phải sử dụng các chuỗi khác nhau để nghe siêu dữ liệu ID3 cho luồng Trực tiếp hoặc VOD:

  • Sự kiện phát trực tiếp: 'https://developer.apple.com/streaming/emsg-id3'
  • Luồng VOD: 'urn:google:dai:2018'

Truyền siêu dữ liệu ID3 đến SDK bằng StreamManager.processMetadata().

Để tự động hiển thị các chế độ điều khiển video sau khi mọi thứ đã tải và sẵn sàng, hãy theo dõi sự kiện MANIFEST_LOADED của 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 có sự kiện phát trực tiếp (định dạng luồng DASH)

Nếu bạn đang sử dụng trình phát Shaka để phát trực tiếp, hãy sử dụng chuỗi 'emsg' để theo dõi các sự kiện siêu dữ liệu. Sau đó, hãy sử dụng dữ liệu thông báo sự kiện trong lệnh gọi đến 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 với luồng VOD (định dạng luồng DASH)

Nếu bạn đang sử dụng trình phát Shaka để phát luồng VOD, hãy sử dụng chuỗi 'timelineregionenter' để theo dõi các sự kiện siêu dữ liệu. Sau đó, hãy sử dụng dữ liệu thông báo sự kiện trong lệnh gọi đến StreamManager.processMetadata() bằng chuỗi '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);
       }
}