צילום וידאו בסטרימינג מכל רכיב

François Beaufort
François Beaufort

באמצעות Screen capture API תוכלו לצלם את כל הכרטיסייה הנוכחית. Element Recording API מאפשר לצלם ולהקליט רכיב HTML ספציפי. הוא הופך צילום של כל הכרטיסייה לתיעוד של עץ משנה DOM ספציפי, ומתעד רק צאצאים ישירים של רכיב היעד. כלומר, הוא חותך ומסיר גם תוכן שמוסתר וגם תוכן מוסתר.

למה כדאי להשתמש בצילום רכיבים?

כשאתם מביאים בחשבון את הדרישות של אפליקציות לשיחות ועידה בווידאו, אתם יכולים להבין איפה עדיף להשתמש ב-Element שאתם (צילום רכיבים). אם יש לכם אפליקציה לשיחות ועידה בווידאו שמאפשרת להטמיע אפליקציות של צד שלישי ב-iframe, לפעמים כדאי לתעד את ה-iframe הזה כסרטון ולשדר אותו למשתתפים מרוחקים.

צילום מסך של שיחת ועידה בווידאו ב-Chrome.
אלי משתמש באפליקציה של צד שלישי בשיחת ועידה בווידאו עם François.

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

עם זאת, מה קורה אם מציג משתמש באפליקציה של שיחת הוועידה בווידאו, ותוכן מסוים, כמו רשימה נפתחת, מופיע מעל התוכן שמיועד לצילום?

צילום מסך של רשימה נפתחת הכוללת תוכן שמיועד לצילום.
רשימה נפתחת מופיעה מעל התוכן המיועד לצילום.

התכונה 'צילום אזורים' לא תעזור לך לעשות זאת. יכול להיות שחלק מהרשימה הנפתחת יופיעו במסכים של המשתתפים שמחוברים מרחוק.

צולמה צילום מסך של רשימה נפתחת.
הרשימה הנפתחת של אלי מופיעה בנוסף לתוכן שהתקבל על ידי פרנסואה.

