المحوّل في Jetpack Media3 يتيح تعديل مواد العرض الوسائطية وتحويلها وتصديرها على Android. توضّح هذه الصفحة كيفية ضبط عمليات التحويل الأساسية:
- تحويل الترميز وتغيير تنسيق الحاوية: يمكنك تحويل تنسيقات الصوت والفيديو، أو تجاوز إعادة الترميز من خلال نسخ نماذج الحاوية (تغيير تنسيق الحاوية).
- إزالة المسار: يمكنك إزالة المسارات الصوتية أو المرئية من الوسائط.
- القطع والتحسين: يمكنك قطع الوسائط حسب الطابع الزمني، مع توفّر خيارات لـ تصدير أسرع باستخدام قوائم التعديل بتنسيق MP4 وتحسين القطع.
- تأثيرات الفيديو: يمكنك تغيير حجم الفيديو أو تدويره أو تطبيق تأثيرات مخصّصة لبرنامج تظليل OpenGL، ويمكن أيضًا معاينتها في ExoPlayer.
- صورة: يمكنك تحويل الصور الثابتة إلى مقاطع فيديو بمدد مخصّصة ومعدّلات إطارات.
- معالجة الصوت: يمكنك ربط مثيلات
AudioProcessorلتعديل الصوت الخام.
تحويل الترميز بين التنسيقات
يمكنك تحديد تنسيقات الصوت والفيديو التي تريد إنتاجها عند إنشاء المحوّل. على سبيل المثال، يوضّح الرمز البرمجي التالي كيفية ضبط المحوّل لإنتاج فيديو بتنسيق H.264/AVC وصوت بتنسيق AAC:
Kotlin
Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H264) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build()
Java
new Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H264) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build();
إذا كان تنسيق الوسائط المُدخَلة يتطابق مع إعدادات الصوت أو الفيديو، ينتقل المحوّل تلقائيًا إلى تغيير تنسيق الحاوية، أي نسخ النماذج المضغوطة من حاوية الإدخال إلى حاوية الإخراج بدون تعديل. يساعد ذلك في تجنُّب التكلفة الحسابية وفقدان الجودة المحتمَلين الناتجَين عن فك الترميز وإعادة ترميز المحتوى بالتنسيق نفسه.
إزالة الصوت أو الفيديو
يمكنك إزالة الصوت أو الفيديو باستخدام EditedMediaItem.Builder، على سبيل المثال:
Kotlin
EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()
Java
new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();
قطع مقطع
يمكنك إزالة أي وسائط خارج الطابعَين الزمنيَين المحدّدَين للبدء والانتهاء من خلال ضبط إعدادات القطع على مادة العرض الوسائطية المُدخَلة. على سبيل المثال، لإنتاج مقطع يحتوي على الوسائط بين 10 ثوانٍ و20 ثانية فقط:
Kotlin
val inputMediaItem = MediaItem.Builder() .setUri(uri) .setClippingConfiguration( MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) .setEndPositionMs(20_000) .build() ) .build()
Java
MediaItem inputMediaItem = new MediaItem.Builder() .setUri(uri) .setClippingConfiguration( new MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) .setEndPositionMs(20_000) .build()) .build();
قوائم التعديل بتنسيق MP4
لإجراء عملية قطع أسرع، يتيح المحوّل استخدام قوائم التعديل بتنسيق MP4، ما يسمح بإجراء تعديلات أكثر فعالية "للقطع فقط" بدون إعادة ترميز الفيديو بالكامل. تستخدِم هذه الطريقة النماذج المرمَّزة الحالية و"إعلان ما قبل التشغيل" ضِمن قائمة التعديل، ما يطلب من المشغّل بدء التشغيل في نقطة معيّنة، وبالتالي تخطّي المقطع الأوّلي غير المرغوب فيه.
لإجراء تعديلات "القطع فقط" بشكل أسرع بكثير، يمكنك استدعاء experimentalSetMp4EditListTrimEnabled(true).
Kotlin
Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build()
Java
new Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build();
تحسين عمليات القطع
لتقليل وقت استجابة قطع بداية الفيديو، يمكنك تفعيل تحسين القطع.
Kotlin
Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build()
Java
new Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build();
يؤدي ذلك إلى تسريع عملية التصدير من خلال فك ترميز وإعادة ترميز أقل قدر ممكن من الفيديو، ثم دمج البيانات التي تمت إعادة ترميزها مع باقي الفيديو الأصلي. يعتمد التحسين على إمكانية دمج جزء من ملف الإدخال مع الإخراج الذي تم ترميزه حديثًا، ما يعني أنّه يجب أن يكون تنسيق إخراج برنامج الترميز وتنسيق الإدخال متوافقَين. على سبيل المثال، إذا تم إنتاج الملف في الأصل على جهاز يتضمّن برنامج ترميز مختلفًا، فمن المحتمل أنّه لن يكون من الممكن تطبيق التحسين.
لكي ينجح التحسين، يجب أن يتضمّن برنامج الترميز الذي يتم توفيره للمحوّل من خلال EncoderFactory مستوى وملفًا شخصيًا متوافقَين مع تنسيق الإدخال.
لا يعمل هذا التحسين إلا مع إدخال بتنسيق MP4 يتضمّن مادة عرض واحدة بدون أي تأثيرات باستثناء تأثيرات الفيديو التي لا تجري أي عملية والتدويرات القابلة للقسمة على 90 درجة. إذا تعذّر إجراء التحسين، يعود المحوّل تلقائيًا إلى عملية التصدير العادية، ويُبلغ عن نتيجة التحسين في ExportResult.OptimizationResult.
نحن بصدد التحقّق من هذه الوظيفة ونتوقّع أن تصبح غير تجريبية في إصدار لاحق.
التعديلات على الفيديوهات
تحتوي EditedMediaItems على قوائم بمعالِجات الصوت وتأثيرات الفيديو التي يجب تطبيقها بالترتيب. تتضمّن المكتبة عمليات تنفيذ لتأثيرات الفيديو لحالات الاستخدام الشائعة، أو يمكنك كتابة تأثيرات مخصّصة وتمريرها عند إنشاء مواد العرض الوسائطية المعدَّلة.
يمكنك تغيير حجم الوسائط، ما قد يكون مفيدًا لتوفير موارد المعالجة أو النطاق الترددي عند التعامل مع إدخال بدقة عالية جدًا، مثل فيديو بدقة 4K أو 8K. على سبيل المثال، لتغيير الحجم بشكل متناسب إلى 480 بكسل ارتفاعًا:
Kotlin
EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects( Effects( /* audioProcessors= */ listOf(), /* videoEffects= */ listOf(Presentation.createForHeight(480)), ) ) .build()
Java
new EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects( new Effects( /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ ImmutableList.of(Presentation.createForHeight(480)))) .build();
بدلاً من ذلك، يمكنك تغيير الحجم بعامل معيّن، على سبيل المثال، لتقليل الحجم إلى النصف:
Kotlin
val editedMediaItem = EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects( Effects( /* audioProcessors= */ listOf(), /* videoEffects= */ listOf( ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build() ), ) ) .build()
Java
new EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects( new Effects( /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ ImmutableList.of( new ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build()))) .build();
يمكنك ضبط التدوير بالطريقة نفسها:
Kotlin
EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects( Effects( /* audioProcessors= */ listOf(), /* videoEffects= */ listOf( ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build() ), ) ) .build()
Java
new EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects( new Effects( /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ ImmutableList.of( new ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build()))) .build();
تأثيرات الفيديو المخصّصة
يقبل منشئ Effects قائمة بتأثيرات الصوت والفيديو التي يجب تطبيقها.
داخليًا، يحوّل إطار عمل التأثيرات في المحوّل قائمة تأثيرات الفيديو إلى سلسلة من برامج تظليل GL التي يتم تطبيقها بالترتيب. في بعض الحالات، يمكن لإطار عمل التأثيرات تطبيق تأثيرات متعددة باستخدام برنامج تظليل واحد.
على سبيل المثال، يمكن لبرنامج تظليل واحد تطبيق عمليات تحويل متعددة للمصفوفة على التوالي، ما يحسّن الكفاءة والجودة.
تتوفّر أيضًا تأثيرات الفيديو للمعاينة في ExoPlayer، باستخدام ExoPlayer.setVideoEffects. للاطّلاع على مثال حول كيفية استخدام واجهة برمجة التطبيقات هذه، يمكنك الاطّلاع على
تطبيق العرض التوضيحي لـ التأثيرات.
يتضمّن تطبيق العرض التوضيحي أمثلة على تأثيرات الفيديو المخصّصة.
صورة
يتيح المحوّل استخدام الصور كمواد إدخال من خلال التعامل معها على أنّها مقاطع فيديو ثابتة. لضبط صورة كمصدر إدخال، اتّبِع الخطوات التالية:
أنشئ
MediaItemباستخدامMediaItem.Builder. حدِّد مدة عرض الصورة في الفيديو الناتج من خلال استدعاءsetImageDurationMs.أنشئ
EditedMediaItemيغلّفMediaItem. حدِّد عدد اللقطات في الثانية المستهدَف للفيديو المضمّن الذي تم إنشاؤه باستخدامEditedMediaItem.Builder#setFrameRate.
يوضّح المثال التالي كيفية ضبط إدخال صورة لإنشاء فيديو مدته 5 ثوانٍ بمعدّل 30 إطارًا في الثانية:
Kotlin
val imageMediaItem = MediaItem.Builder() .setUri(imageUri) .setImageDurationMs(5000) // 5 seconds .build() val editedImageItem = EditedMediaItem.Builder(imageMediaItem) .setFrameRate(30) // 30 frames per second .build()
Java
MediaItem imageMediaItem = new MediaItem.Builder() .setUri(imageUri) .setImageDurationMs(5000) // 5 seconds .build(); new EditedMediaItem.Builder(imageMediaItem) .setFrameRate(30) // 30 frames per second .build();
التعديلات على الصوت
يتم تنفيذ التأثيرات الصوتية من خلال تطبيق سلسلة من مثيلات AudioProcessor على الصوت الخام (PCM). يتيح ExoPlayer تمرير معالِجات الصوت إلى DefaultAudioSink.Builder، ما يسمح بمعاينة التعديلات على الصوت.