التخصيص

وتقع الواجهة Player في مركز مكتبة ExoPlayer. Player تعرض وظائف مشغّل الوسائط التقليدية عالية المستوى مثل القدرة على تخزين الوسائط مؤقتًا والتشغيل والإيقاف المؤقت وتقديمها. طريقة التنفيذ التلقائية ExoPlayer هي مصممة لوضع القليل من الافتراضات حول (وبالتالي فرض قيود قليلة عليها) ونوع الوسائط التي يتم تشغيلها وكيف وأين يتم تخزينها وكيف يتم تشغيلها المعروضة. فبدلاً من تنفيذ عملية تحميل الوسائط وعرضها بشكل مباشر تفوض عمليات تنفيذ ExoPlayer هذا العمل إلى المكونات التي يتم إدخالها عند إنشاء مشغّل أو عند تمرير مصادر وسائط جديدة إلى المشغّل المكوّنات المشتركة لجميع عمليات تنفيذ ExoPlayer هي:

  • MediaSource مثيلات تحدّد الوسائط التي سيتم تشغيلها وتحميل الوسائط التي يمكن قراءة الوسائط المحملة منها. يتم إنشاء مثيل MediaSource من MediaItem من MediaSource.Factory داخل المشغّل. يمكنه أيضًا يتم نقلها مباشرةً إلى المشغّل باستخدام واجهة برمجة تطبيقات قائمة التشغيل المستندة إلى مصدر الوسائط.
  • مثيل MediaSource.Factory يحوِّل MediaItem إلى MediaSource تشير رسالة الأشكال البيانية يتم إدخال MediaSource.Factory عند إنشاء المشغّل.
  • Renderer مثيلات تعرض مكونات فردية للوسائط. وهي يتم إدخاله عند إنشاء المشغّل.
  • TrackSelector الذي يحدّد المقاطع الصوتية التي يوفّرها "MediaSource" يستهلكها كل Renderer من السلع المتوفرة. تم إدخال TrackSelector عند إنشاء المشغّل.
  • LoadControl الذي يتحكّم في وقت تخزين MediaSource لمزيد من الوسائط مقدار الوسائط التي تم تخزينها مؤقتًا. يتم تطبيق LoadControl عندما يكون المشغّل إنشاء.
  • LivePlaybackSpeedControl التي تتحكّم في سرعة التشغيل أثناء البث المباشر عمليات التشغيل للسماح للمشغّل بالبقاء بالقرب من مدة البث المباشر التي تم ضبطها. حاسمة يتم إدخال LivePlaybackSpeedControl عند إنشاء المشغّل.

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

تخصيص اللاعب

ومن الأمثلة الشائعة لتخصيص المشغل عن طريق إدخال المكونات الموضحة أدناه.

تهيئة حزم الشبكة

لدينا صفحة حول تخصيص حزمة الشبكة المستخدمة بواسطة ExoPlayer.

التخزين المؤقت للبيانات التي تم تحميلها من الشبكة

اطّلِع على أدلة التخزين المؤقت أثناء التنقل وتنزيل الوسائط

تخصيص تفاعلات الخادم

قد تحتاج بعض التطبيقات إلى اعتراض طلبات HTTP واستجاباته. قد ترغب في إدخال رؤوس الطلبات المخصصة، وقراءة عناوين استجابة الخادم، وتعديل الطلبات معرفات الموارد المنتظمة (URI) وما إلى ذلك. على سبيل المثال، قد يصادق تطبيقك على نفسه عن طريق إدخال رمز مميز كعنوان عند طلب شرائح الوسائط.

يوضح المثال التالي كيفية تنفيذ هذه السلوكيات عن طريق جارٍ إدخال DataSource.Factory مخصّص في DefaultMediaSourceFactory:

Kotlin

val dataSourceFactory =
  DataSource.Factory {
    val dataSource = httpDataSourceFactory.createDataSource()
    // Set a custom authentication request header.
    dataSource.setRequestProperty("Header", "Value")
    dataSource
  }
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)
    )
    .build()

Java

DataSource.Factory dataSourceFactory =
    () -> {
      HttpDataSource dataSource = httpDataSourceFactory.createDataSource();
      // Set a custom authentication request header.
      dataSource.setRequestProperty("Header", "Value");
      return dataSource;
    };

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory))
        .build();