העובדה שצילום אזור מסוים מתעד חלקים של רכיבים באופן הזה (שנקרא תוכן הסתרה) יוצרת בעיות רבות:

  • הסתרה של תוכן עלולה להסתיר את התוכן שהמשתמש התכוון לשתף.
  • הסתרה של תוכן עשויה להיות פרטית (למשל, התראות בצ'אט).
  • הסתרה של תוכן עלולה להיות מבלבלת. (לדוגמה, העברה מחדש של האפליקציה עשויה להעביר לזמן קצר את הסרטונים של המשתתפים המרוחקים אל עבר היעד שתועד).

ה-API לצילום של רכיבים פותר את כל הבעיות האלה ומאפשר לכם לטרגט את הרכיב שאתם רוצים לשתף.

צילום מסך של רכיב היעד ללא רשימה נפתחת.
François לא רואה את הרשימה הנפתחת של Elad.

איך משתמשים בצילום רכיבים?

ה-captureTarget הוא רכיב בדף שמכיל את התוכן שהמשתמש רוצה לצלם. ברצונך שאפליקציית האינטרנט לשיחות ועידה בווידאו תקליט את captureTarget ותשתף אותה עם המשתתפים שמחוברים מרחוק. לכן מקבלים RestrictionTarget מ-captureTarget. אחרי הגבלת הטראק של הסרטון באמצעות רכיב RestrictionTarget הזה, הפריימים בטראק הווידאו הזה מכילים עכשיו רק את הפיקסלים שהם חלק מ-captureTarget וצאצאים ישירים של DOM.

אם הגודל, הצורה או המיקום של captureTarget משנים את הגודל, הצורה או המיקום, טראק הסרטון הולך אחריו, בלי שיהיה צורך בקלט נוסף מאף אפליקציית אינטרנט. הסתרה של תוכן שמופיע, נעלם או זז, בדומה לכך, לא דורש טיפול מיוחד.

יש לבצע שוב את השלבים האלה:

כדי להתחיל, צריך לאפשר למשתמש לצלם את הכרטיסייה הנוכחית.

// Ask the user for permission to start capturing the current tab.
const stream = await navigator.mediaDevices.getDisplayMedia({
 preferCurrentTab: true,
});
const [track] = stream.getVideoTracks();

כדי להגדיר RestrictionTarget, שולחים קריאה ל-RestrictionTarget.fromElement() עם רכיב לבחירתכם כקלט.

// Associate captureTarget with a new RestrictionTarget
const captureTarget = document.querySelector("#captureTarget");
const restrictionTarget = await RestrictionTarget.fromElement(captureTarget);

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

// Start restricting the self-capture video track using the RestrictionTarget.
await track.restrictTo(restrictionTarget);

// Enjoy! Transmit remotely.

ירידה לעומק

זיהוי תכונות

כדי לבדוק אם RestrictionTarget.fromElement() נתמך, צריך להשתמש בקוד:

if ("RestrictionTarget" in self && "fromElement" in RestrictionTarget) {
  // Deriving a restriction target is supported.
}

גזירה של יעד הגבלה

מתמקדים ברכיב שנקרא captureTarget. כדי להפיק ממנו RestrictionTarget, צריך לבצע קריאה ל-RestrictionTarget.fromElement(captureTarget). ההבטחה שהוחזרה תטופל עם אובייקט RestrictionTarget חדש אם הפעולה בוצעה בהצלחה. אחרת, היא תידחה אם יונפקו מספר לא סביר של RestrictionTarget אובייקטים.

const captureTarget = document.querySelector("#captureTarget");
const restrictionTarget = await RestrictionTarget.fromElement(captureTarget);

בניגוד לרכיב, אובייקט RestrictionTarget ניתן לסידור מראש. למשל, אפשר להעביר אותה למסמך אחר באמצעות Window.postMessage().

הגבלה

במהלך צילום כרטיסייה, טראק הווידאו חושף את restrictTo(). כשמצלמים את הכרטיסייה הנוכחית, אפשר להשתמש בפונקציה restrictTo() עם null או עם RestrictionTarget שנגזר מרכיב בכרטיסייה הנוכחית.

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

// Start restricting the self-capture video track using the RestrictionTarget.
await track.restrictTo(restrictionTarget);

קריאות אל restrictTo(null) יחזירו את הטראק למצב המקורי שלו.

// Stop restricting.
await track.restrictTo(null);

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

אם תיכשל, ההבטחה תידחה. שיחה שנכשלה אל restrictTo() נובעת מאחת מהסיבות הבאות:

  • אם ה-restrictionTarget הוטבע בכרטיסייה אחרת מזו שמתועדת. (לידיעתכם, שימוש בלחצן 'שיתוף כרטיסייה זו במקום זאת' מאפשר למשתמשים לשנות בכל רגע נתון את הכרטיסייה שתועדה).
  • אם restrictionTarget נגזר מרכיב שכבר לא קיים.
  • אם בטראק יש שיבוטים. (ראו בעיה 1509418).
  • אם הטראק הנוכחי הוא לא טראק של צילום עצמי.
  • אם הרכיב שממנו נגזר restrictionTarget לא עומד בדרישות להגבלה.

שיקולים לצילום עצמי

כשאפליקציה שולחת קריאה ל-getDisplayMedia(), והמשתמש בוחר לצלם את הכרטיסייה של האפליקציה עצמה, אנחנו קוראים לזה 'צילום עצמי'.

השיטה restrictTo() חשופה בכל טראק וידאו לצילום כרטיסיות, ולא רק לצילום עצמי. עם זאת, התכונה 'צילום רכיבים' מופעלת כרגע רק לצילום עצמי. לכן מומלץ לבדוק אם המשתמש בחר בכרטיסייה הנוכחית, לפני שמנסים להגביל את הטראק. ניתן לעשות זאת באמצעות כינוי הצילום. אפשר גם לבקש מהדפדפן לעודד את המשתמש לצלם את עצמו באמצעות preferCurrentTab.

שקיפות

פריימים של סרטונים שהאפליקציה מקבלת דרך getDisplayMedia() לא כוללים ערוץ אלפא. אם האפליקציה מגדירה יעד צילום שקוף חלקית, להסרת ערוץ האלפא יש השלכות אפשריות:

  • הצבעים עשויים להשתנות. רכיבי יעד שקופים חלקית המשורטטים על רקע בהיר עשויים להיראות כהים יותר כשמסירים את ערוץ האלפא, ואלמנטים שמצוינים על רקע כהה עשויים להיראות בהירים יותר.
  • צבעים שהיו נסתרים או לא גלויים למשתמש כשערוץ האלפא הוגדר למקסימום, יופיעו לאחר הסרה של ערוץ האלפא. לדוגמה, יכול להיות שזה יגרום לאזורים שחורים לא צפויים בפריימים שתועדו, אם קוד ה-RGBA הוא rgba(0, 0, 0, 0) בקטעים השקופים.
צילום מסך של התוצאה של יעד צילום שקוף שאינו מלבן.
שידור היעד של הסרטון שקוף הוא לא מלבן (בצד ימין) הוא מלבן רקע שחור שמכיל עיגול כחול אטום.

יעדי לכידה לא עומדים בדרישות

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

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

<div id="captureTarget" style="isolation: isolate;"></iframe>

שימו לב שרכיב היעד יכול לעבור בין מצב עמידה בדרישות לעמידה בדרישות להגבלה בכל שלב שרירותי, למשל אם האפליקציה משנה את מאפייני ה-CSS שלה. האפליקציה צריכה להשתמש ביעדי קליטה סבירים ולא לשנות את המאפיינים שלהם באופן בלתי צפוי. אם רכיב היעד לא עומד בדרישות, פריימים חדשים פשוט לא יונפקו במסלול עד שרכיב היעד יעמוד שוב בדרישות להגבלה.

הפעלת צילום רכיבים

ממשק ה-API של 'צילום רכיבים' זמין ב-Chrome במחשב מאחורי הדגל Element Recording ואפשר להפעיל אותו ב-chrome://flags/#element-capture.

התכונה הזו גם מוסיפה גרסת מקור לניסיון מ-Chrome 121 במחשב. הגרסה הזו מאפשרת למפתחים להפעיל את התכונה הזאת למבקרים באתרים שלהם כדי לאסוף נתונים ממשתמשים אמיתיים. למידע נוסף על גרסאות מקור לניסיון, ראו איך מתחילים לעבוד עם גרסאות מקור לניסיון.

אבטחה ופרטיות

כדי להבין את ההשפעות שיכולות להיות לכך על האבטחה, כדאי לעיין בקטע שיקולי פרטיות ואבטחה במפרט של 'צילום רכיבים'.

דפדפן Chrome משרטט מסגרת כחולה מסביב לקצוות של כרטיסיות שצולמו.

הדגמה (דמו)

כדי לשחק עם Element Upload (צילום רכיבים), מריצים את ההדגמה ב-Glitch. חשוב לבדוק את קוד המקור.

משוב

צוות Chrome וקהילת תקני האינטרנט רוצים לשמוע על החוויה שלכם עם Element Recording.

נשמח לשמוע על העיצוב

האם יש משהו בתכונה 'צילום אזור' שלא פועל כצפוי? או שיש שיטות או מאפיינים חסרים שתצטרכו ליישם את הרעיון שלכם? יש לך שאלה או הערה לגבי מודל האבטחה?

  • אפשר לדווח על בעיית מפרט במאגר GitHub או להוסיף רעיונות לגבי בעיה קיימת.

נתקלתם בבעיה בהטמעה?

מצאת באג בהטמעה של Chrome? או שההטמעה שונה מהמפרט?

  • דיווח על באג בכתובת https://new.crbug.com. חשוב לכלול כמה שיותר פרטים והוראות פשוטות לשחזור הבעיה. Glitch היא אפשרות טובה לשיתוף תגובות מהירות וקלות.

אימות חתימות

צילום: פול Skorupskas ב-Unbounce