मल्टीमीडिया टनलिंग

मल्टीमीडिया टनलिंग को टनल मोड भी कहा जाता है. इसकी मदद से, कंप्रेस किए गए वीडियो डेटा को सीधे हार्डवेयर वीडियो डिकोडर से डिसप्ले तक टनल किया जा सकता है. इसके लिए, ऐप्लिकेशन कोड या Android फ़्रेमवर्क कोड से प्रोसेस करने की ज़रूरत नहीं होती. Android स्टैक के नीचे मौजूद डिवाइस के हिसाब से कोड यह तय करता है कि डिसप्ले को कौनसे वीडियो फ़्रेम भेजने हैं और उन्हें कब भेजना है. इसके लिए, वह वीडियो फ़्रेम प्रज़ेंटेशन के टाइमस्टैंप की तुलना, यहां दी गई किसी एक तरह की इंटरनल क्लॉक से करता है:

  • Android 5 या इसके बाद के वर्शन में, मांग पर वीडियो चलाने के लिए, AudioTrack घड़ी को ऑडियो प्रज़ेंटेशन के टाइमस्टैंप के साथ सिंक किया जाता है. यह घड़ी, ऐप्लिकेशन से पास की जाती है

  • Android 11 या इसके बाद के वर्शन में लाइव ब्रॉडकास्ट चलाने के लिए, प्रोग्राम रेफ़रंस क्लॉक (पीसीआर) या सिस्टम टाइम क्लॉक (एसटीसी) की ज़रूरत होती है. यह ट्यूनर से चलता है

बैकग्राउंड

नॉन-टनल मोड में Android पर वीडियो चलाने पर, कंप्रेस किए गए वीडियो फ़्रेम के डिकोड होने पर ऐप्लिकेशन को सूचना मिलती है. इसके बाद, ऐप्लिकेशन डिकोड किए गए वीडियो फ़्रेम को डिसप्ले के लिए रिलीज़ करता है, ताकि उसे उसी सिस्टम क्लॉक टाइम पर रेंडर किया जा सके जिस पर ऑडियो फ़्रेम रेंडर किया गया था. इसके लिए, ऐप्लिकेशन AudioTimestamp के पिछले इंस्टेंस फिर से हासिल करता है, ताकि सही समय का हिसाब लगाया जा सके.

टनल किए गए वीडियो प्लेबैक में, ऐप्लिकेशन कोड को बायपास किया जाता है. साथ ही, वीडियो पर काम करने वाली प्रोसेस की संख्या कम हो जाती है. इसलिए, ओईएम के लागू करने के तरीके के आधार पर, यह वीडियो को ज़्यादा बेहतर तरीके से रेंडर कर सकता है. यह वीडियो कैडेंस और चुने गए क्लॉक (पीआरसी, एसटीडी या ऑडियो) के साथ सिंक्रनाइज़ेशन को ज़्यादा सटीक बना सकता है. ऐसा इसलिए, क्योंकि यह Android के वीडियो रेंडर करने के अनुरोध के समय और हार्डवेयर के वीसिंक के समय के बीच संभावित अंतर की वजह से होने वाली टाइमिंग की समस्याओं से बचता है. हालांकि, टनलिंग से जीपीयू इफ़ेक्ट के लिए भी सहायता कम हो सकती है. जैसे, पिक्चर-इन-पिक्चर (पीआईपी) विंडो में धुंधला करना या गोल कोने. ऐसा इसलिए होता है, क्योंकि बफ़र Android ग्राफ़िक्स स्टैक को बायपास करते हैं.

इस डायग्राम में दिखाया गया है कि टनलिंग की मदद से, वीडियो चलाने की प्रोसेस को कैसे आसान बनाया जाता है.

ट्रेडिशन और टनल मोड की तुलना

पहली इमेज. नॉन-टनल्ड और टनल्ड वीडियो चलाने की प्रोसेस की तुलना.

ऐप्लिकेशन डेवलपर के लिए जानकारी

