דחיסת וידיאו וקידוד תמונה – מה, כמה ולמה?

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

7:00
  /  
14.02.2007
  
המאמר נכתב ע"י GoodGuys נערך ע"י דרור אנגל

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

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

דחיסת קומפוננטים

אחד השלבים הראשונים בתהליך הוא העברת התמונה מ-RGB לפורמט YUV שהוא נוח יותר לעבודה עבור הקודק. הסיבה שהוא נוח קשורה בטרנספורמציות המתימטיות שעושות את הדחיסה ואני לא אתייחס אליהן כאן מעבר למה הן בעצם עושות (למטה).
פורמט YUV הוא פורמט שבו הרכיב Y מסמל את עוצמת האור מהפיקסל, והרכיבים U ו-V מסמלים את הצבע. בניגוד ל-RGB שבו עוצמת האור נגזרת מסכום העוצמות בכל רכיב.
לאחר המעבר ל-YUV, לוקחים את מפת הצבעים ברכיב U וברכיב V ומקטינים אותן פי-2 בכל ציר. כלומר שכעת לכל רביעיית פיקסלים בתמונה (2×2) יש את אותו צבע.
פה יכול לבוא הבדל בין קודקים – איך עושים את ההקטנה פי-2? בד"כ עושים ממוצע של 4 פיקסלים של U לפיקסל חדש, וכנ"ל ל-V. אבל יש שיטות SCALING אחרות.
השאלה המציקה ביותר היא כמובן איך זה יכול להיות טוב שמאבדים כל כך הרבה מידע?
התשובה פשוטה – כושר ההפרדה של העין האנושית לצבעים הוא בערך רבע מכושר ההפרדה לעוצמת אור. אנחנו פשוט לא ממש מבחינים באובדן הזה.
והנה, אם הייתה לנו תמונה 720×576, בפורמט RGB היא לוקחת 720x576x3 בתים.
אחרי מעבר ל-YUV והקטנת U ו-V, מקבלים:
720x576x1 + 360x288x2
וזה לבד הורדת גודל של 50%! בלי לאבד איכות נראית לעין.

סוגי תמונות

בקובץ MPEG יש שלושה סוגים של תמונות.

– תמונת מפתח – I-Frame
– תמונה שתלויה בתמונה קודמת – P-Frame
– תמונה שתלויה בתמונה קודמת וגם בתמונה הבאה – B-Frame.
אני יודע שזה נראה מבלבל, אבל זה יהיה ברור. מבטיח.

תמונות מסוג I-Frame, הן למעשה תמונות ששמורות בקובץ בשיטה מאוד דומה לדחיסת JPEG.
משתמשים בטרנספורמציה מתימטית מסוג DCT.
בעזרת הטרנספורמציה הזו, מסתכלים על התמונה כעל אוסף של מקדמים של נוסחא מורכבת, והטרנספורמציה עצמה מגדילה את המקדמים החשובים ומקטינה את המקדמים הפחות חשובים.
לאחר השימוש, מחלקים את כל המקדמים במספר כלשהו, והמקדמים שגודלם ירד מתחת לאפס (זכרו שמדובר בחלוקה שאיננה בשלמים אלא ב-Floating Point) פשוט נזרקים.
זה המקום שבו JPEG וגם MPEG מאבדים חלק מהמידע.
תמונות P ו-B מצריכות הסברים נוספים:

מקרו בלוקים

כעת ננסה להרוויח ע"י מציאת ההבדלים מהתמונה הקודמת. בכדי לעשות את זה נחלק את התמונה לריבועים קטנים יותר.
ב-MPEG1 ו-MPEG2 הריבועים הם בגודל של 32×32 פיקסלים ב-Y ו-16×16 פיקסלים ב-U/V.
ב-MPEG4 הריבועים יכולים להיות בגדלים שונים (הסבר מעמיק יותר על MPEG4 ועל AVC H264 למטה).
עבור כל ריבוע בתמונה הקודמת, נחפש אם הוא במקרה זז פיקסל אחד הצידה לכל כיוון.
לאחר מכן אפשר להמשיך ולחפש, ואם נמצא – אז לא נשמור את הריבוע, אלא רק נרשום בקובץ איזה ריבוע זז בתמונה החדשה, ולאן.
החיפוש הזה נקרא Motion Estimation.
המידע שאומר לאן זז הריבוע נקרא Motion Vector.
ככל שנחפש יותר רחוק יש לנו יותר סיכוי למצוא את הריבוע, ולהרוויח יותר דחיסה. אבל החיפוש הזה לוקח הרבה מאוד משאבי עיבוד וזיכרון.
לאחר שמצאנו את כל הריבועים שזזו (כמובן – רק את אלה שהצלחנו למצוא), נשארו תאי שטח שלא הצלחנו למצוא להם בלוקים מהתמונה הקודמת. את הריבועים האלה מקודדים שוב בשיטה כמו JPEG.

תמונות

