ניהול מטא-נתונים מתוזמנים

בחירת פלטפורמה: HTML5 Roku

ה-SDK של Interactive Media Ads (IMA) Dynamic Ad Insertion (DAI)‎ (הטמעה דינמית של מודעות) מסתמך על מידע מטא-נתונים שמוטמע בפלחי המדיה של הסטרימינג (מטא-נתונים בתוך הסטרימינג) או בקובץ המניפסט של הסטרימינג (מטא-נתונים במניפסט) כדי לעקוב אחרי המיקום של הצופים ואירועי מודעות בצד הלקוח. המטא-נתונים נשלחים בפורמטים שונים, בהתאם לסוג הסטרימינג שמופעל.

נגן הווידאו מקבל מטא-נתונים עם חותמות זמן באצוות. בהתאם לנגן, המטא-נתונים יכולים להופיע בזמן המתוזמן או בקבוצות. לכל מחרוזת מטא-נתונים יש חותמת זמן (PTS) שמשויכת לה, שמציינת מתי צריך להפעיל אותה.

האפליקציה אחראית לתיעוד המטא-נתונים ולהעברתם אל IMA DAI SDK. ה-SDK מציע את השיטות הבאות להעברת המידע הזה:

onTimedMetadata

השיטה הזו מעבירה מחרוזות של מטא-נתונים שמוכנות לעיבוד אל ה-SDK. היא מקבלת ארגומנט אחד:

  • metadata: אובייקט שמכיל מפתח של TXXX עם ערך מחרוזת משויך שמתחיל ב-google_.
processMetadata

בשיטה הזו, מחרוזות המטא-נתונים מתוזמנות לעיבוד על ידי ה-SDK אחרי ה-PTS שצוין. הפונקציה מקבלת את הארגומנטים הבאים:

  • type: מחרוזת שמכילה את סוג האירוע שעובר עיבוד. הערכים האפשריים הם ID3 ל-HLS או urn:google:dai:2018 ל-DASH
  • data: ערך מחרוזת עם הקידומת google_ או מערך בייטים בפורמט הבא: ID3:u\0004u\000u\000u\0000TXXXu\0004u\000u\000u\0000google_xxxxxxxx.
  • timestamp: חותמת הזמן בשניות שבה הנתונים צריכים לעבור עיבוד.

כל סוג סטרימינג שנתמך על ידי IMA DAI SDK משתמש בצורה ייחודית של מטא-נתונים מתוזמנים, כפי שמתואר בקטעים הבאים.

שידורי HLS MPEG2TS

בסטרימינג לינארי של DAI בפורמט HLS, פלחים של MPEG2TS מעבירים מטא-נתונים מתוזמנים לנגן הווידאו באמצעות תגי ID3 בתוך הפס. תגי ID3 האלה מוטמעים בפלחי MPEG2TS ומקבלים את שם השדה TXXX (לתוכן טקסט מותאם אישית שהוגדר על ידי המשתמש).

הפעלה ב-Safari

דפדפן Safari מעבד תגי ID3 באופן אוטומטי, כרצועה מוסתרת, כך שאירועי cuechange מופעלים בזמן הנכון כדי לעבד כל חלק של מטא-נתונים. אפשר להעביר את כל המטא-נתונים אל 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 של ID3 מכיל PTS ביחס לאי הרציפות האחרונה בזרם.

החל מגרסה 1.2.0 של HLS.js, שני הנגנים המוצעים שלנו מעבירים 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 לינארי, המטא-נתונים מועברים כאירועים של מניפסט בסטרימינג של אירועים עם הערך המותאם אישית schemeIdUri urn:google:dai:2018. כל אירוע בזרמים האלה מכיל מטען ייעודי (payload) של טקסט, ואת חותמת הזמן של האירוע.

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 Player

‫Shaka Player מציג אירועים כחלק מהאירוע timelineregionenter. בגלל חוסר תאימות לפורמט של Shaka Player, צריך לאחזר את ערך המטא-נתונים בצורה גולמית דרך מאפיין הפרטים eventNode.attributes['messageData'].

לדוגמה:

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

הצגת מודעות ב-Pod

בשידור של פודקאסטים, יש הגדרות שונות להעברת מטא-נתונים עם חותמת זמן, בהתאם לקריטריונים הבאים:

  • סוג הסטרימינג: שידור חי או VOD
  • פורמט שידור HLS או DASH
  • סוג הנגן שבו נעשה שימוש
  • סוג ה-backend של DAI שבו נעשה שימוש

פורמט שידור HLS (שידורים חיים ושידורי VOD, נגן HLS.js)

אם אתם משתמשים בנגן HLS.js, צריך להאזין לאירוע FRAG_PARSING_METADATA של HLS.js כדי לקבל מטא נתונים של 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 player להפעלת שידורים חיים, צריך להשתמש במחרוזת '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 player להפעלה של סטרימינג של תוכן על פי דרישה, צריך להשתמש במחרוזת '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);
       }
}