أخبار المنتجات

الإصدار 1.9.0 من Media3: الميزات الجديدة

مدّة القراءة: 6 دقائق
عرض الملف الشخصي لـ "كريستينا سيماكوفا"
Kristina Simakova مدير هندسي

تم طرح الإصدار 1.9.0 من Media3 بالإضافة إلى إصلاحات الأخطاء المعتادة وتحسينات الأداء، يحتوي الإصدار الأخير أيضًا على أربع وحدات جديدة أو تمت إعادة كتابتها إلى حد كبير:

  • media3-inspector - استخراج البيانات الوصفية والإطارات خارج نطاق التشغيل
  • media3-ui-compose-material3 - إنشاء واجهة مستخدم أساسية لتشغيل الوسائط باستخدام Material3 Compose في بضع خطوات فقط
  • media3-cast - التعامل تلقائيًا مع عمليات الانتقال بين البث والتشغيل على الجهاز
  • ‫media3-decoder-av1: تشغيل فيديوهات AV1 بشكل متّسق باستخدام أداة فك الترميز المُعاد كتابتها والمستندة إلى مكتبة dav1d

أضفنا أيضًا تحسينات على التخزين المؤقت وإدارة الذاكرة في PreloadManager، وقدّمنا العديد من عمليات التبسيط الجديدة في ExoPlayer وTransformer وMediaSession. 

يمنحك هذا الإصدار أيضًا إمكانية الوصول التجريبي الأول إلى CompositionPlayer لمعاينة تعديلات الوسائط.  


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

استخراج البيانات الوصفية والإطارات خارج نطاق التشغيل

هناك العديد من الحالات التي تريد فيها فحص الوسائط بدون بدء التشغيل. على سبيل المثال، قد تحتاج إلى رصد التنسيقات التي يحتوي عليها أو مدته، أو استرداد الصور المصغّرة.

تجمع وحدة media3-inspector الجديدة جميع الأدوات المساعدة لفحص الوسائط بدون تشغيلها في مكان واحد:

  • ‫MetadataRetriever لقراءة المدة والتنسيق والبيانات الوصفية الثابتة من MediaItem
  • ‫FrameExtractor للحصول على إطارات أو صور مصغّرة من ملف وسائط
  • ‫MediaExtractorCompat كبديل مباشر لفئة MediaExtractor في نظام Android الأساسي، للحصول على معلومات مفصّلة عن العيّنات في الملف.

يتبع كل من MetadataRetriever وFrameExtractor نمط AutoCloseable بسيط. يمكنك الاطّلاع على صفحات الدليل الجديدة لمزيد من التفاصيل.

suspend fun extractThumbnail(mediaItem: MediaItem) {

  FrameExtractor.Builder(context, mediaItem).build().use {

    val thumbnail = frameExtractor.getThumbnail().await()

  } 

}

يمكنك إنشاء واجهة مستخدم أساسية للوسائط في Material3 Compose ببضع خطوات بسيطة

في الإصدارات السابقة، بدأنا في توفير رمز ربط بين عناصر واجهة مستخدم Compose ومثيل Player. في الإصدار 1.9.0 من Media3، أضفنا وحدة جديدة media3-ui-compose-material3 تتضمّن أزرارًا وعناصر محتوى من Material3 منسَّقة بالكامل. وتتيح لك إنشاء واجهة مستخدم للوسائط في بضع خطوات فقط، مع توفير كل المرونة لتخصيص النمط المخصّص. إذا كنت تفضّل إنشاء نمط واجهة المستخدم الخاص بك، يمكنك استخدام الوحدات الأساسية التي تتولّى جميع عمليات التحديث والاتصال، ما يتيح لك التركيز فقط على تصميم عنصر في واجهة المستخدم. يُرجى الاطّلاع على صفحات الدليل الموسّع لوحدات واجهة مستخدم Compose.

نعمل أيضًا على توفير المزيد من مكوّنات Compose، مثل شريط تقديم/ترجيع مُعدّ مسبقًا، وبديل كامل وجاهز للاستخدام لـ PlayerView، بالإضافة إلى دمج الترجمة والإعلانات.

@Composable
fun SimplePlayerUI(player: Player, modifier: Modifier = Modifier) {
  Column(modifier) {
    ContentFrame(player)  // Video surface and shutter logic
    Row (Modifier.align(Alignment.CenterHorizontally)) {                 
      SeekBackButton(player)   // Simple controls
      PlayPauseButton(player)
      SeekForwardButton(player)
    }
  }
}

 

image.png

واجهة مستخدم بسيطة لمشغّل Compose مع عناصر جاهزة للاستخدام

التعامل تلقائيًا مع عمليات الانتقال بين عمليات التشغيل على جهاز Cast وعمليات التشغيل على الجهاز المحلي

