จัดการข้อมูลเมตาที่มีการระบุเวลาในสตรีม DAI ที่ไม่ปรากฏร่วมกับวิดีโอ

SDK การแทรกโฆษณาแบบไดนามิก (DAI) สำหรับโฆษณาสื่ออินเทอร์แอกทีฟ (IMA) จะใช้ข้อมูลเมตาที่ฝังอยู่ในส่วนสื่อของสตรีม (ข้อมูลเมตาในกลุ่ม) หรือในไฟล์ Manifest ของสตรีมมิง (ข้อมูลเมตาในไฟล์ Manifest) เพื่อติดตามตำแหน่งของผู้ชมและเหตุการณ์โฆษณาฝั่งไคลเอ็นต์ ระบบจะส่งข้อมูลเมตาในรูปแบบต่างๆ โดยขึ้นอยู่กับประเภทของสตรีมที่เล่น

โปรแกรมเล่นวิดีโอจะได้รับข้อมูลเมตาที่มีการระบุเวลาเป็นกลุ่ม ข้อมูลเมตาอาจแสดงในเวลาที่กำหนดไว้หรือเป็นกลุ่มก็ได้ ทั้งนี้ขึ้นอยู่กับโปรแกรมเล่น สตริงข้อมูลเมตาแต่ละสตริงมีการประทับเวลาการนำเสนอ (PTS) ที่เกี่ยวข้องกันเพื่อระบุเวลาที่ควรทริกเกอร์

แอปของคุณมีหน้าที่บันทึกข้อมูลเมตาและส่งต่อไปยัง IMA DAI SDK SDK เสนอวิธีต่อไปนี้ในการส่งข้อมูลนี้

onTimedMetadata

เมธอดนี้จะส่งต่อสตริงข้อมูลเมตาที่พร้อมประมวลผลไปยัง SDK โดยใช้อาร์กิวเมนต์เดียว:

  • metadata: ออบเจ็กต์ที่มีคีย์ TXXX ซึ่งมีค่าสตริงที่เกี่ยวข้องซึ่งขึ้นต้นด้วย google_
processMetadata

เมธอดนี้จะกำหนดเวลาให้ SDK ประมวลผลสตริงข้อมูลเมตาหลัง PTS ที่ระบุ โดยใช้อาร์กิวเมนต์ต่อไปนี้

  • type: สตริงที่มีประเภทเหตุการณ์ที่กำลังประมวลผล ค่าที่ยอมรับคือ ID3 สำหรับ HLS หรือ urn:google:dai:2018 สำหรับ DASH
  • data: ค่าสตริงที่ขึ้นต้นด้วย google_ หรืออาร์เรย์ไบต์ที่ถอดรหัสสตริงดังกล่าว
  • timestamp: การประทับเวลาในหน่วยวินาทีที่ควรประมวลผลข้อมูล

สตรีมแต่ละประเภทที่ IMA DAI SDK รองรับจะใช้รูปแบบข้อมูลเมตาที่มีการระบุเวลาที่ไม่ซ้ำกัน ดังที่อธิบายไว้ในส่วนต่อไปนี้

สตรีม HLS MPEG2TS

สตรีม DAI HLS เชิงเส้นโดยใช้กลุ่ม MPEG2TS จะส่งข้อมูลเมตาที่มีการกำหนดเวลาไปยังโปรแกรมเล่นวิดีโอผ่านแท็ก 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 จะระบุแท็ก ID3 เป็นกลุ่มผ่านเหตุการณ์ FRAG_PARSING_METADATA เป็นอาร์เรย์ของตัวอย่าง HLS.js จะไม่แปลข้อมูล ID3 จากอาร์เรย์ไบต์เป็นสตริง และไม่แปลงค่าเหตุการณ์เป็น PTS ที่สอดคล้องกัน คุณไม่จำเป็นต้องถอดรหัสข้อมูลตัวอย่างจากไบต์อาร์เรย์เป็นสตริง หรือกรองแท็ก ID3 ที่ไม่เกี่ยวข้องออก เนื่องจาก 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);
    });
  }
});
...

สตรีม HLS CMAF

สตรีม DAI HLS เชิงเส้นที่ใช้ Common Media Application Framework (CMAF) จะส่งข้อมูลเมตาที่กำหนดเวลาผ่านกล่อง eMSGv1 ในย่านความถี่ตามมาตรฐาน ID3 ผ่าน CMAF ช่อง eMSG เหล่านี้จะฝังอยู่ที่ตอนต้นของแต่ละส่วนสื่อ โดย eMSG แต่ละรหัส 3 จะมี PTS ที่สัมพันธ์กับความไม่ต่อเนื่องครั้งล่าสุดในสตรีม

