อุโมงค์มัลติมีเดีย

ช่องทางมัลติมีเดียช่วยให้ข้อมูลวิดีโอที่ถูกบีบอัดสามารถส่งสัญญาณผ่านตัวถอดรหัสวิดีโอฮาร์ดแวร์ไปยังจอแสดงผลได้โดยตรง โดยไม่ต้องประมวลผลด้วยโค้ดของแอปหรือโค้ดเฟรมเวิร์กของ Android โค้ดเฉพาะอุปกรณ์ด้านล่างกลุ่ม Android จะกำหนดเฟรมวิดีโอที่จะส่งไปยังจอแสดงผลและเวลาที่จะส่งโดยการเปรียบเทียบการประทับเวลาการนำเสนอเฟรมวิดีโอกับนาฬิกาภายในประเภทใดประเภทหนึ่งต่อไปนี้:

  • สำหรับการเล่นวิดีโอตามความต้องการใน Android 5 หรือสูงกว่า นาฬิกา AudioTrack จะซิงโครไนซ์กับการประทับเวลาการนำเสนอเสียง ที่ส่ง ผ่านโดยแอป

  • สำหรับการเล่นการถ่ายทอดสดใน Android 11 หรือสูงกว่า นาฬิกาอ้างอิงโปรแกรม (PCR) หรือนาฬิกาเวลาของระบบ (STC) ที่ขับเคลื่อนโดย จูนเนอร์

พื้นหลัง

การเล่นวิดีโอแบบเดิมบน Android จะแจ้งเตือน แอปเมื่อมีการถอดรหัสเฟรมวิดีโอที่บีบอัดแล้ว จากนั้นแอพ จะปล่อย เฟรมวิดีโอที่ถอดรหัสแล้วไปยังจอแสดงผลเพื่อเรนเดอร์ในเวลานาฬิกาของระบบเดียวกันกับเฟรมเสียงที่เกี่ยวข้อง โดยดึง ข้อมูลอินสแตนซ์ AudioTimestamps ในอดีตเพื่อคำนวณเวลาที่ถูกต้อง

เนื่องจากการเล่นวิดีโอแบบอุโมงค์ข้ามโค้ดของแอปและลดจำนวนกระบวนการที่กระทำกับวิดีโอ จึงสามารถให้การแสดงผลวิดีโอที่มีประสิทธิภาพมากขึ้น โดยขึ้นอยู่กับการใช้งาน OEM นอกจากนี้ยังสามารถให้จังหวะและการซิงโครไนซ์วิดีโอที่แม่นยำยิ่งขึ้นกับนาฬิกาที่เลือก (PRC, STC หรือเสียง) โดยการหลีกเลี่ยงปัญหาด้านเวลาที่เกิดจากความเบี่ยงเบนที่อาจเกิดขึ้นระหว่างกำหนดเวลาของคำขอ Android ในการแสดงผลวิดีโอ และกำหนดเวลาของ vsync ของฮาร์ดแวร์ที่แท้จริง อย่างไรก็ตาม การทำทันเนลยังสามารถลดการรองรับเอฟเฟ็กต์ 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-frames ) หมายความว่าเฟรมวิดีโอแรกที่แสดงควรเป็น I-frame เสมอ

    • หากคุณไม่ต้องการให้เฟรมวิดีโอที่อยู่ในคิวแรกถูกเรนเดอร์จนกว่าการเล่นเสียงจะเริ่มขึ้น ให้ตั้งค่าพารามิเตอร์นี้เป็น 0

    • หากไม่ได้ตั้งค่าพารามิเตอร์นี้ OEM จะกำหนดลักษณะการทำงานสำหรับอุปกรณ์

  • เมื่อไม่ได้ให้ข้อมูลเสียงแก่ AudioTrack และบัฟเฟอร์ว่างเปล่า (เสียงไม่เพียงพอ) การเล่นวิดีโอจะหยุดลงจนกว่าจะมีการเขียนข้อมูลเสียงมากขึ้น เนื่องจากนาฬิกาเสียงไม่ก้าวหน้าอีกต่อไป

  • ในระหว่างการเล่น ความไม่ต่อเนื่องที่แอพไม่สามารถแก้ไขได้อาจปรากฏในการประทับเวลาการนำเสนอด้วยเสียง เมื่อสิ่งนี้เกิดขึ้น OEM จะแก้ไขช่องว่างเชิงลบโดยการหยุดเฟรมวิดีโอปัจจุบัน และช่องว่างเชิงบวกโดยการลดเฟรมวิดีโอหรือแทรกเฟรมเสียงเงียบ (ขึ้นอยู่กับการใช้งาน OEM) ตำแหน่งเฟรม AudioTimestamp จะไม่เพิ่มขึ้นสำหรับเฟรมเสียงเงียบที่แทรก

