מנהור מולטימדיה

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

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

  • להפעלת שידור חי ב-Android מגרסה 11 ואילך, נדרש שעון ייחוס של תוכנית (PCR) או שעון זמן מערכת (STC) שמופעל על ידי מקלט

רקע

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

הפעלת סרטונים בטכנולוגיית טאנלינג עוקפת את קוד האפליקציה ומצמצמת את מספר התהליכים שפועלים על הסרטון, ולכן יכולה לספק עיבוד יעיל יותר של סרטונים, בהתאם להטמעה של יצרן ציוד מקורי (OEM). בנוסף, הוא יכול לספק קצב פריימים וסנכרון מדויקים יותר של הווידאו לשעון שנבחר (PRC,‏ STC או אודיו) על ידי הימנעות מבעיות תזמון שנובעות מהטיה פוטנציאלית בין התזמון של בקשות Android לעיבוד הווידאו לבין התזמון של סנכרון אנכי אמיתי של החומרה. עם זאת, טכנולוגיית המנהור יכולה גם להפחית את התמיכה באפקטים של GPU, כמו טשטוש או פינות מעוגלות בחלונות של תמונה בתוך תמונה (PiP), כי המאגרים עוקפים את מחסנית הגרפיקה של Android.

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

השוואה בין מצב מסורתי למצב מנהור

איור 1. השוואה בין תהליכי הפעלת סרטונים ללא מנהור ולבין תהליכי הפעלת סרטונים עם מנהור.

למפתחי אפליקציות

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

כדי להפעיל סרטונים על פי דרישה ב-Android מגרסה 5 ואילך:

  1. יוצרים מכונת SurfaceView.

  2. יוצרים מכונת audioSessionId.

  3. יוצרים מכונות AudioTrack ו-MediaCodec עם המכונה audioSessionId שנוצרה בשלב 2.

  4. מעבירים נתוני אודיו לתור של AudioTrack עם חותמת הזמן של המצגת עבור מסגרת האודיו הראשונה בנתוני האודיו.

כדי להפעיל שידור חי ב-Android מגרסה 11 ואילך:

  1. יוצרים מכונת SurfaceView.

  2. קבלת מופע של avSyncHwId מ-Tuner.

  3. יוצרים מכונות AudioTrack ו-MediaCodec עם מכונת avSyncHwId שנוצרה בשלב 2.

קטעי הקוד הבאים מציגים את תהליך הקריאה ל-API:

aab.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE);

// configure for audio clock sync
aab.setFlag(AudioAttributes.FLAG_HW_AV_SYNC);
// or, for tuner clock sync (Android 11 or higher)
new tunerConfig = TunerConfiguration(0, avSyncId);
aab.setTunerConfiguration(tunerConfig);
if (codecName == null) {
  return FAILURE;
}

// configure for audio clock sync
mf.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
// or, for tuner clock sync (Android 11 or higher)
mf.setInteger(MediaFormat.KEY_HARDWARE_AV_SYNC_ID, avSyncId);

התנהגות של הפעלת וידאו על פי דרישה

הפעלת וידאו לפי דרישה במנהור קשורה באופן מרומז להפעלת AudioTrack, ולכן התנהגות ההפעלה של וידאו במנהור עשויה להיות תלויה בהתנהגות ההפעלה של אודיו.

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

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

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

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

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

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

רצף הפעולות של דילוג מדויק

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

כדי לבצע חיפוש מדויק, פועלים לפי סדר הביצוע שמוצג באיור 2:

תהליך של רצף חיפוש

איור 2. רצף הפעולות לדילוג מדויק.

פרטים עיקריים:

  • ביצוע מקביל: אפשר להריץ שלבים בתוך תיבת par אחת במקביל. לדוגמה, שיחות וידאו ב-MediaCodec הן נפרדות מ-AudioTrack.

  • תלויות עוקבות: כל הפעולות בתיבה par הראשונה צריכות להתבצע לפני שמתקדמים לתיבה par השנייה. באופן ספציפי, האפליקציה צריכה לוודא ש-AudioTrack.write ומאגרי נתונים זמניים בסרטון MediaCodec מתווספים לתור לפני הקריאה ל-AudioTrack.play.

רצף הפעולה של הפעלת סרטון במהירות משתנה

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

כדי להגדיר את המהירות, פועלים לפי סדר ההפעלה שמוצג באיור 3:

תהליך רצף מהיר

איור 3. רצף הפעולות להגדרת המהירות.

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

  • AudioTrack.getTimestamp מחזירה את הערך framePosition על סמך התדירות המקורית של קלט האודיו. לדוגמה, אם קצב הדגימה של הקלט הוא 44,100 Hz ומהירות ההפעלה היא 2.0x, אחרי הפעלה של 2 שניות, הפונקציה AudioTrack.getTimestamp מחזירה את הערך framePosition של 176,400.

  • אם האפליקציה קוראת ל-setSpeed(1.5) והפעולה הזו מצליחה, ואז האפליקציה קוראת ל-setSpeed(30) והפעולה הזו נכשלת, ההפעלה נשארת במהירות של פי 1.5.

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

  • גובה הצליל של האודיו נשמר כשמשנים את המהירות.

  • מהירות ההפעלה לא מושפעת מפעולות הפעלה אחרות.

    • דוגמה 1: אם מהירות ההפעלה היא 1.5x והסרטון AudioTrack מושהה, המהירות נשארת 1.5x אחרי שממשיכים את ההפעלה של AudioTrack.

    • דוגמה 2: אם מהירות ההפעלה היא x1.5 והמשתמש עובר ל-PTS אחר, לפי איור 2, ההפעלה נשארת במהירות x1.5.

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

    • לדוגמה: אם קצב הפריימים המקורי של התוכן הוא 60 fps, ומהירות ההפעלה היא x2, צריך להגדיר את KEY_OPERATING_RATE ל-120.
  • הגדרת מהירות שוב ושוב עם מהירויות שונות שנתמכות לא אמורה להפעיל שגיאות, והתנהגות ההפעלה אחרי הקריאה האחרונה צריכה להיות זהה להתנהגות ההפעלה אם המהירות מוגדרת רק פעם אחת, למהירות האחרונה שהוגדרה.

ליצרני מכשירים

הגדרות אישיות

יצרני ציוד מקורי (OEM) צריכים ליצור מפענח וידאו נפרד כדי לתמוך בהפעלת וידאו במנהור. המפענח הזה צריך לפרסם שהוא מסוגל להפעיל תוכן בשיטת טאנלינג בקובץ media_codecs.xml:

<Feature name="tunneled-playback" required="true"/>

כשמוגדר מופע MediaCodec עם מנהור עם מזהה של סשן אודיו, הוא שולח שאילתה אל AudioFlinger לגבי מזהה HW_AV_SYNC הזה:

if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
    int sessionId = 0;
    try {
        sessionId = (Integer)entry.getValue();
    }
    catch (Exception e) {
        throw new IllegalArgumentException("Wrong Session ID Parameter!");
    }
    keys[i] = "audio-hw-sync";
    values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
}

במהלך השאילתה הזו,‏ AudioFlinger מאחזר את מזהה HW_AV_SYNC ממכשיר האודיו הראשי ומשייך אותו באופן פנימי למזהה של סשן האודיו:

audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC);
AudioParameter param = AudioParameter(String8(reply));
int hwAVSyncId;
param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), hwAVSyncId);

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

mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);

המזהה HW_AV_SYNC, בין אם הוא תואם לסטרימינג של פלט אודיו או להגדרה של Tuner, מועבר לרכיב OMX או Codec2 כדי שקוד ה-OEM יוכל לשייך את הקודק לסטרימינג המתאים של פלט האודיו או לסטרימינג של הטיונר.

במהלך הגדרת הרכיב, רכיב ה-OMX או Codec2 צריך להחזיר ידית פס צד שאפשר להשתמש בה כדי לשייך את הקודק לשכבת Hardware Composer‏ (HWC). כשהאפליקציה משייכת משטח ל-MediaCodec, ה-handle של פס הצד הזה מועבר ל-HWC דרך MediaCodec, שמגדיר את השכבה כשכבת פס צד.SurfaceFlinger

err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle);
if (err != OK) {
  ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).", sidebandHandle, err);
  return err;
}

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

OMX

רכיב של מפענח מנהור צריך לתמוך בפעולות הבאות:

  • הגדרת הפרמטר המורחב OMX.google.android.index.configureVideoTunnelMode, שמשתמש במבנה ConfigureVideoTunnelModeParams כדי להעביר את המזהה HW_AV_SYNC שמשויך למכשיר פלט האודיו.

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

  • שליחת האירוע OMX_EventOnFirstTunnelFrameReady כשמסגרת הווידאו הראשונה שמועברת במנהור מפוענחת ומוכנה להצגה.