นับตั้งแต่ HLS.js เปิดตัวเวอร์ชัน 1.2.0 โปรแกรมเล่นทั้ง 2 โปรแกรมของเราจะส่ง ID3 ผ่าน CMAF ไปยังผู้ใช้ราวกับว่าเป็นแท็ก ID3 ด้วยเหตุนี้ ตัวอย่างต่อไปนี้จึงเป็นตัวอย่างสำหรับสตรีม HLS MPEG2TS อย่างไรก็ตาม ปัญหานี้อาจไม่เกิดขึ้นกับโปรแกรมเล่นทั้งหมด ดังนั้นการใช้การรองรับสตรีม HLS CMAF จึงอาจต้องใช้รหัสที่ไม่ซ้ำกันในการแยกวิเคราะห์ ID3 ผ่าน eMSG

การเล่นใน 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 เชิงเส้นจะส่งข้อมูลเมตาเป็นเหตุการณ์ไฟล์ Manifest ในสตรีมเหตุการณ์ด้วยค่า schemeIdUri ที่กำหนดเอง urn: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

Shaka Player จะแสดงกิจกรรมในเป็นส่วนหนึ่งของกิจกรรม timelineregionenter ของตน เนื่องจากการจัดรูปแบบเข้ากันไม่ได้กับ Shaka Player ระบบจึงต้องดึงค่าข้อมูลเมตาออกมาเป็นข้อมูลดิบผ่านพร็อพเพอร์ตี้รายละเอียด eventElement.attributes['messageData'].value

ตัวอย่าง

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

การแสดงในพ็อด

ในการแสดงโฆษณาในพ็อด จะมีการกำหนดค่าต่างๆ สำหรับการส่งข้อมูลเมตาที่กำหนดเวลา โดยขึ้นอยู่กับเกณฑ์ต่อไปนี้

  • ประเภทสตรีมแบบสดหรือ VOD
  • รูปแบบสตรีม HLS หรือ DASH
  • ประเภทของโปรแกรมเล่นที่ใช้
  • ประเภทแบ็กเอนด์ DAI ที่นำมาใช้

รูปแบบสตรีม HLS (สตรีมแบบสดและ VOD, โปรแกรมเล่น HLS.js)

หากคุณใช้โปรแกรมเล่น HLS.js ให้ฟังเหตุการณ์ HLS.js FRAG_PARSING_METADATA เพื่อรับข้อมูลเมตา ID3 และส่งไปยัง SDK ด้วย StreamManager.processMetadata()

หากต้องการเล่นวิดีโอโดยอัตโนมัติหลังจากที่ทุกอย่างโหลดและพร้อมแล้ว ให้ฟังเหตุการณ์ MANIFEST_PARSED ของ HLS.js เพื่อทริกเกอร์การเล่น

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 คุณต้องใช้สตริงอื่นเพื่อฟังข้อมูลเมตา ID3 สำหรับสตรีมแบบสดหรือ VOD

  • สตรีมแบบสด: 'https://developer.apple.com/streaming/emsg-id3'
  • สตรีม VOD: 'urn:google:dai:2018'

ส่งข้อมูลเมตา ID3 ไปยัง SDK ด้วย StreamManager.processMetadata()

หากต้องการแสดงตัวควบคุมวิดีโอโดยอัตโนมัติหลังจากที่ทุกอย่างโหลดและพร้อมแล้ว ให้ฟังเหตุการณ์ 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 ที่มีสตรีมแบบสด (รูปแบบสตรีม DASH)

หากคุณใช้โปรแกรมเล่น Shaka สำหรับการเล่นสตรีมแบบสด ให้ใช้สตริง '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});
}

Shaka Player ที่มีสตรีม VOD (รูปแบบสตรีม DASH)

หากคุณใช้โปรแกรมเล่น Shaka สำหรับการเล่นสตรีม VOD ให้ใช้สตริง 'timelineregionenter' เพื่อฟังเหตุการณ์ข้อมูลเมตา จากนั้นใช้ข้อมูลข้อความเหตุการณ์ในการโทรไปยัง StreamManager.processMetadata() ด้วยสตริง '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);
       }
}