تمت إعادة كتابة CastPlayer في وحدة media3-cast للتعامل تلقائيًا مع عمليات الانتقال بين التشغيل على الجهاز (على سبيل المثال، باستخدام ExoPlayer) والتشغيل عن بُعد باستخدام Cast.

عند إعداد MediaSession، ما عليك سوى إنشاء CastPlayer حول ExoPlayer وإضافة MediaRouteButton إلى واجهة المستخدم.

// MediaSession setup with CastPlayer 

val exoPlayer = ExoPlayer.Builder(context).build()

val castPlayer = CastPlayer.Builder(context).setLocalPlayer(exoPlayer).build()

val session = MediaSession.Builder(context, castPlayer).build()

// MediaRouteButton in UI 

@Composable fun UIWithMediaRouteButton() {

  MediaRouteButton()

}
image.png

دمج CastPlayer الجديد في تطبيق Media3 التجريبي للجلسات

تشغيل AV1 بشكل متّسق مع الإضافة المُعاد كتابتها استنادًا إلى dav1d

يحتوي الإصدار 1.9.0 على وحدة إضافة AV1 تمت إعادة كتابتها بالكامل استنادًا إلى مكتبة dav1d الشهيرة. 

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

دمج ميزتَي التخزين المؤقت وإدارة الذاكرة في PreloadManager

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

  1. دعم التخزين المؤقت : عند تحديد مدى التحميل المُسبق، يمكنك الآن اختيار PreloadStatus.specifiedRangeCached(0, 5000) كحالة مستهدَفة للعناصر التي تم تحميلها مسبقًا. سيؤدي ذلك إلى إضافة النطاق المحدّد إلى ذاكرة التخزين المؤقت على القرص بدلاً من تحميل البيانات إلى الذاكرة. وبذلك، يمكنك توفير نطاق أكبر بكثير من العناصر للتحميل المُسبَق، لأنّ العناصر البعيدة عن العنصر الحالي لم تعد بحاجة إلى شغل الذاكرة. يُرجى العِلم أنّ ذلك يتطلّب ضبط Cache في DefaultPreloadManager.Builder.
  2. إدارة الذاكرة تلقائيًا : عدّلنا أيضًا واجهة LoadControl للتعامل بشكل أفضل مع حالة التحميل المُسبَق، فأصبح بإمكانك الآن ضبط حدّ أقصى صريح للذاكرة لجميع العناصر التي تم تحميلها مُسبقًا في الذاكرة. ويبلغ الحدّ الأقصى التلقائي 144 ميغابايت، ويمكنك ضبطه في DefaultLoadControl.Builder. ستتوقف DefaultPreloadManager تلقائيًا عن التحميل المُسبق بعد بلوغ الحدّ الأقصى، وستُخلي تلقائيًا مساحة الذاكرة التي تشغلها العناصر ذات الأولوية المنخفضة إذا لزم الأمر.

الاعتماد على الإعدادات التلقائية الجديدة والمبسّطة في ExoPlayer

وكالعادة، أضفنا الكثير من التحسينات التدريجية إلى ExoPlayer أيضًا. على سبيل المثال لا الحصر:

  • كتم الصوت وإعادة الصوت: كانت لدينا طريقة setVolume، ولكننا أضفنا الآن طريقتَي mute وunmute لتسهيل استعادة مستوى الصوت السابق بدون تتبُّعه بنفسك.
  • رصد توقُّف المشغّل: في بعض الحالات النادرة، قد يتوقّف المشغّل في حالة تخزين مؤقت أو تشغيل بدون إحراز أي تقدّم، على سبيل المثال، بسبب مشاكل في برامج الترميز أو أخطاء في الإعدادات. سيشعر المستخدمون بالانزعاج، ولكن لن تظهر لك هذه المشاكل في إحصاءاتك. ولتوضيح ذلك بشكل أكبر، يعرض المشغّل الآن StuckPlayerException عند رصد حالة توقّف.
  • تفعيل قفل التنشيط تلقائيًا: كانت إدارة قفل التنشيط تتطلّب الموافقة في السابق، ما أدّى إلى صعوبة العثور على الحالات الاستثنائية التي يمكن أن يتأخّر فيها تقدّم التشغيل كثيرًا عند التشغيل في الخلفية. أصبحت هذه الميزة الآن اختيارية، لذا لا داعي للقلق بشأنها ويمكنك أيضًا إزالة جميع عمليات معالجة قفل التنشيط اليدوية المتعلقة بالتشغيل.
  • إعداد مبسّط لمنطق زر الترجمة والشرح: كان من الصعب تغيير TrackSelectionParameters ليصبح "تفعيل الترجمة أو إيقافها"، لذا أضفنا خيارًا منطقيًا بسيطًا selectTextByDefault لحالة الاستخدام هذه.

تبسيط إعدادات أزرار الوسائط المفضّلة في MediaSession

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

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

