จัดการข้อมูลเมตาที่มีการระบุเวลาในสตรีม 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 เหล่านี้จะฝังอยู่ที่จุดเริ่มต้นของกลุ่มสื่อแต่ละกลุ่ม โดยแต่ละ ID3 eMSG จะมี 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 เป็นเหตุการณ์รหัส 3 จำลอง โดยจัดเตรียมข้อมูลเป็นกลุ่มผ่านเหตุการณ์ 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);
       }
}