ज़्यादातर ऐप्लिकेशन डेवलपर, वीडियो चलाने की सुविधा लागू करने के लिए किसी लाइब्रेरी के साथ इंटिग्रेट करते हैं. इसलिए, ज़्यादातर मामलों में टनल किए गए प्लेबैक के लिए, सिर्फ़ उस लाइब्रेरी को फिर से कॉन्फ़िगर करना होता है. टनल किए गए वीडियो प्लेयर को कम लेवल पर लागू करने के लिए, यहां दिए गए निर्देशों का पालन करें.

Android 5 या इसके बाद के वर्शन वाले डिवाइसों में, मांग पर वीडियो चलाने के लिए:

  1. SurfaceView इंस्टेंस बनाएं.

  2. audioSessionId इंस्टेंस बनाएं.

  3. दूसरे चरण में बनाए गए audioSessionId इंस्टेंस का इस्तेमाल करके, AudioTrack और MediaCodec इंस्टेंस बनाएं.

  4. ऑडियो डेटा में मौजूद पहले ऑडियो फ़्रेम के लिए, प्रज़ेंटेशन के टाइमस्टैंप के साथ AudioTrack में ऑडियो डेटा को लाइन में लगाएं.

Android 11 या इसके बाद के वर्शन वाले डिवाइसों पर लाइव ब्रॉडकास्ट चलाने के लिए:

  1. SurfaceView इंस्टेंस बनाएं.

  2. Tuner से avSyncHwId इंस्टेंस पाएं.

  3. दूसरे चरण में बनाए गए avSyncHwId इंस्टेंस की मदद से, AudioTrack और MediaCodec इंस्टेंस बनाएं.

एपीआई कॉल फ़्लो को यहां दिए गए कोड स्निपेट में दिखाया गया है:

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 पर सेट करें.

    • अगर इस पैरामीटर को सेट नहीं किया जाता है, तो ओईएम यह तय करता है कि डिवाइस किस तरह काम करेगा.

  • जब AudioTrack को ऑडियो डेटा नहीं मिलता और बफ़र खाली होते हैं (ऑडियो अंडररन), तो वीडियो तब तक नहीं चलता, जब तक ज़्यादा ऑडियो डेटा नहीं लिखा जाता. ऐसा इसलिए होता है, क्योंकि ऑडियो क्लॉक अब आगे नहीं बढ़ रही होती है.

  • ऑडियो चलाने के दौरान, ऑडियो प्रज़ेंटेशन के टाइमस्टैंप में ऐसी रुकावटें दिख सकती हैं जिन्हें ऐप्लिकेशन ठीक नहीं कर सकता. ऐसा होने पर, ओईएम नेगेटिव गैप को ठीक करने के लिए, मौजूदा वीडियो फ़्रेम को रोक देता है. साथ ही, पॉज़िटिव गैप को ठीक करने के लिए, वीडियो फ़्रेम हटा देता है या साइलेंट ऑडियो फ़्रेम डाल देता है. यह ओईएम के लागू करने के तरीके पर निर्भर करता है. AudioTimestamp में जोड़े गए साइलेंट ऑडियो फ़्रेम के लिए, फ़्रेम की पोज़िशन नहीं बढ़ती.

वीडियो के किसी भी हिस्से पर जाने की सुविधा का क्रम

वीडियो के किसी भी हिस्से पर जाने की सुविधा से, वीडियो में खास पल वाले हिस्से पर जाना आसान हो जाता है. कीफ़्रेम सीकिंग की तुलना में, सटीक सीकिंग की सुविधा ज़्यादा बेहतर है. कीफ़्रेम सीकिंग की सुविधा में, वीडियो सिर्फ़ सबसे नज़दीकी आई-फ़्रेम पर जाता है. साथ ही, यह टारगेट की गई पोज़िशन से कुछ सेकंड आगे-पीछे हो सकता है. वहीं, सटीक सीकिंग की सुविधा में, वीडियो ठीक उसी टाइमस्टैंप पर रेंडर होता है जिसके लिए अनुरोध किया गया है. एपीआई के इस खास क्रम का पालन करने से, ऐप्लिकेशन को बैकग्राउंड में प्री-रोलिंग और समय के साथ सिंक्रनाइज़ेशन को आसानी से पूरा करने की अनुमति मिलती है. इससे यह पक्का होता है कि प्लेबैक फिर से शुरू होने पर, टारगेट फ़्रेम तुरंत दिखे.

