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) 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 về siêu dữ liệu được nhúng trong 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 truyền 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à 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 sự kiện phát trực tiếp đang phát.

Trình phát video sẽ nhận siêu dữ liệu được xác định thời gian theo đợt. Tuỳ thuộc vào trình phát, siêu dữ liệu có thể xuất hiện tại thời điểm đã lên lịch hoặc xuất hiện 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 với thời điểm cần kích hoạt.

Ứ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 IMA DAI. 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ý cho SDK. Phương thức này chỉ có một đối số:

  • metadata: một đối tượng chứa khoá TXXX có giá trị chuỗi liên kết với tiền tố 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 PTS được chỉ định. Hàm này nhận 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ố google_ hoặc một mảng byte giải mã thành một chuỗi như vậ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 có tính thời gian duy nhất, như được mô tả trong các phần sau.

Luồng MPEG2TS HLS

Các luồng HLS của DAI tuyến tính sử dụng các phân đoạn MPEG2TS sẽ truyền siêu dữ liệu được tính thời gian đến trình phát video thông qua các 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 TXXX (đối với 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 kênh ẩn, vì vậy, các sự kiện gợi ý thay đổi sẽ kích hoạt đúng thời điểm để xử lý từng phần siêu dữ liệu. Bạn có thể chuyển tất cả siêu dữ liệu đến SDK IMA DAI, bất kể nội dung hay 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 hàng loạt thẻ ID3 thông qua sự kiện FRAG_PARSING_METADATA dưới dạng một loạt mẫu. HLS.js không dịch dữ liệu ID3 từ các mảng byte sang chuỗi và không bù trừ các sự kiện sang PTS tương ứng. Bạn không cần phải 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 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 CMAF HLS

Các luồng HLS của DAI tuyến tính sử dụng Khung ứng dụng đa phương tiện chung (CMAF) sẽ truyền siêu dữ liệu được tính thời gian 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 ở đầu mỗi phân đoạn nội dung nghe nhìn, trong đó mỗi eMSG ID3 chứa một PTS liên quan đến điểm gián đoạn cuối cùng trong luồng.

Kể từ bản phát hành HLS.js 1.2.0, cả hai trình phát đề xuất của chúng tôi đều truyền ID3 thông qua CMAF cho người dùng như thể họ là thẻ ID3. Vì lý do này, các ví dụ sau đây sẽ giống như đối với luồng MPEG2TS HLS. Tuy nhiên, điều này có thể không đúng 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 CMAF HLS có thể yêu cầu mã duy nhất để phân tích cú pháp ID3 thông qua eMSG.

Phát trong Safari

Safari 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ô dưới dạng một kênh ẩn để 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ể chuyển tất cả siêu dữ liệu đến SDK IMA DAI, dù 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ẽ được lọc ra tự động.

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 chúng theo hàng loạt 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ừ các mảng byte sang chuỗi và không bù trừ các sự kiện sang PTS tương ứng. Bạn không cần phải giải mã dữ liệu mẫu từ mảng byte sang chuỗi, vì SDK IMA DAI sẽ tự động giải mã việ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 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 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ị schemaIdUri của mỗi luồng sự kiện. Các trình xử lý tuỳ chỉnh này kích hoạt theo lô, do bạn có thể tuỳ ý xử lý giá trị PTS để xác định thời gian sự kiện đúng cách. 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);
});
...

Người chơi Shaka

Shaka Player hiển thị các sự kiện trong sự kiện timelineregionenter của họ. Do định dạng không tương thích với Shaka Player, nên giá trị siêu dữ liệu phải được truy xuất ở dạng thô thông qua thuộc tính chi tiết eventElement.attributes['messageData'].value.

Ví dụ:

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

Phân phát nhóm

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

  • Loại sự kiện phát trực tiếp hoặc video theo yêu cầu
  • Đị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 phát trực tiếp HLS (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 theo dõi sự kiện HLS.js FRAG_PARSING_METADATA để lấy siêu dữ liệu ID3 và chuyển siêu dữ liệu đó đến SDK bằng StreamManager.processMetadata().

Để tự động phát video sau khi mọi thứ được tải và sẵn sàng, hãy theo dõi sự kiện MANIFEST_PARSED HLS.js để kích hoạt chế độ 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 trực tiếp và VOD)

Nếu đang 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 các sự kiện phát 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 video theo yêu cầu: '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 nút điều khiển video sau khi mọi thứ được tải và sẵn sàng, hãy theo dõi sự kiện MANIFEST_LOADED 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);
}

Trình phát Shaka với chương trình phát trực tiếp (định dạng luồng DASH)

Nếu bạn đang dùng trình phát Shaaka để phát trực tiếp, hãy sử dụng chuỗi 'emsg' để nghe các sự kiện siêu dữ liệu. Sau đó, hãy sử dụng dữ liệu tin nhắn sự kiện trong cuộc gọi đến số 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});
}

Trình phát Shaka có luồng VOD (định dạng luồng DASH)

Nếu bạn đang dùng trình phát Shaka để phát luồng VOD, hãy sử dụng chuỗi 'timelineregionenter' để nghe các sự kiện siêu dữ liệu. Sau đó, 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);
       }
}