การสร้างอุโมงค์สำหรับมัลติมีเดีย

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

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

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

ฉากหลัง

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

เนื่องจากการเล่นวิดีโอแบบ Tunnel จะข้ามโค้ดของแอปและลดจำนวน กระบวนการที่ทำงานกับวิดีโอ จึงทำให้การแสดงวิดีโอมีประสิทธิภาพมากขึ้น ขึ้นอยู่กับการติดตั้งใช้งานของ 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-frame ) หมายความว่าเฟรมวิดีโอแรกที่แสดงควรเป็น I-frame เสมอ

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

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

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

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

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

การกำหนดค่า

OEM ควรสร้างตัวถอดรหัสวิดีโอแยกต่างหากเพื่อรองรับการเล่นวิดีโอแบบ Tunnel ตัวถอดรหัสนี้ควรโฆษณาว่าสามารถเล่นแบบ Tunnel ได้ในไฟล์ 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 ID ไปยังสตรีมเอาต์พุตในระหว่างการสร้าง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) ได้ เมื่อแอปเชื่อมโยง 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 มีหน้าที่รับบัฟเฟอร์รูปภาพใหม่จากเอาต์พุตของตัวแปลงรหัสในเวลาที่เหมาะสม ไม่ว่าจะซิงค์กับสตรีมเอาต์พุตเสียงที่เกี่ยวข้องหรือนาฬิกาอ้างอิงของโปรแกรมจูนเนอร์ การคอมโพสิตบัฟเฟอร์กับเนื้อหาปัจจุบันของเลเยอร์อื่นๆ และแสดงรูปภาพที่ได้ ซึ่งจะเกิดขึ้น โดยไม่ขึ้นอยู่กับวงจรการเตรียมและการตั้งค่าปกติ การเรียกใช้ prepare และ set จะเกิดขึ้นเมื่อเลเยอร์อื่นๆ เปลี่ยนแปลง หรือเมื่อพร็อพเพอร์ตี้ของเลเยอร์แถบข้าง (เช่น ตำแหน่งหรือขนาด) เปลี่ยนแปลงเท่านั้น

OMX

คอมโพเนนต์ตัวถอดรหัสที่ส่งผ่านอุโมงค์ควรรองรับสิ่งต่อไปนี้

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

  • การกำหนดค่าพารามิเตอร์ OMX_IndexConfigAndroidTunnelPeek ที่บอกให้ตัวแปลงรหัส แสดงผลหรือไม่แสดงผลเฟรมวิดีโอแรกที่ถอดรหัสแล้ว ไม่ว่าการเล่นเสียงจะเริ่มแล้วหรือไม่ก็ตาม

  • ส่งเหตุการณ์ OMX_EventOnFirstTunnelFrameReady เมื่อถอดรหัสเฟรมวิดีโอแรกที่ผ่านการอุโมงค์ และพร้อมที่จะแสดงผล

การติดตั้งใช้งาน AOSP จะกำหนดค่าโหมด Tunnel ใน 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 รองรับการเล่นแบบ Tunnel คอมโพเนนต์ตัวถอดรหัส ควรรองรับสิ่งต่อไปนี้

  • การกำหนดค่า 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 เสียง

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

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

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

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

ลำดับการเรียกใช้ pause, flush, resume จะได้รับการพิจารณาโดยการเรียกใช้ HAL ในเธรดการเล่น (เช่นเดียวกับการออฟโหลด)

คำแนะนำในการใช้งาน

HAL เสียง

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

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

OMX

ผู้ผลิตอุปกรณ์ควรมีคอมโพเนนต์ OMX แยกต่างหากสำหรับการเล่นวิดีโอแบบ Tunnel (ผู้ผลิตอาจมีคอมโพเนนต์ 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 ที่ส่งผ่านอุโมงค์) กับ แทร็กเสียงที่เกี่ยวข้อง (ที่มี audio-hw-sync ID) เมื่อเฟรมวิดีโอใหม่ กลายเป็นเฟรมปัจจุบัน HWC จะรวมเฟรมดังกล่าวกับเนื้อหาปัจจุบันของเลเยอร์ทั้งหมด ที่ได้รับระหว่างการเรียกเตรียมหรือตั้งค่าครั้งล่าสุด แล้วแสดงรูปภาพที่ได้ การเรียกใช้ prepare หรือ set จะเกิดขึ้นเมื่อเลเยอร์อื่นๆ เปลี่ยนแปลง หรือเมื่อพร็อพเพอร์ตี้ของเลเยอร์แถบข้าง (เช่น ตำแหน่งหรือขนาด) เปลี่ยนแปลงเท่านั้น

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

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

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