ההטמעה של AOSP מגדירה את מצב המנהור ב-ACodec דרך OMXNodeInstance, כמו שמוצג בקטע הקוד הבא:

OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
        "OMX.google.android.index.configureVideoTunnelMode");

OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);

ConfigureVideoTunnelModeParams tunnelParams;
InitOMXParams(&tunnelParams);
tunnelParams.nPortIndex = portIndex;
tunnelParams.bTunneled = tunneled;
tunnelParams.nAudioHwSync = audioHwSync;
err = OMX_SetParameter(mHandle, index, &tunnelParams);
err = OMX_GetParameter(mHandle, index, &tunnelParams);
sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;

אם הרכיב תומך בהגדרה הזו, הוא צריך להקצות לרכיב הקודק הזה נקודת אחיזה של ערוץ צדדי ולהעביר אותה חזרה דרך חבר pSidebandWindow כדי שמערכת HWC תוכל לזהות את רכיב הקודק המשויך. אם הרכיב לא תומך בהגדרה הזו, הוא צריך להגדיר את bTunneled ל-OMX_FALSE.

Codec2

ב-Android מגרסה 11 ואילך, ‏ Codec2 תומך בהפעלה במנהור. רכיב הפענוח צריך לתמוך בפעולות הבאות:

  • הגדרת C2PortTunneledModeTuning, שכוללת הגדרה של מצב מנהור והעברה של HW_AV_SYNC שאוחזר ממכשיר פלט האודיו או מהגדרת הטיונר.

  • מתבצעת שאילתה לגבי C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE כדי להקצות ולאחזר את נקודת האחיזה של פס הצד עבור HWC.

  • טיפול ב-C2_PARAMKEY_TUNNEL_HOLD_RENDER כשהוא מצורף ל-C2Work, שמורה לקודק לפענח ולסמן את סיום העבודה, אבל לא לעבד את מאגר הפלט עד ש-1) הקודק יקבל הוראה לעבד אותו מאוחר יותר או 2) הפעלת האודיו תתחיל.

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

  • לא להגדיר את debug.stagefright.ccodec_delayed_params (מומלץ). אם מגדירים אותה, צריך להגדיר את הערך false.

ההטמעה ב-AOSP מגדירה את מצב המנהור ב-CCodec דרך C2PortTunnelModeTuning, כמו שמוצג בקטע הקוד הבא:

if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
} else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
} else {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
    tunneledPlayback->setFlexCount(0);
}
c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK,
        failures);
std::vector<std::unique_ptr<C2Param>> params;
c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE},
        C2_DONT_BLOCK, &params);
if (c2err == C2_OK && params.size() == 1u) {
    C2PortTunnelHandleTuning::output *videoTunnelSideband =
            C2PortTunnelHandleTuning::output::From(params[0].get());
    return OK;
}

אם הרכיב תומך בהגדרה הזו, הוא צריך להקצות לרכיב הקודק הזה נקודת אחיזה של ערוץ צדדי ולהעביר אותה בחזרה דרך C2PortTunnelHandlingTuning כדי שרכיב ה-HWC יוכל לזהות את רכיב הקודק המשויך.

HAL של אודיו

להפעלת וידאו על פי דרישה, ה-Audio HAL מקבל את חותמות הזמן של הצגת האודיו בשורה עם נתוני האודיו בפורמט big-endian בתוך כותרת שנמצאת בתחילת כל בלוק של נתוני אודיו שהאפליקציה כותבת:

struct TunnelModeSyncHeader {
  // The 32-bit data to identify the sync header (0x55550002)
  int32 syncWord;
  // The size of the audio data following the sync header before the next sync
  // header might be found.
  int32 sizeInBytes;
  // The presentation timestamp of the first audio sample following the sync
  // header.
  int64 presentationTimestamp;
  // The number of bytes to skip after the beginning of the sync header to find the
  // first audio sample (20 bytes for compressed audio, or larger for PCM, aligned
  // to the channel count and sample size).
  int32 offset;
}

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

השהיית התמיכה