वीडियो के किसी भी हिस्से पर जाने के लिए, इमेज 2 में दिखाए गए क्रम में ये काम करें:

वीडियो को आगे-पीछे करने के क्रम का फ़्लो

दूसरी इमेज. वीडियो के किसी भी हिस्से पर जाने की सुविधा का इस्तेमाल करने का क्रम.

मुख्य जानकारी में ये शामिल हैं:

  • एक साथ कई कार्रवाइयां करना: एक ही par बॉक्स में एक साथ कई कार्रवाइयां की जा सकती हैं. उदाहरण के लिए, वीडियो MediaCodec कॉल, AudioTrack से अलग होते हैं.

  • क्रम से जुड़ी डिपेंडेंसी: दूसरे par बॉक्स पर जाने से पहले, पहले par बॉक्स में मौजूद सभी कार्रवाइयों को कॉल करें. खास तौर पर, ऐप्लिकेशन को यह पक्का करना होगा कि AudioTrack.play को कॉल करने से पहले, वीडियो MediaCodec में AudioTrack.write और बफ़रिंग को कतार में लगाया गया हो.

वीडियो चलाने की अलग-अलग स्पीड का क्रम

वीडियो को अलग-अलग स्पीड पर चलाने की सुविधा की मदद से, वीडियो को सामान्य स्पीड से तेज़ या धीमी स्पीड पर चलाया जा सकता है. इस सुविधा का इस्तेमाल आम तौर पर ऐप्लिकेशन करते हैं, ताकि उपयोगकर्ता तेज़ी से कॉन्टेंट देख सकें. जैसे, समय बचाने के लिए शिक्षा से जुड़े लेक्चर या पॉडकास्ट को 1.5x या 2.0x की स्पीड पर चलाना. इसके अलावा, इस सुविधा का इस्तेमाल कॉन्टेंट को धीमी स्पीड पर देखने के लिए भी किया जाता है. जैसे, खेल से जुड़ी गतिविधियों या निर्देश वाले वीडियो को 0.5x की स्पीड पर देखना.

स्पीड सेट करने के लिए, इमेज 3 में दिखाए गए क्रम का पालन करें:

स्पीड सीक्वेंस फ़्लो

तीसरी इमेज. स्पीड सेट करने के लिए, क्रम से दिया गया फ़्लो.