สำหรับผู้ผลิตอุปกรณ์

การกำหนดค่า

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 ID จากอุปกรณ์เสียงหลักและเชื่อมโยงภายในกับ ID เซสชันเสียง:

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 ID จะถูกส่งผ่านไปยังสตรีมเอาต์พุตระหว่างการสร้าง AudioTrack สิ่งนี้ทำได้โดย เธรดการเล่น :

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

HW_AV_SYNC ID ไม่ว่าจะสอดคล้องกับสตรีมเอาต์พุตเสียงหรือการกำหนดค่า Tuner จะถูกส่งผ่านไปยังส่วนประกอบ OMX หรือ Codec2 เพื่อให้รหัส OEM สามารถเชื่อมโยงตัวแปลงสัญญาณกับสตรีมเอาต์พุตเสียงหรือสตรีมจูนเนอร์ที่สอดคล้องกันได้

ในระหว่างการกำหนดค่าส่วนประกอบ ส่วนประกอบ OMX หรือ Codec2 ควรส่งคืนหมายเลขอ้างอิงแถบด้านข้างที่สามารถใช้เพื่อเชื่อมโยงตัวแปลงสัญญาณกับเลเยอร์ Hardware Composer (HWC) เมื่อแอปเชื่อมโยง Surface กับ MediaCodec ตัวจัดการแถบด้านข้างนี้จะถูกส่งต่อไปยัง HWC ผ่าน 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 มีหน้าที่รับผิดชอบในการรับบัฟเฟอร์ภาพใหม่จากเอาต์พุตโคเดกในเวลาที่เหมาะสม ไม่ว่าจะซิงโครไนซ์กับสตรีมเอาต์พุตเสียงที่เกี่ยวข้องหรือนาฬิกาอ้างอิงโปรแกรมจูนเนอร์ แต่งบัฟเฟอร์ด้วยเนื้อหาปัจจุบันของเลเยอร์อื่น และแสดงภาพที่ได้ สิ่งนี้เกิดขึ้นโดยไม่ขึ้นอยู่กับรอบการเตรียมและการตั้งค่าตามปกติ การจัดเตรียมและตั้งค่าการโทรจะเกิดขึ้นเฉพาะเมื่อเลเยอร์อื่นเปลี่ยนแปลง หรือเมื่อคุณสมบัติของเลเยอร์แถบด้านข้าง (เช่น ตำแหน่งหรือขนาด) เปลี่ยนแปลง

โอเอ็มเอ็กซ์

ส่วนประกอบตัวถอดรหัสแบบช่องสัญญาณควรสนับสนุนสิ่งต่อไปนี้:

  • การตั้งค่าพารามิเตอร์ขยาย OMX.google.android.index.configureVideoTunnelMode ซึ่งใช้โครงสร้าง ConfigureVideoTunnelModeParams เพื่อส่งผ่าน HW_AV_SYNC ID ที่เชื่อมโยงกับอุปกรณ์เอาต์พุตเสียง

  • การกำหนดค่าพารามิเตอร์ 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

โคเดก2

ใน 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 เรนเดอร์เฟรมวิดีโอซิงค์กับเฟรมเสียงที่เกี่ยวข้อง Audio HAL ควรแยกวิเคราะห์ส่วนหัวการซิงค์และใช้การประทับเวลาการนำเสนอเพื่อซิงโครไนซ์นาฬิกาเล่นกลับด้วยการเรนเดอร์เสียง ในการซิงโครไนซ์ใหม่เมื่อมีการเล่นเสียงที่บีบอัด Audio HAL อาจจำเป็นต้องแยกวิเคราะห์ข้อมูลเมตาภายในข้อมูลเสียงที่บีบอัดเพื่อกำหนดระยะเวลาการเล่น

หยุดการสนับสนุนชั่วคราว