ב-Android 5 ומטה אין תמיכה בהשהיה. אפשר להשהות הפעלה של מנהור רק על ידי הרעבת A/V, אבל אם המאגר הפנימי של הווידאו גדול (לדוגמה, יש שנייה אחת של נתונים ברכיב OMX), ההשהיה נראית לא מגיבה.

ב-Android מגרסה 5.1 ואילך, AudioFlinger תומך בהשהיה ובהמשך הפעלה של פלט אודיו ישיר (מנהור). אם שכבת ה-HAL מטמיעה השהיה והפעלה מחדש, השהיה והפעלה מחדש של הרצועה מועברות לשכבת ה-HAL.

רצף הקריאות pause, flush, resume מבוצע על ידי הפעלת קריאות HAL בשרשור ההפעלה (בדומה להעברה).

הצעות להטמעה

HAL של אודיו

ב-Android 11, אפשר להשתמש במזהה הסנכרון של החומרה מ-PCR או מ-STC לסנכרון אודיו/וידאו, כך שנתמך סטרימינג של וידאו בלבד.

ב-Android מגרסה 10 ומטה, למכשירים שתומכים בהפעלת סרטונים בשיטת tunneled צריכים להיות לפחות פרופיל אחד של זרם פלט אודיו עם הדגלים FLAG_HW_AV_SYNC ו-AUDIO_OUTPUT_FLAG_DIRECT בקובץ audio_policy.conf. הדגלים האלה משמשים להגדרת שעון המערכת משעון האודיו.

OMX

ליצרני מכשירים צריך להיות רכיב OMX נפרד להפעלת סרטונים בשיטת ה-tunneling (יצרנים יכולים להשתמש ברכיבי OMX נוספים להפעלת סוגים אחרים של אודיו ווידאו, כמו הפעלה מאובטחת). הרכיב המנהור צריך:

  • מציינים 0 מאגרי נתונים זמניים (nBufferCountMin, nBufferCountActual) ביציאה שלו.

  • מטמיעים את התוסף OMX.google.android.index.prepareForAdaptivePlayback setParameter.

  • מציינים את היכולות שלו בקובץ media_codecs.xml ומצהירים על התכונה 'הפעלה במנהור'. כדאי גם להבהיר אם יש הגבלות על גודל המסגרת, על היישור או על קצב העברת הנתונים. דוגמה:

    <MediaCodec name="OMX.OEM_NAME.VIDEO.DECODER.AVC.tunneled"
    type="video/avc" >
        <Feature name="adaptive-playback" />
        <Feature name="tunneled-playback" required=true />
        <Limit name="size" min="32x32" max="3840x2160" />
        <Limit name="alignment" value="2x2" />
        <Limit name="bitrate" range="1-20000000" />
            ...
    </MediaCodec>
    

אם אותו רכיב OMX משמש לתמיכה בפענוח עם מנהור ובפענוח ללא מנהור, הוא צריך להשאיר את תכונת ההפעלה עם מנהור כלא נדרשת. לכן, גם למפענחים עם מנהור וגם למפענחים בלי מנהור יש את אותן מגבלות יכולת. דוגמה:

<MediaCodec name="OMX._OEM\_NAME_.VIDEO.DECODER.AVC" type="video/avc" >
    <Feature name="adaptive-playback" />
    <Feature name="tunneled-playback" />
    <Limit name="size" min="32x32" max="3840x2160" />
    <Limit name="alignment" value="2x2" />
    <Limit name="bitrate" range="1-20000000" />
        ...
</MediaCodec>

Hardware Composer (HWC)

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

ה-HWC מסנכרן פריימים מפוענחים של וידאו (מרכיב ה-OMX המנהר) עם טראק האודיו המשויך (עם המזהה audio-hw-sync). כשפריים חדש של סרטון הופך להיות הנוכחי, ה-HWC משלב אותו עם התוכן הנוכחי של כל השכבות שהתקבלו במהלך ההכנה או השיחה האחרונה להגדרת המיקום, ומציג את התמונה שמתקבלת. הקריאות להכנה או להגדרה מתבצעות רק כששכבות אחרות משתנות, או כשמאפיינים של שכבת פס הצד (כמו מיקום או גודל) משתנים.

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

שילוב פריימים של סרטונים על ידי HWC על סמך אודיו

איור 4. מסנכרן חומרה (או ליבה או דרייבר) של HWC.