Encrypted Media Extensions (EME) הוא ממשק API שמאפשר לאפליקציות אינטרנט לקיים אינטראקציה עם מערכות להגנה על תוכן, כדי לאפשר הפעלה של אודיו ווידאו מוצפנים.
EME נועד לאפשר שימוש באותה אפליקציה ובקבצים מוצפנים בכל דפדפן, ללא קשר למערכת ההגנה הבסיסית. האפשרות הראשונה מתאפשרת באמצעות ממשקי API וזרימה סטנדרטיים, והשיטה השנייה מתאפשרת באמצעות הרעיון של Common Encryption (הצפנה משותפת).
EME הוא תוסף למפרט HTMLMediaElement
– ומכאן השם. העובדה ש-EME הוא 'תוסף' מאפשרת לדפדפנים לבחור אם לתמוך בו: אם דפדפן לא תומך במדיה מוצפנת, הוא לא יוכל להפעיל מדיה מוצפנת, אבל EME לא נדרש כדי לעמוד בדרישות של מפרט HTML. ממפרט ה-EME:
הטמעות של EME משתמשות ברכיבים החיצוניים הבאים:
- מערכת מפתחות: מנגנון להגנה על תוכן (DRM). EME לא מגדיר מערכות מפתחות בעצמו, מלבד Clear Key (מידע נוסף על כך בהמשך).
- מודול לפענוח תוכן (CDM): מנגנון תוכנה או חומרה בצד הלקוח שמאפשר הפעלה של מדיה מוצפנת. בדומה ל-Key Systems, EME לא מגדיר שירותי CDM, אלא מספק ממשק לאפליקציות כדי שיוכלו לקיים אינטראקציה עם שירותי CDM שזמינים.
- שרת רישיונות (מפתחות): מתקשר עם CDM כדי לספק מפתחות לפענוח מדיה. המשא ומתן עם שרת הרישיונות הוא באחריות האפליקציה.
- שירות אריזה: קידוד והצפנה של מדיה לצורך הפצה או שימוש.
חשוב לזכור שאפליקציה שמשתמשת ב-EME יוצרת אינטראקציה עם שרת רישיונות כדי לקבל מפתחות שמאפשרים פענוח, אבל הזהות והאימות של המשתמש לא נכללים ב-EME. אחזור המפתחות כדי לאפשר הפעלת מדיה מתבצע אחרי אימות המשתמש (אופציונלי). שירותים כמו Netflix חייבים לאמת משתמשים באפליקציית האינטרנט שלהם: כשמשתמש נכנס לאפליקציה, האפליקציה קובעת את הזהות וההרשאות של המשתמש.
איך פועל EME?
כך הרכיבים של EME מקיימים אינטראקציה, בהתאם לדוגמת הקוד הבאה:
- אפליקציית אינטרנט מנסה להפעיל אודיו או וידאו עם שידור מוצפן אחד או יותר.
- הדפדפן מזהה שהמדיה מוצפנת (בתיבה שבהמשך מוסבר איך זה קורה) ומפעיל אירוע
encrypted
עם מטא-נתונים (initData
) שהתקבלו מהמדיה בנושא ההצפנה. - האפליקציה מטפלת באירוע
encrypted
:- אם לא שויך לאלמנט המדיה אובייקט
MediaKeys
, קודם צריך לבחור מערכת מפתחות זמינה באמצעותnavigator.requestMediaKeySystemAccess()
כדי לבדוק אילו מערכות מפתחות זמינות, ואז ליצור אובייקטMediaKeys
למערכת מפתחות זמינה באמצעות אובייקטMediaKeySystemAccess
. חשוב לשים לב שאתחול האובייקט MediaKeys צריך להתרחש לפני האירוע הראשון מסוגencrypted
. קבלת כתובת ה-URL של שרת הרישיונות מתבצעת על ידי האפליקציה בנפרד מהבחירה של מערכת המפתחות הזמינה. אובייקטMediaKeys
מייצג את כל המפתחות שזמינים לפענוח המדיה של רכיב אודיו או וידאו. הוא מייצג מכונה של CDM ומספק גישה ל-CDM, במיוחד ליצירת סשנים של מפתחות, המשמשים לקבלת מפתחות משרת רישיונות. - אחרי שהאובייקט
MediaKeys
נוצר, מקצים אותו לאלמנט המדיה:setMediaKeys()
משייך את האובייקטMediaKeys
ל-HTMLMediaElement, כדי שאפשר יהיה להשתמש במפתחות שלו במהלך הפעלה, כלומר במהלך הפענוח.
- אם לא שויך לאלמנט המדיה אובייקט
- האפליקציה יוצרת
MediaKeySession
על ידי קריאה ל-createSession()
ב-MediaKeys
. הפונקציה יוצרתMediaKeySession
שמייצג את משך החיים של רישיון ומפתחותיו. - האפליקציה יוצרת בקשת רישיון על ידי העברת נתוני המדיה שהתקבלו במטפל
encrypted
ל-CDM, באמצעות קריאה ל-generateRequest()
ב-MediaKeySession
. - ה-CDM יוצר אירוע
message
: בקשה לקבלת מפתח משרת רישיונות. - האובייקט
MediaKeySession
מקבל את האירועmessage
והאפליקציה שולחת הודעה לשרת הרישיונות (לדוגמה, באמצעות XHR). - האפליקציה מקבלת תשובה משרת הרישיונות ומעבירה את הנתונים ל-CDM באמצעות השיטה
update()
שלMediaKeySession
. - ה-CDM מפענח את המדיה באמצעות המפתחות ברישיון. אפשר להשתמש במפתח תקף מכל סשן בתוך הערכים של
MediaKey
שמשויכים לרכיב המדיה. ה-CDM ייגש למפתח ולמדיניות, וייוצרו להם אינדקסים לפי מזהה המפתח. - הפעלת המדיה תמשיך.
איזה מזל...
שימו לב שיכולות להיות מספר הודעות בין ה-CDM לבין שרת הרישיון, וכל התקשורת בתהליך הזה תהיה אטומה לדפדפן ולאפליקציה: ההודעות מובנות רק על ידי ה-CDM ושרת הרישיון, אבל שכבת האפליקציה יכולה לראות איזה סוג של הודעה ה-CDM שולח. בקשת הרישיון מכילה הוכחה לתקינות של CDM (וליחסי האמון שלו), וגם מפתח לשימוש בהצפנת מפתחות התוכן ברישיון שנוצר.
...אבל מה בדיוק עושים ב-CDM?
הטמעת EME לא מספקת בעצמה דרך לפענח מדיה: היא פשוט מספקת ממשק API לאפליקציית אינטרנט כדי ליצור אינטראקציה עם מודולים לפענוח תוכן.
מה ש-CDM עושים בפועל לא מוגדר במפרט EME, ו-CDM עשוי לטפל בפענוח (ביטול דחיסה) של מדיה וגם בפענוח. יש כמה אפשרויות פוטנציאליות לפונקציונליות של CDM:
- פענוח בלבד, שמאפשר הפעלה באמצעות צינור עיבוד הנתונים הרגיל של המדיה, למשל באמצעות רכיב
<video>
. - פענוח ופענוח, העברת פריימים של וידאו לדפדפן לצורך עיבוד.
- פענוח ופענוח, עיבוד ישירות בחומרה (לדוגמה, GPU).
יש כמה דרכים להפוך מאגר נתונים מנוהל (CDM) לזמין לאפליקציית אינטרנט:
- מצרפים CDM לדפדפן.
- הפצת CDM בנפרד.
- נכנסים ל-CDM במערכת ההפעלה.
- הכללת CDM בקושחה.
- הטמעת CDM בחומרה.
אופן הזמינות של CDM לא מוגדר במפרט EME, אבל בכל המקרים הדפדפן אחראי על בדיקת ה-CDM ועל חשיפת ה-CDM.
EME לא מחייב מערכת מפתחות ספציפית. בין הדפדפנים הנוכחיים למחשבים או לניידים, Chrome תומך ב-Widevine וב-IE11 יש תמיכה ב-PlayReady.
אחזור מפתח משרת רישיונות
בשימוש מסחרי רגיל, התוכן ינוווט ויקודר באמצעות שירות או כלי לאריזה. אחרי שהמדיה המוצפנת זמינה באינטרנט, לקוח אינטרנט יכול לקבל מפתח (שכלול ברישיון) משרת רישיונות ולהשתמש במפתח כדי לאפשר פענוח והפעלה של התוכן.
הקוד הבא (שהוא עיבוד של דוגמאות למפרט) מראה איך אפליקציה יכולה לבחור מערכת מפתחות מתאימה ולקבל מפתח משרת רישיונות.
var video = document.querySelector('video');
var config = [{initDataTypes: ['webm'],
videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}]}];
if (!video.mediaKeys) {
navigator.requestMediaKeySystemAccess('org.w3.clearkey',
config).then(
function(keySystemAccess) {
var promise = keySystemAccess.createMediaKeys();
promise.catch(
console.error.bind(console, 'Unable to create MediaKeys')
);
promise.then(
function(createdMediaKeys) {
return video.setMediaKeys(createdMediaKeys);
}
).catch(
console.error.bind(console, 'Unable to set MediaKeys')
);
promise.then(
function(createdMediaKeys) {
var initData = new Uint8Array([...]);
var keySession = createdMediaKeys.createSession();
keySession.addEventListener('message', handleMessage,
false);
return keySession.generateRequest('webm', initData);
}
).catch(
console.error.bind(console,
'Unable to create or initialize key session')
);
}
);
}
function handleMessage(event) {
var keySession = event.target;
var license = new Uint8Array([...]);
keySession.update(license).catch(
console.error.bind(console, 'update() failed')
);
}
הצפנה משותפת
פתרונות של הצפנה משותפת מאפשרים לספקים של תוכן להצפין ולארז את התוכן שלהם פעם אחת לכל מאגר/קודק, ולהשתמש בו עם מגוון מערכות מפתחות, מערכות ניהול נתונים עיבוד (CDM) ולקוחות: כלומר, כל CDM שתומך בהצפנה משותפת. לדוגמה, אפשר להפעיל סרטון שארוז באמצעות PlayReady בדפדפן באמצעות CDM של Widevine שמקבל מפתח משרת רישיונות של Widevine.
בניגוד לפתרונות מדור קודם שפועלים רק עם סטאק אנכי שלם, כולל לקוח יחיד שלרוב כלל גם זמן ריצה של אפליקציה.
הצפנה משותפת (CENC) היא תקן ISO שמגדיר סכמת הגנה ל-ISO BMFF. קונספט דומה חל על WebM.
מקש ניקוי
אמנם EME לא מגדיר את הפונקציונליות של DRM, אבל לפי המפרט הנוכחי, כל הדפדפנים שתומכים ב-EME חייבים להטמיע את Clear Key. באמצעות המערכת הזו, אפשר להצפין מדיה באמצעות מפתח ולאחר מכן להפעיל אותה פשוט על ידי מתן המפתח. אפשר להטמיע את Clear Key בדפדפן: הוא לא מחייב שימוש במודול נפרד לפענוח.
סביר להניח שלא נעשה שימוש ב-Clear Key בסוגים רבים של תוכן מסחרי, אבל הוא תומך בכל הדפדפנים שתומכים ב-EME. הוא גם שימושי לבדיקת הטמעות של EME ואפליקציות שמשתמשות ב-EME, בלי צורך לבקש מפתח תוכן משרת רישיונות. בכתובת simpl.info/ck אפשר למצוא דוגמה פשוטה ל'מפתח ברור'. בהמשך מופיע הסבר מפורט על הקוד, שתואם לשלבים שמפורטים למעלה, אבל ללא אינטראקציה עם שרת הרישיונות.
// Define a key: hardcoded in this example
// – this corresponds to the key used for encryption
var KEY = new Uint8Array([
0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
]);
var config = [{
initDataTypes: ['webm'],
videoCapabilities: [{
contentType: 'video/webm; codecs="vp8"'
}]
}];
var video = document.querySelector('video');
video.addEventListener('encrypted', handleEncrypted, false);
navigator.requestMediaKeySystemAccess('org.w3.clearkey', config).then(
function(keySystemAccess) {
return keySystemAccess.createMediaKeys();
}
).then(
function(createdMediaKeys) {
return video.setMediaKeys(createdMediaKeys);
}
).catch(
function(error) {
console.error('Failed to set up MediaKeys', error);
}
);
function handleEncrypted(event) {
var session = video.mediaKeys.createSession();
session.addEventListener('message', handleMessage, false);
session.generateRequest(event.initDataType, event.initData).catch(
function(error) {
console.error('Failed to generate a license request', error);
}
);
}
function handleMessage(event) {
// If you had a license server, you would make an asynchronous XMLHttpRequest
// with event.message as the body. The response from the server, as a
// Uint8Array, would then be passed to session.update().
// Instead, we will generate the license synchronously on the client, using
// the hard-coded KEY at the top.
var license = generateLicense(event.message);
var session = event.target;
session.update(license).catch(
function(error) {
console.error('Failed to update the session', error);
}
);
}
// Convert Uint8Array into base64 using base64url alphabet, without padding.
function toBase64(u8arr) {
return btoa(String.fromCharCode.apply(null, u8arr)).
replace(/\+/g, '-').replace(/\//g, '_').replace(/=*$/, '');
}
// This takes the place of a license server.
// kids is an array of base64-encoded key IDs
// keys is an array of base64-encoded keys
function generateLicense(message) {
// Parse the clearkey license request.
var request = JSON.parse(new TextDecoder().decode(message));
// We only know one key, so there should only be one key ID.
// A real license server could easily serve multiple keys.
console.assert(request.kids.length === 1);
var keyObj = {
kty: 'oct',
alg: 'A128KW',
kid: request.kids[0],
k: toBase64(KEY)
};
return new TextEncoder().encode(JSON.stringify({
keys: [keyObj]
}));
}
כדי לבדוק את הקוד הזה, צריך להפעיל סרטון מוצפן. אפשר להצפין סרטון לשימוש עם Clear Key בפורמט WebM לפי ההוראות של webm_crypt. קיימים גם שירותים מסחריים (בתקן ISO BMFF/MP4 לפחות), ואנחנו מפתחים פתרונות אחרים.
טכנולוגיה קשורה מס' 1
תוספי מקור מדיה (MSE)
HTMLMediaElement הוא יצור פשוט ויפה.
אנחנו יכולים לטעון, לפענח ולהפעיל מדיה פשוט על ידי מתן כתובת URL מסוג src:
<video src='foo.webm'></video>
Media Source API הוא תוסף ל-HTMLMediaElement שמאפשר שליטה מפורטת יותר על מקור המדיה, על ידי מתן אפשרות ל-JavaScript ליצור סטרימינג להפעלה מ'קטעים' של וידאו. כך אפשר להשתמש בשיטות כמו סטרימינג אדפטיבי ושינוי מהירות.
למה MSE חשוב ל-EME? הסיבה לכך היא שבנוסף להפצת תוכן מוגן, ספקי תוכן מסחרי צריכים להיות מסוגלים להתאים את העברת התוכן לתנאי הרשת ולדרישות אחרות. לדוגמה, ב-Netflix, קצב העברת הנתונים משתנה באופן דינמי בהתאם לשינויים בתנאי הרשת. EME פועל עם הפעלה של שידורי מדיה שסופקו על ידי הטמעת MSE, בדיוק כמו שהוא פועל עם מדיה שסופקה באמצעות מאפיין src
.
איך מחלקים קטעי מדיה עם קצב העברת נתונים שונה לקטעים ומפעילים אותם? עיינו בקטע DASH בהמשך.
אפשר לראות את MSE בפעולה בכתובת simpl.info/mse. לצורך הדוגמה הזו, סרטון WebM מחולק לחמישה קטעים באמצעות ממשקי ה-API של קבצים. באפליקציה בסביבת ייצור, קטעי וידאו יאוחזרו באמצעות Ajax.
קודם נוצר SourceBuffer:
var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');
לאחר מכן, הסרט כולו 'מועבר בסטרימינג' אל רכיב וידאו על ידי צירוף כל מקטע באמצעות השיטה appendBuffer():
reader.onload = function (e) {
sourceBuffer.appendBuffer(new Uint8Array(e.target.result));
if (i === NUM_CHUNKS - 1) {
mediaSource.endOfStream();
} else {
if (video.paused) {
// start playing after first chunk is appended
video.play();
}
readChunk_(++i);
}
};
מידע נוסף על MSE זמין במאמר HTML5 Rocks.
טכנולוגיה קשורה מס' 2
שידור דינמי שניתן להתאמה באמצעות HTTP (DASH)
ריבוי מכשירים, פלטפורמות מרובות, נייד – איך שקוראים לזה, בדרך כלל האינטרנט סובל מתנאים של קישוריות שניתנת לשינוי. העברה דינמית ומותאמת היא קריטית כדי להתמודד עם מגבלות רוחב פס ועם התנודות בעולם של מכשירים מרובים.
DASH (נקרא גם MPEG-DASH) נועד לספק את העברת המדיה הטובה ביותר האפשרית בעולם לא יציב, גם בסטרימינג וגם בהורדה. כמה טכנולוגיות אחרות מבצעות פעולה דומה – כמו HTTP Live Streaming (HLS) של Apple ו-Smooth Streaming – אבל DASH היא השיטה היחידה לסטרימינג עם קצב העברת נתונים דינמי דרך HTTP המבוסס על תקן פתוח. DASH כבר נמצא בשימוש באתרים כגון YouTube.
מה הקשר בין זה ל-EME ול-MSE? הטמעות DASH שמבוססות על MSE יכולות לנתח מניפסט, להוריד קטעי וידאו בקצב נתונים מתאים ולהעביר אותם לרכיב וידאו כשהוא זקוק לנתונים – באמצעות תשתית HTTP קיימת.
במילים אחרות, DASH מאפשר לספקי תוכן מסחרי לבצע סטרימינג מותאם של תוכן מוגן.
ה-DASH עושה את מה שהוא מציע:
- דינמית: מגיבה לשינויים בתנאים.
- דינמי: הסרטון מותאם כדי לספק קצב דגימה מתאים של אודיו או וידאו.
- סטרימינג: מאפשר סטרימינג וגם הורדה.
- HTTP: מאפשר העברת תוכן באמצעות היתרון של HTTP, ללא החסרונות של שרת סטרימינג מסורתי.
BBC התחילה לספק שידורי בדיקה באמצעות DASH:
לסיכום:
- המדיה מקודדת בקצבי העברת נתונים שונים.
- קובצי קצב העברת הנתונים השונים זמינים משרת HTTP.
- אפליקציית אינטרנט לקוח בוחרת את קצב הנתונים לאחזור ולהפעלה באמצעות DASH.
כחלק מתהליך פילוח הסרטון, נוצר באופן פרוגרמטי מניפסט XML שנקרא תיאור של הצגת מדיה (MPD). כאן מתוארים קבוצות של התאמות ותצוגות, עם משכים וכתובות URL. קובץ MPD נראה כך:
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" mediaPresentationDuration="PT0H3M1.63S" minBufferTime="PT1.5S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011"
type="static">
<Period duration="PT0H3M1.63S" start="PT0S">
<AdaptationSet>
<ContentComponent contentType="video" id="1" />
<Representation bandwidth="4190760" codecs="avc1.640028" height="1080" id="1" mimeType="video/mp4" width="1920">
<BaseURL>car-20120827-89.mp4</BaseURL>
<SegmentBase indexRange="674-1149">
<Initialization range="0-673" />
</SegmentBase>
</Representation>
<Representation bandwidth="2073921" codecs="avc1.4d401f" height="720" id="2" mimeType="video/mp4" width="1280">
<BaseURL>car-20120827-88.mp4</BaseURL>
<SegmentBase indexRange="708-1183">
<Initialization range="0-707" />
</SegmentBase>
</Representation>
…
</AdaptationSet>
</Period>
</MPD>
(קובץ ה-XML הזה נלקח מקובץ ה-.mpd שמשמש את נגן הדגמה של YouTube DASH)
לפי מפרט DASH, באופן תיאורטי אפשר להשתמש בקובץ MPD בתור src
של סרטון. עם זאת, כדי לתת גמישות רבה יותר למפתחי אתרים, יצרני הדפדפנים בחרו להשאיר את התמיכה ב-DASH לספריות JavaScript שמשתמשות ב-MSE, כמו dash.js. הטמעת DASH ב-JavaScript מאפשרת לאלגוריתם ההתאמה להתפתח בלי צורך בעדכוני דפדפן. השימוש ב-MSE מאפשר גם להתנסות בפורמטים חלופיים של מניפסטים ובמנגנוני הצגת מודעות חלופיים ללא צורך בביצוע שינויים בדפדפן. Shaka Player של Google מטמיע לקוח DASH עם תמיכה ב-EME.
ב-Mozilla Developer Network יש הוראות לשימוש בכלים של WebM ו-FFmpeg כדי לפלח סרטונים וליצור קובץ MPD.
סיכום
השימוש באינטרנט להעברת סרטונים ואודיו בתשלום הולך וגדל בקצב עצום. נראה שכל מכשיר חדש, בין אם מדובר בטאבלט, בקונסולת משחקים, בטלוויזיה מחוברת או בממיר, מסוגל להעביר מדיה בסטרימינג מספקי התוכן הגדולים באמצעות HTTP. יותר מ-85% מהדפדפנים לנייד ולמחשב תומכים עכשיו ב-<video>
וב-<audio>
, וסיכום של Cisco הוא שסרטונים ייצגו 80 עד 90 אחוז מתנועת הגולשים הגלובלית באינטרנט עד שנת 2017. בהקשר הזה, סביר להניח שהתמיכה של הדפדפנים בהפצת תוכן מוגן תלך ותגבר, כי ספקי הדפדפנים מגבילים תמיכה בממשקי API שרוב יישומי הפלאגין של המדיה מסתמכים עליהם.
קריאה נוספת
מפרטים ותקנים
- מפרט EME: הטיוטה העדכנית ביותר של העורך
- הצפנה נפוצה (CENC)
- תוספים למקור מדיה
- תקן DASH (כן, זה קובץ PDF)
- מידע על תקן DASH
מאמרים
- DTG Webinar (מיושן חלקית)
- מה זה EME?, מאת Henri Sivonen
- מאמר בנושא HTML5 Rocks Media Source Extensions
- נתוני זרם לבדיקה של MPEG-DASH: פוסט בבלוג של BBC R&D