الاتصال النفقي للوسائط المتعددة

يعمل الاتصال النفقي للوسائط المتعددة على تمكين بيانات الفيديو المضغوطة من الاتصال النفقي عبر جهاز. برنامج فك ترميز الفيديو مباشرةً على الشاشة، بدون معالجته باستخدام رمز التطبيق رمز إطار عمل Android. الرمز الخاص بالجهاز أسفل حزمة Android إطارات الفيديو المطلوب إرسالها إلى الشاشة ومتى يتم إرسالها بمقارنة الطوابع الزمنية للعرض التقديمي لإطار الفيديو بأحد العناصر التالية أنواع الساعات الداخلية:

  • لتشغيل فيديو عند الطلب في Android 5 أو الإصدارات الأحدث، AudioTrack ساعة متزامنة مع الطوابع الزمنية للعرض الصوتي تم بنجاح داخل التطبيق

  • ساعة مرجعية للبرنامج لتشغيل البث المباشر على نظام Android 11 أو الإصدارات الأحدث (PCR) أو ساعة النظام الزمنية (STC) التي يتم تشغيلها بواسطة أداة موالفة

خلفية

إرسال إشعارات إلى التشغيل التقليدي للفيديو على أجهزة Android التطبيق عند فك ترميز إطار فيديو مضغوط. يعمل التطبيق بعد ذلك الإصدارات إطار الفيديو الذي تم فك ترميزه على الشاشة ليتم عرضه في ساعة النظام نفسها والوقت كإطار الصوت المناسب استرداد البيانات السابقة AudioTimestamps الحالات لحساب التوقيت الصحيح.

نظرًا لأن تشغيل الفيديو النفقي يتجاوز رمز التطبيق ويقلل من عدد على الفيديو، يمكن أن يوفر عرض أكثر فعالية للفيديو اعتمادًا على التنفيذ من قِبل المصنّع الأصلي للجهاز. وقد يساعد أيضًا في تقديم فيديوهات أكثر دقة الإيقاع والمزامنة مع الساعة المحدّدة (PRC أو STC أو الصوت) من خلال تجنب مشاكل في التوقيت بسبب اختلاف محتمل بين توقيتات عمل Android وطلبات عرض الفيديو وتوقيت عمليات vsyncs الفعلية للأجهزة. ومع ذلك، أيضًا إلى تقليل دعم تأثيرات وحدة معالجة الرسومات مثل التمويه الزوايا الدائرية في النوافذ على وضع "نافذة ضمن النافذة" (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.

يظهر مسار طلب بيانات من واجهة برمجة التطبيقات في مقتطفات الرمز التالية:

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 عن تم إدراج إطارات صوتية صامتة.

للشركات المصنّعة للأجهزة

الإعدادات

على المصنّعين الأصليين للأجهزة إنشاء برنامج فك ترميز فيديو منفصل لإتاحة تشغيل الفيديو من خلال النفق. يجب أن تعلن أداة فك الترميز هذه عن إمكانية تشغيل نفقي في ملف 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 بحيث بإمكان رمز المصنّع الأصلي للجهاز ربط برنامج الترميز بالبث الصوتي المناسب. بث الموالف.

أثناء ضبط المكوِّن، يجب أن يعرض المكوِّن OMX أو Codec2 مقبض النطاق الجانبي الذي يمكن استخدامه لربط برنامج الترميز بأداة إنشاء الأجهزة (HWC). عندما يربط التطبيق سطحًا بـ "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

يجب أن يتيح مكوّن فك الترميز النفقي ما يلي:

  • تم تمديد إعداد 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.

برنامج الترميز 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) للصوت

لتشغيل الفيديو عند الطلب، يتلقى جهاز HAL الصوت العرض التقديمي الصوتي تم العثور على طوابع زمنية مضمّنة مع البيانات الصوتية بتنسيق كبير في عنوان URL. في بداية كل كتلة من البيانات الصوتية، يكتب التطبيق ما يلي:

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) الصوتية إلى تحليل البيانات الوصفية ضمن البيانات الصوتية المضغوطة لتحديد مدة تشغيلها.

إيقاف الدعم مؤقتًا

لا يوفِّر الإصدار 5 من نظام التشغيل Android أو الإصدارات الأقدم إمكانية الإيقاف المؤقت. يمكنك إيقاف الاتصال النفقي مؤقتًا التشغيل من خلال تجويع الصوت والفيديو فقط، ولكن إذا كان المخزن المؤقت الداخلي للفيديو كبيرًا (على سبيل المثال، هناك ثانية واحدة من البيانات في مكوِّن OMX)، فتتوقف مؤقتًا تبدو غير مستجيبة.

في الإصدار 5.1 من Android أو الإصدارات الأحدث، يتيح AudioFlinger الإيقاف المؤقت والاستئناف المباشر (قنوات نفقية) مصادر إخراج الصوت في حال تنفيذ HAL للإيقاف المؤقت واستئنافه، تتبع الإيقاف المؤقت والسيرة الذاتية إلى HAL.

الالتزام بالإيقاف المؤقت والتدفق واستئناف المكالمات من خلال تنفيذ طلبات HAL في سلسلة التشغيل (مثلما تم إلغاء التحميل).

اقتراحات التنفيذ

طبقة تجريد الأجهزة (HAL) للصوت

بالنسبة إلى نظام التشغيل Android 11، يمكن استخدام معرّف مزامنة HW من PCR أو STC لمزامنة الصوت والصورة، لذلك يمكنك استخدام بث الفيديو فقط.

بالنسبة إلى نظام التشغيل Android 10 أو الإصدارات الأقدم، يجب أن تتوفّر على الأجهزة التي تتيح تشغيل الفيديو عبر النفق. ملف شخصي واحد على الأقل لبثّ إخراج الصوت باستخدام FLAG_HW_AV_SYNC هناك AUDIO_OUTPUT_FLAG_DIRECT علامات في ملف audio_policy.conf. هذه العلامات تُستخدم لضبط ساعة النظام من ساعة الصوت.

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>
    

إذا تم استخدام مكوِّن 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) عندما يتم عرض إطار فيديو جديد حديثة، فإن HWC يدمجها مع المحتويات الحالية لجميع الطبقات التي تلقيتها خلال آخر اتصال تحضير أو ضبط، ويعرض الصورة الناتجة. لا يحدث الإعداد أو تعيين الطلبات إلا عند تغيير طبقات أخرى، أو عندما تتغير خصائص طبقة النطاق الجانبي (مثل الموضع أو الحجم).

يمثل الشكل التالي HWC الذي يعمل مع الأجهزة (أو النواة أو برنامج التشغيل) مزامنة، لدمج إطارات الفيديو (7b) مع أحدث تركيبة (7a) للعرض في الوقت المناسب، استنادًا إلى الصوت (7c).

HWC يدمج إطارات الفيديو استنادًا إلى الصوت

الشكل 2. أداة مزامنة أجهزة HWC (أو النواة أو برنامج التشغيل)