קוראים לי דיל קורטיס ואני מנהל ההנדסה של הפעלת המדיה ב-Chromium. הצוות שלי אחראי על ממשקי ה-API שגלויים לאינטרנט להפעלת וידאו, כמו MSE ו-WebCodecs, ועל הרכיבים הפנימיים הספציפיים לפלטפורמה שקשורים לפירוק רכיבים, לפענוח ולעיבוד של אודיו ווידאו.
במאמר הזה אציג את הארכיטקטורה של עיבוד הווידאו ב-Chromium. ייתכן שחלק מהפרטים לגבי יכולת ההרחבה יהיו ספציפיים ל-Chromium, אבל רוב המושגים והעיצובים שנדון בהם כאן רלוונטיים למנועי עיבוד אחרים ואפילו לאפליקציות הפעלה מקוריות.
ארכיטקטורת ההפעלה של Chromium השתנתה באופן משמעותי במהלך השנים. לא התחלנו עם הרעיון של פירמידה של הצלחה כפי שמתואר בפוסט הראשון בסדרה הזו, אבל בסופו של דבר פעלנו לפי שלבים דומים: אמינות, ביצועים ואז יכולת התאמה.
בהתחלה, עיבוד הווידאו היה פשוט למדי – רק לולאת for שבוחרת איזו תוכנה תפענח את הפריימים של הסרטון ששולחים למעבד הקומפוזיציה. במשך שנים הפתרון הזה היה מהימן מספיק, אבל ככל שהאינטרנט הפך למורכב יותר, הצורך בביצועים וביעילות טובים יותר הוביל לשינויים בארכיטקטורה. שיפורים רבים דרשו פריימים בסיסיים ספציפיים למערכת ההפעלה, ולכן הארכיטקטורה שלנו גם נדרשה להיות ניתנת להתאמה כדי להגיע לכל הפלטפורמות של Chromium.
אפשר לחלק את תהליך העיבוד של סרטונים לשני שלבים: בחירה של מה שרוצים להעביר והעברת המידע הזה בצורה יעילה. כדי להקל על הקריאה, אתחיל בהסבר על העברה יעילה ואז אמשיך להסביר איך Chromium בוחרת מה להעביר.
חלק מהמונחים והפריסה
המאמר הזה מתמקד ברינדור, ולכן אגע בקצרה רק בהיבטים של ניתוק ה-muxing ופענוח הצינור עיבוד הנתונים.
פעולות הפענוח והביטול של מיזוג הערוצים (demuxing) בעולם המודרני שמתאפיין בדאגה רבה לאבטחה מחייבות הרבה זהירות. מנתח נתונים בינאריים הוא סביבות יעד עשירות, והפעלת מדיה מלאה בניתוח נתונים בינאריים. לכן, בעיות אבטחה בניתחי מדיה הן נפוצות מאוד.
ב-Chromium אנחנו משתמשים בשיטת הגנה לעומק כדי לצמצם את הסיכון לבעיות אבטחה אצל המשתמשים שלנו. בפועל, המשמעות היא שפענוח תוכנה ופירוק מודולים תמיד מתרחשים בתהליך עם הרשאות נמוכות, ואילו פענוח חומרה מתרחש בתהליך עם מספיק הרשאות כדי לתקשר עם ה-GPU של המערכת.
מנגנון התקשורת בין תהליכים ב-Chromium נקרא Mojo. לא נרחיב על Mojo במאמר הזה, אבל הוא שכבת האבסטרקציה בין התהליכים, והוא אבן יסוד בצינור עיבוד הנתונים המותאם אישית של Chromium. חשוב לזכור את זה כשנעבור על צינור עיבוד הנתונים של ההפעלה, כי הוא מאפשר להבין את התזמור המורכב של רכיבים חוצי-תהליכים שמקיימים אינטראקציה כדי לקבל, לבצע ניתוק מMUX, לפענח ולבסוף להציג מדיה.
כל כך הרבה ביטים
כדי להבין את צינורות עיבוד הווידאו של היום, צריך להבין למה סרטונים הם מיוחדים: רוחב פס. הפעלה ברזולוציה של 3840x2160 (4K) בקצב של 60 פריימים לשנייה צורכת בין 9 ל-12 ג'יגה-ביט לשנייה של רוחב פס זיכרון. למערכות מודרניות יכולה להיות רוחב פס שיא של מאות ג'יגה-ביט לשנייה, אבל הפעלת וידאו עדיין מהווה חלק משמעותי ממנו. אם לא נוהגים בזהירות, רוחב הפס הכולל יכול להכפיל את עצמו בקלות בגלל עותקים או נסיעות בין זיכרון ה-GPU לזיכרון ה-CPU.
המטרה של כל מנוע מודרני להפעלת וידאו שמתמקד ביעילות היא למזער את רוחב הפס בין המקודד לשלב הטרנספורמציה הסופי. לכן, עיבוד הווידאו מנותק במידה רבה צינור העיבוד הראשי של Chromium. באופן ספציפי, מנקודת המבט של צינור עיבוד הנתונים הראשי לעיבוד, סרטון הוא רק חור בגודל קבוע עם עכירות. Chromium משיג זאת באמצעות מושג שנקרא משטחים – שבו כל סרטון פונה ישירות ל-Viz.
בגלל הפופולריות של המחשוב הנייד, עוצמה ויעילות הפכו לנושאים מרכזיים בדור הנוכחי. כתוצאה מכך, פענוח הקוד והעיבוד (רנדר) מקושרים יותר מאי פעם ברמת החומרה, וכתוצאה מכך הסרטון נראה כמו חור עם אטימות, גם למערכת ההפעלה עצמה. פעמים רבות, מקודדים ברמת הפלטפורמה מספקים רק מאגרים אטומים ש-Chromium מעביר למערכת הרכבת התמונות ברמת הפלטפורמה בצורת שכבות-על.
לכל פלטפורמה יש סוג משלה של שכבות-על, שממשקי ה-API לפענוח של הפלטפורמה פועלים בהתאם אליהן. ב-Windows יש Direct Composition ו-Media Foundation Transforms, ב-macOS יש CoreAnimation Layers ו-VideoToolbox, ב-Android יש SurfaceView ו-MediaCodec וב-Linux יש VASurfaces ו-VA-API. הממשקים OverlayProcessor ו-mojo::VideoDecoder מטפלים בהכללות של Chromium למושגים האלה, בהתאמה.
במקרים מסוימים, אפשר למפות את המאגרים האלה לזיכרון המערכת, כך שהם אפילו לא צריכים להיות אטומים ולא צורכים רוחב פס עד שמשתמשים בהם. ב-Chromium הם נקראים GpuMemoryBuffers. ב-Windows, הם נתמכים על ידי מאגרי DXGI, ב-macOS על ידי IOSurfaces, ב-Android על ידי AHardwareBuffers וב-Linux על ידי מאגרי DMA. בדרך כלל אין צורך בגישה הזו להפעלת וידאו, אבל מאגרי הנתונים האלה חשובים לצילום וידאו כדי להבטיח רוחב פס מינימלי בין מכשיר הצילום לבין המקודדים הסופיים.
מאחר שה-GPU אחראי לרוב גם על פענוח וגם על הצגה, השימוש במאגרים האטומים האלה (שגם הם לרוב אטומים) מבטיח שנתוני וידאו עם רוחב פס גבוה אף פעם לא יוצאים מה-GPU. כפי שציינו קודם, חשוב מאוד לשמור נתונים ב-GPU כדי לשפר את היעילות, במיוחד ברזולוציות גבוהות ובקצב פריימים גבוה.
ככל שנוכל לנצל יותר את הרכיבים הבסיסיים של מערכת ההפעלה, כמו שכבות-על ומאגרי GPU, כך נוכל לחסוך יותר ברוחב הפס שנדרש להעברת ביטים של וידאו ללא צורך. שמירת הכול במקום אחד, מהפענוח ועד לעיבוד, יכולה להוביל ליעילות אנרגטית מדהימה. לדוגמה, כשהפעלנו שכבות-על ב-Chromium ב-macOS, צריכת החשמל במהלך הפעלת סרטונים במסך מלא ירדה בחצי. בפלטפורמות אחרות, כמו Windows, Android ו-ChromeOS, אנחנו יכולים להשתמש בשכבות-על גם במקרים שבהם המסך לא מלא, וכך לחסוך עד 50% כמעט בכל מקום.
רינדור
אחרי שסיפרנו על מנגנוני ההעברה האופטימליים, אפשר להסביר איך Chromium בוחר מה להעביר. סטאק ההפעלה של Chromium מבוסס על ארכיטקטורה של 'משיכה', כלומר כל רכיב בסטאק מבקש את הקלט שלו מהרכיב שמתחתיו בסדר היררכי. בחלק העליון של הסטאק נמצא העיבוד של פריימים של אודיו ווידאו, מתחתיו נמצא פענוח, ואחריו פענוח מוזיקה (demuxing) ולבסוף קלט/פלט. כל פריים אודיו שעבר רינדור מפעיל שעון שמשמש לבחירת פריימים של וידאו לעיבוד, בשילוב עם פרק זמן להצגה.
בכל מרווח הצגה (כל רענון של המסך), ה-video renderer מתבקש לספק פריים של וידאו על ידי CompositorFrameSink שמצורף ל-SurfaceLayer שצוין קודם. בתוכן עם קצב פריימים נמוך מקצב התצוגה, אותו פריים יוצג יותר מפעם אחת. לעומת זאת, אם קצב הפריימים גבוה מקצב התצוגה, חלק מהפריימים לא יוצגו אף פעם.
יש הרבה יותר מאשר סנכרון של אודיו ווידאו באופן שמשמח את הצופים. במאמר Project Butter מוסבר בהרחבה איך מגיעים לווידאו חלק ב-Chromium. במאמר הזה מוסבר איך אפשר לפרק את העיבוד של סרטון לרצפים אידיאליים שמייצגים את מספר הפעמים שכל פריים צריך להופיע. לדוגמה: "פריים אחד בכל מרווח תצוגה ([1], 60 fps ב-60 Hz)", "פריים אחד בכל 2 מרווחי תצוגה ([2], 30 fps ב-60 Hz)", או דפוסים מורכבים יותר כמו [2:3:2:3:2] (25 fps ב-60 Hz) שכוללים מספר פריימים ומרווחי תצוגה נפרדים. ככל שהעיבוד של הווידאו יתקרב לדפוס האידיאלי הזה, כך סביר יותר שהמשתמש יתרשם מהפעלת הווידאו כחלקה.
רוב פלטפורמות Chromium מבצעות רינדור של פריימים בודדים, אבל לא כולן. הארכיטקטורה המתרחבת שלנו מאפשרת גם רינדור באצווה. עיבוד גרפי באצווה הוא טכניקה יעילה שבה ה-compositor ברמת מערכת ההפעלה מקבל מידע מראש על כמה פריים, ומטפל בשחרור שלהם לפי לוח זמנים שהאפליקציה מספקת.
העתיד הוא עכשיו?
התמקדנו בדרכים שבהן Chromium מנצל את הרכיבים הבסיסיים של מערכת ההפעלה כדי לספק את חוויית ההפעלה הטובה ביותר. אבל מה קורה באתרים שרוצים להציע יותר מאשר הפעלת סרטונים בסיסית? האם נוכל להציע להם את אותם רכיבים בסיסיים חזקים שבהם Chromium עצמו משתמש כדי להביא את הדור הבא של תוכן האינטרנט?
לדעתנו התשובה היא כן! יכולת ההרחבה היא העיקרון המרכזי שאנחנו חושבים עליו כשאנחנו מדברים על פלטפורמת האינטרנט בימינו. אנחנו עובדים עם מפתחים ודפדפנים אחרים כדי ליצור טכנולוגיות חדשות כמו WebGPU ו-WebCodecs, כדי שמפתחי אתרים יוכלו להשתמש באותם רכיבים בסיסיים ש-Chromium משתמש בהם כשמדברים עם מערכת ההפעלה. WebGPU מספק תמיכה במאגרי GPU, ו-WebCodecs מספק רכיבים בסיסיים לקידוד ולפענוח של פלטפורמות שתואמים למערכות שכבת-העל ומאגרי ה-GPU שצוינו למעלה.
סוף השידור
תודה על שקראת מידע זה! אני מקווה שהצלחתי להסביר לכם טוב יותר איך מערכות ההפעלה המודרניות פועלות, ואיך Chromium מאפשרת לצפות בכמה מאות מיליוני שעות מדי יום. אם אתם מחפשים מקורות מידע נוספים על קודיקים ועל סרטוני וידאו מודרניים באינטרנט, מומלץ לקרוא את המאמרים H.264 is magic מאת Sid Bala, How Modern Video Players Work מאת Erica Beaves ו-Packaging award-winning shows with award-winning technology מאת Cyril Concolato.
איור אחד (היפה!) של Una Kravets.