في مقتطف الرمز أعلاه، تتضمّن سمة HttpDataSource التي تم إدخالها العنوان. "Header: Value" في كل طلب HTTP. هذا السلوك يتم إصلاحه لكل التفاعل مع مصدر HTTP.

ولاعتماد نهج أكثر دقة، يمكنك إدخال السلوك في الوقت المناسب باستخدام ResolvingDataSource يوضح مقتطف الرمز التالي كيفية إدخال طلب العناوين قبل التفاعل مع مصدر HTTP مباشرةً:

Kotlin

val dataSourceFactory: DataSource.Factory =
  ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec ->
    // Provide just-in-time request headers.
    dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri))
  }

Java

    DataSource.Factory dataSourceFactory =
        new ResolvingDataSource.Factory(
            httpDataSourceFactory,
            // Provide just-in-time request headers.
            dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));

يمكنك أيضًا استخدام ResolvingDataSource لإجراء تعديلات في الوقت المناسب لعنوان URI، كما هو موضح في المقتطف التالي:

Kotlin

val dataSourceFactory: DataSource.Factory =
  ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec ->
    // Provide just-in-time URI resolution logic.
    dataSpec.withUri(resolveUri(dataSpec.uri))
  }

Java

DataSource.Factory dataSourceFactory =
    new ResolvingDataSource.Factory(
        httpDataSourceFactory,
        // Provide just-in-time URI resolution logic.
        dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));

تخصيص معالجة الأخطاء

يسمح تنفيذ LoadErrorHandlingPolicy مخصصة للتطبيقات بتخصيص طريقة تفاعل ExoPlayer مع أخطاء التحميل. على سبيل المثال، قد يحتاج أحد التطبيقات إلى تعذُّر إكماله بسرعة بدلاً من إعادة المحاولة عدة مرات، أو قد ترغب في تخصيص منطق التراجع الذي للتحكم في مدة انتظار اللاعب بين كل إعادة محاولة. المقتطف التالي كيفية تنفيذ منطق التراجع المخصص:

Kotlin

val loadErrorHandlingPolicy: LoadErrorHandlingPolicy =
  object : DefaultLoadErrorHandlingPolicy() {
    override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long {
      // Implement custom back-off logic here.
      return 0
    }
  }
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(
      DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
    )
    .build()

Java

LoadErrorHandlingPolicy loadErrorHandlingPolicy =
    new DefaultLoadErrorHandlingPolicy() {
      @Override
      public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) {
        // Implement custom back-off logic here.
        return 0;
      }
    };

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context)
                .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy))
        .build();

تحتوي الوسيطة LoadErrorInfo على مزيد من المعلومات حول عملية التحميل التي تعذّر تحميلها إلى تخصيص المنطق استنادًا إلى نوع الخطأ أو الطلب الذي تعذّر تنفيذه.

تخصيص علامات أداة الاستخراج

يمكن استخدام علامات أداة الاستخراج لتخصيص كيفية استخراج التنسيقات الفردية من الوسائط التقدّمية ويمكن ضبطها على DefaultExtractorsFactory الذي المقدَّمة إلى DefaultMediaSourceFactory. يقوم المثال التالي بتمرير علامة تتيح البحث عن فيديوهات بتنسيق MP3 استنادًا إلى الفهرس.

Kotlin

val extractorsFactory =
  DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING)
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory))
    .build()

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING);

ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory))
        .build();

تمكين التقديم المستمر لمعدل نقل البيانات

بالنسبة إلى أحداث بث MP3 وADTS وAMR، يمكنك تفعيل وضع "التقديم/الترجيع تقريبًا" باستخدام فرضية معدل نقل بيانات ثابت مع علامات FLAG_ENABLE_CONSTANT_BITRATE_SEEKING. يمكن ضبط هذه العلامات لأدوات استخلاص البيانات الفردية باستخدام أداة DefaultExtractorsFactory.setXyzExtractorFlags طريقة كما هو موضّح أعلاه. إلى تمكين البحث عن معدل نقل بيانات مستمر لجميع أدوات الاستخراج التي تتوافق معه، واستخدام DefaultExtractorsFactory.setConstantBitrateSeekingEnabled