नीचे दी गई तकनीकी ज़रूरी शर्तों और व्यवहारों को, तीसरे डायग्राम के क्रम में शामिल नहीं किया गया है:

  • AudioTrack.getTimestamp, ओरिजनल ऑडियो इनपुट फ़्रीक्वेंसी के आधार पर framePosition दिखाता है. उदाहरण के लिए, 44,100 हर्ट्ज़ के इनपुट और 2.0x की स्पीड से चलाने पर, दो सेकंड बाद AudioTrack.getTimestamp, framePosition के तौर पर 1,76,400 दिखाता है.

  • अगर ऐप्लिकेशन setSpeed(1.5) को कॉल करता है और वह कॉल पूरा हो जाता है, तो ऐप्लिकेशन setSpeed(30) को कॉल करता है और वह कॉल पूरा नहीं होता है. ऐसे में, वीडियो 1.5x की स्पीड से चलता रहेगा.

  • अगर ऑडियो को म्यूट किया जाता है (setVolume का इस्तेमाल करके), तो भी ऐप्लिकेशन को ऑडियो बफ़र भेजने होंगे. ऐसा इसलिए, क्योंकि वीडियो फ़्रेम, ऑडियो की पोज़िशन के आधार पर रेंडर किए जाते हैं.

  • स्पीड बदलने पर, ऑडियो की पिच में कोई बदलाव नहीं होता.

  • वीडियो चलाने की स्पीड पर, वीडियो चलाने से जुड़ी अन्य कार्रवाइयों का कोई असर नहीं पड़ता.

    • पहला उदाहरण: अगर वीडियो चलाने की स्पीड 1.5x पर सेट है और AudioTrack को रोका जाता है, तो AudioTrack को फिर से शुरू करने पर भी स्पीड 1.5x पर ही रहेगी.

    • दूसरा उदाहरण: अगर वीडियो चलाने की स्पीड 1.5 गुना है और उपयोगकर्ता किसी दूसरे पीटीएस पर जाता है, तो दूसरी इमेज में दिए गए तरीके के मुताबिक, वीडियो चलाने की स्पीड 1.5 गुना ही रहेगी.

  • यह पक्का करने के लिए कि सभी फ़्रेम को समय पर डिकोड किया जा सके, ताकि उन्हें चुनी गई स्पीड पर रेंडर किया जा सके, KEY_OPERATING_RATE को वीडियो फ़्रेम रेट और प्लेबैक स्पीड के प्रॉडक्ट से मैच करने के लिए सेट करें. अगर KEY_OPERATING_RATE को ज़रूरत के मुताबिक सेट नहीं किया गया है, तो हो सकता है कि कोडेक फ़्रेम को तेज़ी से डीकोड न कर पाए. इससे वीडियो चलाने के दौरान फ़्रेम ड्रॉप हो सकते हैं.

    • उदाहरण: अगर कॉन्टेंट का ओरिजनल फ़्रेम रेट 60 फ़्रेम प्रति सेकंड है और चलाने की स्पीड 2x है, तो KEY_OPERATING_RATE को 120 पर सेट करें.
  • वीडियो चलाने की स्पीड को बार-बार अलग-अलग स्पीड पर सेट करने से कोई गड़बड़ी नहीं होनी चाहिए. साथ ही, आखिरी बार स्पीड सेट करने के बाद, वीडियो चलाने का तरीका वैसा ही होना चाहिए जैसा कि स्पीड को सिर्फ़ एक बार सेट करने पर होता है.

डिवाइस बनाने वाली कंपनियों के लिए

कॉन्फ़िगरेशन

ओईएम को टनल किए गए वीडियो चलाने की सुविधा के लिए, एक अलग वीडियो डिकोडर बनाना चाहिए. इस डिकोडर को यह जानकारी देनी चाहिए कि यह media_codecs.xml फ़ाइल में टनल किए गए प्लेबैक की सुविधा दे सकता है:

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

जब ऑडियो सेशन आईडी के साथ टनल किए गए MediaCodec इंस्टेंस को कॉन्फ़िगर किया जाता है, तो यह इस HW_AV_SYNC आईडी के लिए AudioFlinger से क्वेरी करता है:

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 बनाते समय आउटपुट स्ट्रीम में पास किया जाता है. यह काम playback thread करता है:

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

HW_AV_SYNC आईडी को OMX या Codec2 कॉम्पोनेंट में पास किया जाता है. यह आईडी, ऑडियो आउटपुट स्ट्रीम या Tuner कॉन्फ़िगरेशन से जुड़ा होता है. इससे OEM कोड, कोडेक को ऑडियो आउटपुट स्ट्रीम या ट्यूनर स्ट्रीम से जोड़ सकता है.

कॉम्पोनेंट कॉन्फ़िगरेशन के दौरान, OMX या Codec2 कॉम्पोनेंट को एक साइडबैंड हैंडल दिखाना चाहिए. इसका इस्तेमाल, कोडेक को हार्डवेयर कंपोज़र (एचडब्ल्यूसी) लेयर से जोड़ने के लिए किया जा सकता है. जब ऐप्लिकेशन, किसी सरफेस को MediaCodec से जोड़ता है, तब इस साइडबैंड हैंडल को SurfaceFlinger के ज़रिए HWC को पास किया जाता है. इससे लेयर को साइडबैंड लेयर के तौर पर कॉन्फ़िगर किया जाता है.

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;
}

