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) cho 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 hàng loạt siêu dữ liệu về thời gian. Tuỳ thuộc vào trình phát, siêu dữ liệu có thể xuất hiện vào thời điểm đã 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 biết 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 sẽ 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ỉ sử dụng một đối số duy nhất:

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

Phương thức này lên lịch cho các chuỗi siêu dữ liệu mà SDK sẽ xử lý sau PTS đã chỉ định. Phương thức 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 sẽ đượ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 duy nhất, như được mô tả trong các phần sau.

Luồng MPEG2TS HLS

Các luồng HLS tuyến tính của DAI sử dụng các phân đoạn MPEG2TS sẽ truyền siêu dữ liệu theo 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 thay đổi tín hiệu 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ể chuyển tất cả siêu dữ liệu đến SDK IMA DAI, bất kể nội dung hay loại nội dung. Siêu dữ liệu không liên quan được tự động 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

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

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 DAI tuyến tính sử dụng Khung chế độ ứ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, với mỗi eMSG mã nhận dạng 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 HLS.js 1.2.0, cả hai trình phát đề xuất của chúng tôi đều chuyể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ẽ tương tự 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 khả năng hỗ trợ cho luồng HLS CMAF 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 siêu dữ liệu ID3 thông qua eMSG là các sự kiện ID3 giả, cung cấp các sự kiện này theo lô, tự động dưới dạng một theo dõi ẩn để 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ể chuyển tất cả siêu dữ liệu đến SDK IMA DAI, cho 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 tự động 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à sự kiện ID3 giả, cung cấp chúng 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ừ các mảng byte thành chuỗi và không bù trừ sự kiện cho PTS tương ứng. Bạn không cần phải giải mã dữ liệu mẫu từ mảng byte thành 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 DASH DAI 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 các trình xử lý sự kiện tuỳ chỉnh được đặt tên theo giá trị SchemeIdUri của từng luồng sự kiện. Các trình xử lý tuỳ chỉnh này sẽ kích hoạt theo lô, do đó bạn có thể tuỳ ý xử lý giá trị PTS để tính giờ sự kiện cho phù hợp. SDK IMA DAI có thể xử lý vấn đề 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 về 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 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 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à truyề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 tính năng 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 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 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 VOD: 'urn:google:dai:2018'

Truyền siêu dữ liệu ID3 cho 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);
}

Shaka Player với sự kiện phát trực tiếp (định dạng luồng DASH)

Nếu bạn đang dùng trình phát Shaka để phát sự kiện phát trực tiếp, hãy 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 tin nhắn sự kiện trong cuộc 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 dùng trình phát Shaaka để 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);
       }
}