Kotlin

val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);

ويمكن بعد ذلك إدخال ExtractorsFactory عبر DefaultMediaSourceFactory باسم الموضحة أعلاه لتخصيص علامات أداة الاستخراج.

تمكين قائمة انتظار المخزن المؤقت غير المتزامن

يُعد وضع المخزن المؤقت غير المتزامن تحسينًا في عرض ExoPlayer الذي يشغِّل MediaCodec في الوضع غير المتزامن سلاسل محادثات إضافية لجدولة فك ترميز البيانات وعرضها. جارٍ تفعيله إلى تقليل الإطارات المسقطة وحالات التشغيل دون تشغيل الصوت.

يتم تلقائيًا تفعيل خيار إضافة المخزن المؤقت غير المتزامن إلى قائمة الانتظار على الأجهزة التي تعمل بنظام التشغيل Android 12. (المستوى 31 من واجهة برمجة التطبيقات) والإصدارات الأحدث، ويمكن تفعيلها يدويًا بدءًا من Android 6.0 (المستوى 23 من واجهة برمجة التطبيقات). ننصحك بتفعيل هذه الميزة على أجهزة محدّدة لاحظت سقوطها في جهازك. اللقطات أو اللقطات الخالية من الصوت، خاصةً عند تشغيل المحتوى المحمي بموجب إدارة الحقوق الرقمية أو المعدّل العالي للقطات في الثانية المحتوى.

وفي أبسط الحالات، سيكون عليك إدخال DefaultRenderersFactory في على النحو التالي:

Kotlin

val renderersFactory = 
  DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing()
val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()

Java

DefaultRenderersFactory renderersFactory =
    new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing();
ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();

إذا كنت تنشئ مثيلاً لبرامج العرض مباشرةً، AsynchronousMediaCodecAdapter.Factory إلى MediaCodecVideoRenderer طرق الإنشاء MediaCodecAudioRenderer

استدعاء طريقة اعتراض باستخدام ForwardingPlayer

يمكنك تخصيص جزء من سلوك مثيل Player من خلال تضمينه في فئة فرعية من ForwardingPlayer مع إلغاء الطرق لتنفيذ أي من ما يلي:

  • الوصول إلى المعلمات قبل تمريرها إلى المفوَّض Player.
  • يمكنك الوصول إلى القيمة المعروضة من المستخدم المفوَّض Player قبل عرضها.
  • إعادة تطبيق الطريقة بالكامل.

عند إلغاء طُرق ForwardingPlayer، من المهم التأكّد من استمرار التنفيذ بذاته ومتوافقًا مع Player المستخدم، خاصةً عند التعامل مع الطرق التي تهدف إلى أو سلوك متطابق أو ذي صلة. مثلاً:

  • إذا كنت تريد إلغاء كل "تشغيل" العملية، فأنت بحاجة إلى إلغاء كليهما ForwardingPlayer.play وForwardingPlayer.setPlayWhenReady، لأن ويتوقع المتصل أن يكون سلوك هذه الطرق متطابقًا في حال playWhenReady = true
  • إذا أردت تغيير جزء التقديم والترجيع، عليك إلغاء الإجراءَين. ForwardingPlayer.seekForward لإجراء عملية بحث باستخدام وForwardingPlayer.getSeekForwardIncrement لإعداد تقرير الجزء المخصص الصحيح مرة أخرى إلى المتصل.
  • إذا أردت التحكّم في محتوى Player.Commands التي يعلن عنها أحد اللاعبين على سبيل المثال، يجب عليك إلغاء كل من Player.getAvailableCommands() Player.isCommandAvailable()، وكذلك الاستماع إلى معاودة الاتصال عبر Player.Listener.onAvailableCommandsChanged() لتلقّي إشعار التغييرات التي تحدث من المشغل الأساسي.

تخصيص مصدر الوسائط