एचडब्ल्यूसी, कोडेक आउटपुट से नए इमेज बफ़र को सही समय पर पाने के लिए ज़िम्मेदार होता है. ये बफ़र, ऑडियो आउटपुट स्ट्रीम या ट्यूनर प्रोग्राम के रेफ़रंस क्लॉक के साथ सिंक किए जाते हैं. एचडब्ल्यूसी, बफ़र को अन्य लेयर के मौजूदा कॉन्टेंट के साथ कंपोज़ करता है और नतीजे के तौर पर मिली इमेज को दिखाता है. यह सामान्य तौर पर, तैयारी और सेट करने के साइकल से अलग होता है. तैयार करने और सेट करने के कॉल सिर्फ़ तब किए जाते हैं, जब अन्य लेयर में बदलाव होता है या साइडबैंड लेयर की प्रॉपर्टी (जैसे कि पोज़िशन या साइज़) में बदलाव होता है.

OMX

टनल वाले डिकोडर कॉम्पोनेंट में ये सुविधाएं होनी चाहिए:

  • OMX.google.android.index.configureVideoTunnelMode extended पैरामीटर सेट करना. यह पैरामीटर, 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 सदस्य के ज़रिए वापस पास करना चाहिए, ताकि एचडब्ल्यूसी इससे जुड़े कोडेक की पहचान कर सके. अगर कॉम्पोनेंट इस कॉन्फ़िगरेशन के साथ काम नहीं करता है, तो उसे bTunneled को OMX_FALSE पर सेट करना चाहिए.

Codec2

Android 11 या इसके बाद के वर्शन में, Codec2 टनल किए गए प्लेबैक के साथ काम करता है. डिकोडर कॉम्पोनेंट में ये सुविधाएं होनी चाहिए:

  • C2PortTunneledModeTuning को कॉन्फ़िगर करना. यह टनल मोड को कॉन्फ़िगर करता है और ऑडियो आउटपुट डिवाइस या ट्यूनर कॉन्फ़िगरेशन से वापस लाए गए HW_AV_SYNC में पास होता है.

  • एचडब्ल्यूसी के लिए साइडबैंड हैंडल को असाइन और वापस पाने के लिए, C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE से क्वेरी करना.

  • 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 लागू करने पर, C2PortTunnelModeTuning के ज़रिए CCodec में टनल मोड कॉन्फ़िगर किया जाता है. इसे यहां दिए गए कोड स्निपेट में दिखाया गया है:

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 के ज़रिए वापस भेजना चाहिए, ताकि एचडब्ल्यूसी इससे जुड़े कोडेक की पहचान कर सके.

ऑडियो HAL

मांग पर वीडियो चलाने के लिए, ऑडियो एचएएल को ऑडियो प्रज़ेंटेशन के टाइमस्टैंप मिलते हैं. ये टाइमस्टैंप, ऑडियो डेटा के साथ इनलाइन होते हैं. ऑडियो डेटा, बिग-एंडियन फ़ॉर्मैट में होता है. यह हेडर में मौजूद होता है. हेडर, ऑडियो डेटा के हर ब्लॉक की शुरुआत में मिलता है, जिसे ऐप्लिकेशन लिखता है:

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;
}

एचडब्ल्यूसी को वीडियो फ़्रेम को ऑडियो फ़्रेम के साथ सिंक करके रेंडर करने के लिए, ऑडियो एचएएल को सिंक हेडर पार्स करना चाहिए. साथ ही, ऑडियो रेंडरिंग के साथ प्लेबैक क्लॉक को फिर से सिंक करने के लिए, प्रज़ेंटेशन टाइमस्टैंप का इस्तेमाल करना चाहिए. कंप्रेस किया गया ऑडियो चलाने के दौरान फिर से सिंक करने के लिए, ऑडियो एचएएल को कंप्रेस किए गए ऑडियो डेटा में मौजूद मेटाडेटा को पार्स करने की ज़रूरत पड़ सकती है. इससे, वह ऑडियो चलाने की अवधि का पता लगा सकता है.

सहायता को रोकना

Android 5 या इससे पहले के वर्शन में, वीडियो को रोकने की सुविधा नहीं है. सिर्फ़ ए/वी स्टार्वेशन की वजह से, टनल किए गए प्लेबैक को रोका जा सकता है. हालांकि, अगर वीडियो के लिए इंटरनल बफ़र बड़ा है (उदाहरण के लिए, ओएमएक्स कॉम्पोनेंट में एक सेकंड का डेटा है), तो इससे वीडियो रुकने पर ऐसा लगता है कि वह काम नहीं कर रहा है.