session.setMediaButtonPreferences(listOf(
    CommandButton.Builder(CommandButton.ICON_FAST_FORWARD) // choose an icon
      .setDisplayName(R.string.skip_forward)
      .setPlayerCommand(Player.COMMAND_SEEK_FORWARD) // choose an action 
      .build()
))
image.png

إعدادات أزرار الوسائط المفضّلة مع زر التقديم السريع

‫CompositionPlayer للمعاينة في الوقت الفعلي

يقدّم الإصدار 1.9.0 واجهة CompositionPlayer ضمن تعليق توضيحي جديد @ExperimentalApi. يشير التعليق التوضيحي إلى أنّ الميزة متاحة للتجربة، ولكنّها لا تزال قيد التطوير. 

‫CompositionPlayer هو مكوّن جديد في واجهات برمجة التطبيقات لتعديل Media3، وهو مصمَّم لمعاينة تعديلات الوسائط في الوقت الفعلي. تستند واجهة CompositionPlayer إلى واجهة Media3 Player المألوفة، وتتيح للمستخدمين الاطّلاع على التغييرات التي أجروها قبل بدء عملية التصدير. يستخدم هذا الخيار عنصر Composition نفسه الذي يتم تمريره إلى Transformer للتصدير، ما يسهّل سير عمل التعديل من خلال توحيد نموذج البيانات للمعاينة والتصدير.

ننصحك ببدء استخدام CompositionPlayer ومشاركة ملاحظاتك، ومتابعة المنشورات والتعديلات القادمة على المستندات للحصول على مزيد من التفاصيل.

‫InAppMuxer كمُضاعِف تلقائي في Transformer

يستخدم Transformer الآن InAppMp4Muxer كأداة دمج تلقائية لكتابة ملفات حاويات الوسائط. داخليًا، تعتمد واجهة برمجة التطبيقات InAppMp4Muxer على وحدة Muxer في Media3، ما يوفّر سلوكًا متّسقًا في جميع إصدارات واجهة برمجة التطبيقات. 

يُرجى العِلم أنّه على الرغم من أنّ Transformer لم يعُد يستخدم MediaMuxer في نظام Android الأساسي تلقائيًا، لا يزال بإمكانك تقديم FrameworkMuxer.Factory من خلال setMuxerFactory إذا كانت حالة الاستخدام تتطلّب ذلك.

واجهات برمجة تطبيقات جديدة لتعديل السرعة

يُبسّط الإصدار 1.9.0 واجهات برمجة التطبيقات الخاصة بتعديلات السرعة لتعديل الوسائط. لقد طرحنا طرقًا جديدة مباشرةً على EditedMediaItem.Builder للتحكّم في السرعة، ما يجعل واجهة برمجة التطبيقات أكثر سهولة في الاستخدام. يمكنك الآن تغيير سرعة مقطع من خلال استدعاء setSpeed(SpeedProvider provider) في EditedMediaItem.Builder:

val speedProvider = object : SpeedProvider {
    override fun getSpeed(presentationTimeUs: Long): Float {
        return speed
    }

    override fun getNextSpeedChangeTimeUs(timeUs: Long): Long {
        return C.TIME_UNSET
    }
}

EditedMediaItem speedEffectItem = EditedMediaItem.Builder(mediaItem)
    .setSpeed(speedProvider)
    .build()

يحلّ هذا النهج الجديد محلّ الطريقة السابقة لاستخدام Effects#createExperimentalSpeedChangingEffects()، والتي أوقفناها نهائيًا وسنزيلها في إصدار مستقبلي.

تقديم أنواع المقاطع الصوتية لـ EditedMediaItemSequence 

في الإصدار 1.9.0، يتطلّب EditedMediaItemSequence تحديد أنواع المقاطع الصوتية المطلوبة أثناء إنشاء التسلسل. يضمن هذا التغيير أن تكون معالجة المقاطع الصوتية أكثر وضوحًا وقوة في جميع أنحاء "التركيب". 

ويتم ذلك من خلال مُنشئ EditedMediaItemSequence.Builder جديد يقبل مجموعة من أنواع المسارات (مثل C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO). 

لتبسيط عملية الإنشاء، أضفنا طرقًا ثابتة جديدة لتسهيل الاستخدام:

  • EditedMediaItemSequence.withAudioFrom(List<EditedMediaItem>)
  • EditedMediaItemSequence.withVideoFrom(List<EditedMediaItem>)
  • thought EditedMediaItemSequence.withAudioAndVideoFrom(List<EditedMediaItem>)

ننصحك بالانتقال إلى الدالة الإنشائية الجديدة أو الطرق المريحة للحصول على تعريفات تسلسل أكثر وضوحًا وموثوقية.

مثال على إنشاء تسلسل فيديو فقط:

EditedMediaItemSequence videoOnlySequence =
    EditedMediaItemSequence.Builder(setOf(C.TRACK_TYPE_VIDEO))
        .addItem(editedMediaItem)
        .build()

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

متابعة القراءة