تُدخل الأمثلة أعلاه مكونات مخصصة للاستخدام أثناء تشغيل جميع MediaItem من العناصر التي تم تمريرها إلى اللاعب. أين يوجد التخصيص الدقيق مطلوب، كما يمكن أيضًا إدخال مكونات مخصصة في MediaSource مثيل، ويمكن تمريرها مباشرةً إلى المشغّل المثال يمكنك الاطّلاع أدناه على كيفية تخصيص ProgressiveMediaSource لاستخدام نوع مخصّص DataSource.Factory وExtractorsFactory وLoadErrorHandlingPolicy:

Kotlin

val mediaSource =
  ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory)
    .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy)
    .createMediaSource(MediaItem.fromUri(streamUri))

Java

ProgressiveMediaSource mediaSource =
    new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory)
        .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy)
        .createMediaSource(MediaItem.fromUri(streamUri));

إنشاء مكونات مخصصة

توفّر المكتبة عمليات التنفيذ التلقائية للمكوّنات المدرَجة أعلاه هذه الصفحة لحالات الاستخدام الشائعة. يمكن لـ ExoPlayer استخدام هذه المكوّنات، ولكن قد تُصمم أيضًا لاستخدام عمليات تنفيذ مخصصة إذا كانت السلوكيات غير القياسية مطلوبة. في ما يلي بعض حالات الاستخدام لعمليات التنفيذ المخصّصة:

  • Renderer – ننصحك بتنفيذ Renderer مخصّصة لمعالجة لم يتم التوافق مع نوع الوسائط من خلال عمليات التنفيذ التلقائية التي يوفّرها المكتبة.
  • TrackSelector – يؤدي تنفيذ TrackSelector مخصّصة إلى السماح للتطبيق تغيير طريقة عرض المقاطع الصوتية التي يعرضها MediaSource المحددة للاستهلاك في كل من Renderer المتوفرة.
  • LoadControl – يؤدي تنفيذ LoadControl مخصّصة إلى السماح للتطبيق تغيير سياسة التخزين المؤقت لدى المشغّل.
  • Extractor – إذا كنت بحاجة إلى توافق تنسيق حاوية ليس حاليًا في المكتبة، ننصحك بتنفيذ فئة Extractor مخصّصة.
  • MediaSource – قد يكون تنفيذ فئة MediaSource مخصّصة إذا كنت تريد الحصول على عينات من وسائط خلاصة إلى أجهزة العرض في أو إذا أردت تطبيق تركيب MediaSource مخصّص السلوك.
  • MediaSource.Factory – تنفيذ MediaSource.Factory مخصّصة يسمح هذا الإذن لتطبيق ما بتخصيص طريقة إنشاء MediaSource. من MediaItem.
  • DataSource – تحتوي حزمة ExoPlayer الرئيسية على عدد من DataSource عمليات تنفيذ لحالات استخدام مختلفة قد ترغب في تنفيذ فئة DataSource لتحميل البيانات بطريقة أخرى، مثل أكثر من بروتوكول مخصص، باستخدام حزمة HTTP مخصصة أو من قاعدة ثابتة ذاكرة التخزين المؤقت.

عند إنشاء مكوّنات مخصَّصة، ننصح بما يلي:

  • إذا كان أحد المكوّنات المخصَّصة بحاجة إلى إبلاغ التطبيق بالأحداث مرة أخرى، ننصح بذلك استخدام النموذج نفسه المستخدم في مكونات ExoPlayer الحالية مثال: استخدام EventDispatcher صفوف أو اجتياز Handler مع أداة استماع للدالة الإنشائية للمكون.
  • ننصح باستخدام النموذج نفسه المستخدَم في ExoPlayer الحالي في المكوّنات المخصّصة. للسماح بإعادة تكوين التطبيق أثناء التشغيل. للقيام بذلك، يجب أن تنفذ المكونات المخصصة PlayerMessage.Target وتتلقى تغييرات الضبط في الطريقة handleMessage. يجب أن يكون رمز التطبيق اجتياز التغييرات في الإعدادات من خلال استدعاء طريقة createMessage لـ ExoPlayer، وتهيئة الرسالة وإرسالها إلى المكون باستخدام PlayerMessage.send جارٍ إرسال رسائل ليتم تسليمها في سلسلة محادثات التشغيل. يضمن تنفيذها بالترتيب مع أي عمليات أخرى قيد التقدم بشكل أفضل على اللاعب.