Android 5.1 या इसके बाद के वर्शन में, AudioFlinger सीधे (टनल किए गए) ऑडियो आउटपुट के लिए, ऑडियो को रोकने और फिर से चलाने की सुविधा देता है. अगर HAL में रोकने और फिर से शुरू करने की सुविधा लागू की जाती है, तो रोकने और फिर से शुरू करने की सुविधा को HAL पर फ़ॉरवर्ड किया जाता है.

HAL कॉल को प्लेबैक थ्रेड में (ऑफ़लोड की तरह) लागू करके, रोकने, फ़्लश करने, और फिर से शुरू करने के कॉल सीक्वेंस का पालन किया जाता है.

लागू करने के सुझाव

ऑडियो HAL

Android 11 के लिए, पीसीआर या एसटीडी से मिले एचडब्ल्यू सिंक आईडी का इस्तेमाल ए/वी सिंक के लिए किया जा सकता है. इसलिए, सिर्फ़ वीडियो स्ट्रीम की सुविधा काम करती है.

Android 10 या इससे पहले के वर्शन वाले डिवाइसों के लिए, टनल किए गए वीडियो चलाने की सुविधा वाले डिवाइसों में, कम से कम एक ऑडियो आउटपुट स्ट्रीम प्रोफ़ाइल होनी चाहिए. साथ ही, इसकी audio_policy.conf फ़ाइल में FLAG_HW_AV_SYNC और AUDIO_OUTPUT_FLAG_DIRECT फ़्लैग होने चाहिए. इन फ़्लैग का इस्तेमाल, ऑडियो क्लॉक से सिस्टम क्लॉक को सेट करने के लिए किया जाता है.

OMX

डिवाइस बनाने वाली कंपनियों के पास, टनल किए गए वीडियो चलाने के लिए एक अलग 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>
    

अगर टनल और नॉनटनल डिकोडिंग के लिए एक ही ओएमएक्स कॉम्पोनेंट का इस्तेमाल किया जाता है, तो उसे टनल किए गए कॉन्टेंट को चलाने की सुविधा को गैर-ज़रूरी के तौर पर छोड़ देना चाहिए. इसके बाद, टनल किए गए और टनल नहीं किए गए, दोनों तरह के डिकोडर पर एक जैसी सीमाएं लागू होती हैं. इसका एक उदाहरण यहां दिया गया है:

<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_SIDEBAND compositionType वाली लेयर) होती है, तो लेयर का sidebandStream, OMX वीडियो कॉम्पोनेंट से असाइन किया गया साइडबैंड हैंडल होता है.

एचडब्ल्यूसी, डिकोड किए गए वीडियो फ़्रेम (टनल वाले ओएमएक्स कॉम्पोनेंट से) को audio-hw-sync आईडी वाले ऑडियो ट्रैक के साथ सिंक करता है. जब कोई नया वीडियो फ़्रेम चालू होता है, तो एचडब्ल्यूसी उसे उन सभी लेयर के मौजूदा कॉन्टेंट के साथ कंपोज़ करता है जो उसे पिछले prepare या set कॉल के दौरान मिले थे. इसके बाद, वह कंपोज़ की गई इमेज दिखाता है. तैयार करने या सेट करने के कॉल सिर्फ़ तब होते हैं, जब अन्य लेयर बदलती हैं या जब साइडबैंड लेयर की प्रॉपर्टी (जैसे कि पोज़िशन या साइज़) बदलती हैं.

इस इमेज में दिखाया गया है कि एचडब्ल्यूसी, हार्डवेयर (या कर्नल या ड्राइवर) सिंक्रनाइज़र के साथ मिलकर कैसे काम करता है. इससे वीडियो फ़्रेम (7b) को ऑडियो (7c) के आधार पर सही समय पर दिखाने के लिए, लेटेस्ट कंपोज़िशन (7a) के साथ जोड़ा जा सकता है.

ऑडियो के आधार पर वीडियो फ़्रेम को मिलाकर एचडब्ल्यूसी बनाना

चौथी इमेज. HWC हार्डवेयर (या कर्नल या ड्राइवर) सिंक्रनाइज़र.