המרת קידוד תואמת של מדיה

ב-Android 12 ואילך (API ברמה 31 ואילך), המערכת יכולה להמיר באופן אוטומטי סרטונים שתועדו בפורמטים כמו HEVC‏ (H.265) ל-AVC‏ (H.264) כשהם נפתחים באפליקציה שלא תומכת ב-HEVC. התכונה הזו מאפשרת לאפליקציות לצלם סרטונים להשתמש בקידוד מודרני יותר וחסכוני יותר באחסון לסרטונים שצולמו במכשיר, בלי להקריב את התאימות לאפליקציות אחרות.

אפשר לבצע המרה אוטומטית של הפורמטים הבאים לתוכן שנוצר במכשיר:

פורמט מדיה מאפיין XML סוג ה-MIME של MediaFormat
HEVC‏ (H.265) מק"ט HEVC MediaFormat.MIMETYPE_VIDEO_HEVC
HDR10HDR10 MediaFeature.HdrType.HDR10
HDR10+‎ HDR10Plus MediaFeature.HdrType.HDR10_PLUS

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

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

המרת הקוד היא פעולה שמחייבת חישובים יקרים ומוסיפה עיכוב משמעותי בפתיחת קובץ וידאו. לדוגמה, קובץ וידאו של דקה אחת בפורמט HEVC עובר קובץ המרה ל-AVC בטלפון Pixel 3 תוך כ-20 שניות. לכן, כדאי לבצע המרה של קובץ וידאו רק כששולחים אותו מהמכשיר. לדוגמה, כשמשתפים קובץ וידאו עם משתמשים אחרים באותה אפליקציה, או עם שרת בענן שלא תומך בפורמטים מודרניים של וידאו.

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

הגדרת המרת קידוד

האפליקציות יכולות לשלוט בהתנהגות הקידוד שלהן על ידי הצהרה על יכולות המדיה שלהן. יש שתי דרכים להצהיר על היכולות האלה: בקוד או במשאב.

הצהרה על יכולות בקוד

כדי להצהיר על יכולות מדיה בקוד, יוצרים מופע של אובייקט ApplicationMediaCapabilities באמצעות בונה:

Kotlin

val mediaCapabilities = ApplicationMediaCapabilities.Builder()
    .addSupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC)
    .addUnsupportedHdrType(MediaFeature.HdrType.HDR10)
    .addUnsupportedHdrType(MediaFeature.HdrType.HDR10_PLUS)
    .build()

Java

ApplicationMediaCapabilities mediaCapabilities = new ApplicationMediaCapabilities.Builder()
        .addSupportedVideoMimeType(MediaFormat.MIMETYPE_VIDEO_HEVC)
        .addUnsupportedHdrType(MediaFeature.HdrType.HDR10)
        .addUnsupportedHdrType(MediaFeature.HdrType.HDR10_PLUS)
        .build();

משתמשים באובייקט הזה כשניגשים לתוכן מדיה באמצעות שיטות כמו ContentResolver#openTypedAssetFileDescriptor():

Kotlin

val providerOptions = Bundle().apply {
    putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, mediaCapabilities)
}
contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)
    .use { fileDescriptor ->
        // Content will be transcoded based on values defined in the
        // ApplicationMediaCapabilities provided.
    }

Java

Bundle providerOptions = new Bundle();
providerOptions.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES, mediaCapabilities);
try (AssetFileDescriptor fileDescriptor =  contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)) {
    // Content will be transcoded based on values defined in the
    // ApplicationMediaCapabilities provided.
}

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

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

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

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

כדי להשתמש בשיטה הזו, יוצרים קובץ משאב media_capabilities.xml:

<?xml version="1.0" encoding="utf-8"?>
<media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
    <format android:name="HEVC" supported="true"/>
    <format android:name="HDR10" supported="false"/>
    <format android:name="HDR10Plus" supported="false"/>
</media-capabilities>

בדוגמה הזו, סרטוני HDR שצולמו במכשיר עוברים תהליך המרה חלק לווידאו AVC SDR (טווח דינמי סטנדרטי), אבל סרטוני HEVC לא עוברים תהליך כזה.

משתמשים בתג property בתוך התג application כדי להוסיף הפניה לקובץ של יכולות המדיה. מוסיפים את המאפיינים הבאים לקובץ AndroidManifest.xml:

<property
    android:name="android.media.PROPERTY_MEDIA_CAPABILITIES"
    android:resource="@xml/media_capabilities" />

שימוש ביכולות המדיה של אפליקציה אחרת כדי לפתוח קובץ וידאו

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

כדי לטפל במקרה כזה, פותחים קובץ וידאו באמצעות openTypedAssetFileDescriptor ומציינים את ה-UID של האפליקציה המקבלת. אפשר לקבל את ה-UID באמצעות Binder.getCallingUid. לאחר מכן, הפלטפורמה משתמשת ביכולות המדיה של האפליקציה המקבלת כדי לקבוע אם צריך להמיר את הקידוד של קובץ הסרטון.

Kotlin

val providerOptions = Bundle().apply {
    putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, Binder.getCallingUid())
}
contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)
    .use { fileDescriptor ->
        // Content will be transcoded based on the media capabilities of the
        // calling app.
    }

Java

Bundle providerOptions = new Bundle();
providerOptions.putParcelable(MediaStore.EXTRA_MEDIA_CAPABILITIES_UID, Binder.getCallingUid());
try (AssetFileDescriptor fileDescriptor =  contentResolver.openTypedAssetFileDescriptor(mediaUri, mediaMimeType, providerOptions)) {
    // Content will be transcoded based on the media capabilities of the
    // calling app.
}

תרחישים לדוגמה

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

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

דוגמה 2. המרת הקידוד מתחילה על ידי אפליקציית שיתוף הסרטונים. דוגמה 2 אפליקציית צילום הווידאו משתפת את הסרטון עם האפליקציה לשיתוף הסרטונים באמצעות URI של MediaStore. אפליקציית שיתוף הסרטונים פותחת את קובץ הווידאו באמצעות openTypedAssetFileDescriptor, ומציינת שהיא לא תומכת ב-HEVC ביכולות המדיה שלה. הפעולה הזו מפעילה את תהליך ההמרה, ולאחר שהוא מסתיים הקובץ מועלה לשרת בענן.

פורמטים לא מוצהרים

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

אפשרויות למפתחים

אפשר להשתמש באפשרויות הבאות למפתחים כדי לשנות את התנהגות ברירת המחדל של המרת הקידוד ב-Android:

  • ביטול ברירות המחדל של המרת קידוד ההגדרה הזו קובעת אם הפלטפורמה שולטת בהמרת הקידוד האוטומטית. כשהאפשרות הזו מופעלת, המערכת מתעלמת מברירת המחדל של הפלטפורמה וההגדרה enable transcoding קובעת אם תתבצע המרת קידוד אוטומטית. האפשרות הזו מושבתת כברירת מחדל.

  • Enable transcoding (הפעלת המרת קידוד): ההגדרה הזו קובעת אם תבצע המרת קידוד אוטומטית של פורמטים לא מוצהרים. היא מופעלת כברירת מחדל, אבל יש לה השפעה רק אם מופעלת גם האפשרות ביטול ברירות המחדל של המרת הקידוד.

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

  • הצגת התראות לגבי המרת קידוד כשהאפשרות הזו מופעלת, האפליקציה מציגה התראה על התקדמות ההמרה כשהיא מופעלת על ידי קריאת קובץ מדיה שאינו נתמך. האפשרות הזו מופעלת כברירת מחדל.

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