Android 5 หรือต่ำกว่าไม่มีการรองรับการหยุดชั่วคราว คุณสามารถหยุดการเล่นแบบทันเนลชั่วคราวได้โดยการอด A/V เท่านั้น แต่หากบัฟเฟอร์ภายในสำหรับวิดีโอมีขนาดใหญ่ (เช่น มีข้อมูลหนึ่งวินาทีในคอมโพเนนต์ OMX) ก็จะทำให้การหยุดชั่วคราวดูไม่ตอบสนอง

ใน Android 5.1 หรือสูงกว่า AudioFlinger รองรับการหยุดชั่วคราวและเล่นต่อสำหรับเอาต์พุตเสียงโดยตรง (แบบอุโมงค์) หาก HAL ใช้การหยุดชั่วคราวและเล่นต่อ ติดตามการหยุดชั่วคราวและเล่นต่อจะถูกส่งต่อไปยัง HAL

ลำดับการโทรหยุดชั่วคราว ล้าง และดำเนินการต่อนั้นได้รับความเคารพโดยดำเนินการเรียก HAL ในเธรดการเล่น (เหมือนกับออฟโหลด)

ข้อเสนอแนะในการดำเนินการ

เครื่องเสียง HAL

สำหรับ Android 11 สามารถใช้ HW sync ID จาก PCR หรือ STC สำหรับการซิงค์ A/V ได้ ดังนั้นจึงรองรับการสตรีมวิดีโอเท่านั้น

สำหรับ Android 10 หรือต่ำกว่า อุปกรณ์ที่รองรับการเล่นวิดีโอแบบทันเนลควรมีโปรไฟล์สตรีมเอาต์พุตเสียงอย่างน้อยหนึ่งโปรไฟล์พร้อมแฟล็ก FLAG_HW_AV_SYNC และ AUDIO_OUTPUT_FLAG_DIRECT ในไฟล์ audio_policy.conf แฟล็กเหล่านี้ใช้เพื่อตั้งค่านาฬิการะบบจากนาฬิกาเสียง

โอเอ็มเอ็กซ์

ผู้ผลิตอุปกรณ์ควรมีส่วนประกอบ OMX แยกต่างหากสำหรับการเล่นวิดีโอแบบทันเนล (ผู้ผลิตสามารถมีส่วนประกอบ 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>

นักแต่งเพลงฮาร์ดแวร์ (HWC)

เมื่อมีเลเยอร์ช่องสัญญาณ (เลเยอร์ที่มี HWC_SIDEBAND compositionType ) บนจอแสดง sidebandStream ของเลเยอร์คือตัวจัดการแถบด้านข้างที่จัดสรรโดยคอมโพเนนต์วิดีโอ OMX

HWC ซิงโครไนซ์เฟรมวิดีโอที่ถอดรหัสแล้ว (จากส่วนประกอบ OMX แบบทันเนล) ไปยังแทร็กเสียงที่เกี่ยวข้อง (ด้วย ID audio-hw-sync ) เมื่อเฟรมวิดีโอใหม่กลายเป็นเฟรมปัจจุบัน HWC จะรวมเฟรมเข้ากับเนื้อหาปัจจุบันของเลเยอร์ทั้งหมดที่ได้รับระหว่างการเตรียมหรือตั้งค่าการโทรครั้งล่าสุด และแสดงภาพที่ได้ การจัดเตรียมหรือตั้งค่าการโทรจะเกิดขึ้นเฉพาะเมื่อเลเยอร์อื่นเปลี่ยนแปลง หรือเมื่อคุณสมบัติของเลเยอร์แถบด้านข้าง (เช่น ตำแหน่งหรือขนาด) เปลี่ยนแปลง

รูปต่อไปนี้แสดงถึง HWC ที่ทำงานร่วมกับฮาร์ดแวร์ซิงโครไนเซอร์ (หรือเคอร์เนลหรือไดรเวอร์) เพื่อรวมเฟรมวิดีโอ (7b) เข้ากับองค์ประกอบล่าสุด (7a) เพื่อแสดงผลในเวลาที่ถูกต้อง โดยอิงตามเสียง (7c)

HWC รวมเฟรมวิดีโอตามเสียง

รูปที่ 2 เครื่องซิงโครไนซ์ฮาร์ดแวร์ HWC (หรือเคอร์เนลหรือไดรเวอร์)