תמונה מסוג P מכילה כמו שאמרנו למעלה – בלוקים שזזו מהתמונה הקודמת, ובלוקים שמקודדים כמו JPEG.
תמונה מסוג B מצריכה הסבר. נניח שבשידור המקורי שודרו 6 תמונות:
F1 F2 F3 F4 F5 F6
תמונה F1 תקודד כתמונה מסוג I. קידוד מלא כמו JPEG.
לאחר מכן, נקודד את תמונה F3 כתמונה מסוג P, שתלויה ב-F1.
עכשיו נקודד את תמונה F2 ונרשה לעצמנו לחפש בלוקים שזזו גם ב-F1 וגם ב-F3.
והתהליך יכול לחזור על עצמו. F4 יכולה להיות I, או P שתלויה ב-F2 או B שתלויה ב-F2 וגם ב-F3. וכו'.
כמובן שבשביל שהמפענח יצליח להציג את זה כמו שצריך, חייבים לשמור בקובץ לפי הסדר:
F1 F3 F2 …
המפענח חייב לדעת את זה מראש, ולפני שהוא מציג את F3, הוא חייב לקרוא, לפענח ולהציג את F2. זה דורש עוד זיכרון במפענח, ויכולת עיבוד.

תהליך DEBLOCKING

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

סוף התהליך

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

הבדלים בין השיטות השונות

ישנם הרבה הבדלים קטנים, וכמה הבדלים משמעותיים יותר. אני אנסה לעבור על החשובים:
– מרחק חיפוש Motion Estimation. ב-MPEG1 וב-MPEG2 מרחק החיפוש הוא 32 פיקסלים, אם אני לא טועה. ב-MPEG4 זה עומד על 128, וב-H264 זה אפילו יותר מכיוון שהם נועדו לתת מענה גם ל-HD.
– גודל המקרו-בלוקים. ב-MPEG1 ו-MPEG2 מדובר ב-32×32. ב-MPEG4 אפשר לבחור 16×16 או 32×32, לכל מקרו-בלוק. ב-H264, אפשר לחלק כל בלוק של 32×32 לכמעט כל אפשרות של גושים קטנים יותר, כמו למשל 32×16 ועוד שני גושים של 16×16. אפשר לרדת עד לגודל של 4×4. זה מצריך כוח עיבוד אדיר, ולוקח המון זמן לחפש את החלוקה שתיתן דחיסה אופטימלית.
– אבחנה ברבעי-פיקסל. MPEG2 הכניס את האופציה הזו. דמיינו שאתם מצלמים עצם שזז לאט. אם הוא זז מספיק לאט, הרי שהוא יכול לזוז פחות מיכולת ההפרדה של המצלמה. נניח שהעצם זז בדיוק חצי המרחק שדרוש להפרדה. במקרה זה תתקבל תמונה שבה כל פיקסל הוא בקירוב טוב הממוצע של שני פיקסלים מהתמונה הקודמת. ניתן לזהות את המצב הזה, ולהרוויח דחיסה. למעשה, ניתן לזהות ככה גם תזוזה קטנה יותר, ו-MPEG2 ואחריו יכולים לזהות רבע-פיקסל. זה מופיע לרוב בשם QPEL.
– ריבוי Motion Vectors – ב-MPEG1 ו-MPEG2 כל ריבוע יכול לזוז רק למקום אחד בתמונה החדשה. כלומר שיש לכל ריבוע רק ווקטור אחד. MPEG4 ו-H264 מאפשרים 4 ווקטורים ויותר.

אבל מה מייחד את H264 מעל כל השאר? שני דברים.
האחד איננו טריוויאלי, והשני ברור מאוד.
קודק H264 מנסה להרוויח איכות ע"י שינוי בצורת הקידוד. רוב הקודקים מבצעים את הפעולות שראינו למעלה. המקודד לוקח תמונה אחר תמונה ודוחס אותן אחרי השוואה וכו'.
המפענח מפענח תמונה, מבצע DEBLOCKING, ומפענח את התמונה הבאה לפי התמונה הנוכחית. אולם שימו לב שהמקודד מקודד כל תמונה חדשה לפי התמונה הקודמת המקורית, ואילו המפענח מקבל תמונה שנדחסה ופוענחה והיא לא בדיוק זהה.

המקודד בקודק H264 עושה זאת כך: מתחיל בתמונה מסוג I. מקודד, ושם בקובץ. כעת, הוא מפענח את התמונה, כדי לקבל בדיוק את מה שהמפענח יראה. כעת הוא מבצע DEBLOCKING כמו שהמפענח יעשה, ורק עכשיו משתמש בתמונה הזו כבסיס לתמונות P ו-B הבאות.
וכנ"ל לגבי כל תמונה אחרי שקודדה. דבר זה לבדו יוצר הבדל איכות מרשים ביותר מכיוון שהוא מקטין בכל פעם את השגיאה המצטברת שבין המקודד למפענח.
אבל הדבר המרשים ביותר הוא העובדה שבזמן ש-MPEG4
פורמט MPEG1 ידע לחפש מקרו-בלוקים רק מהתמונה הקודמת, ו-MPEG2 ו-MPEG4 ידעו להסתמך על 2 תמונות, אז H264 מרשה לעצמו להסתמך על עד 15 תמונות!!!
זה לא חובה, אבל אם יש לנו מקודד עם המון זיכרון ויחידת עיבוד מדהימה, אפשר להרוויח ככה המון דחיסה.

דוגמה לגודלי קבצים (ממש בערך):
שעה של וידאו ב-MPEG1 בערך 1 גיגה-בייט והאיכות לא מדהימה.
שעה של וידאו ב-MPEG2 בערך 2 גיגה-בייט באיכות מצויינת.
שעה של וידאו ב-MPEG4 בערך 1 גיגה-בייט באיכות מצויינת.
שעה של וידאו ב-H264 בערך 250 מגה באיכות פנטסטית.
והכל כמובן תלוי באיכות הקידוד.


7:00
  /  
14.2.2007
  
המאמר נכתב ע"י GoodGuys נערך ע"י דרור אנגל

1