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

ב-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 של האפליקציה המקבלת, שניתן לקבל באמצעות 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 אפליקציית הצילום משתפת סרטון עם אפליקציית שיתוף הסרטונים באמצעות MediaStore URI. אפליקציית שיתוף הסרטונים פותחת את קובץ הווידאו באמצעות openTypedAssetFileDescriptor, ומציינת שהיא לא תומכת ב-HEVC ביכולות המדיה שלה. הפעולה הזו מפעילה את תהליך ההמרה, ולאחר שהוא מסתיים הקובץ מועלה לשרת בענן.

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

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

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

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

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

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

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

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

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