تم تصميم واجهات برمجة تطبيقات Transformer في Jetpack Media3 لتحسين أداء تعديل الوسائط وتعزيز موثوقيته. يدعم المحوِّل عددًا من العمليات، من بينها:
- تعديل فيديو من خلال القطع والتكبير والتصغير والدوران
- إضافة تأثيرات، مثل العناصر المركّبة والفلاتر
- معالجة تنسيقات خاصة، مثل فيديوهات HDR والفيديوهات البطيئة
- تصدير ملف وسائط بعد تطبيق التعديلات
ترشدك هذه الصفحة إلى بعض حالات الاستخدام الرئيسية التي يشملها Transformer. لمزيد من التفاصيل، يمكنك الاطّلاع على الأدلّة الكاملة حول Media3 Transformer.
البدء
للبدء، يجب إضافة تبعية إلى الوحدات الخاصة بكل من Transformer وEffect وCommon في Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.4.1" implementation "androidx.media3:media3-effect:1.4.1" implementation "androidx.media3:media3-common:1.4.1"
احرص على استبدال 1.4.1
بالإصدار المفضّل من
المكتبة. يمكنك الرجوع إلى ملاحظات الإصدار لمعرفة أحدث إصدار.
الفئات المهمة
الفئة | الغرض |
---|---|
Transformer |
يمكنك بدء عمليات التحويل وإيقافها والاطّلاع على آخر المعلومات المتعلّقة بالتقدّم في عملية تحويل جارية. |
EditedMediaItem |
يمثّل عنصر وسائط يجب معالجته والتعديلات التي يجب تطبيقها عليه. |
Effects |
مجموعة من تأثيرات الصوت والفيديو |
ضبط الإخراج
باستخدام Transformer.Builder
، يمكنك الآن تحديد الدليل videoMimeType
وaudioMimetype
من خلال ضبط الدالة بدون الحاجة إلى إنشاء
كائن TransformationRequest
.
تحويل ترميز المحتوى بين التنسيقات
يوضِّح الرمز البرمجي التالي كيفية ضبط عنصر Transformer
لمخرجة فيديو بترميز H.265/AVC وصوت بترميز AAC:
Kotlin
val transformer = Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build()
Java
Transformer transformer = new Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build();
إذا كان تنسيق الوسائط المُدخلة يتطابق مع طلب التحويل للصوت أو الفيديو، ينتقل Transformer تلقائيًا إلى تحويل الترميز، أي نسخ عيّنات مضغوطة من حاوية الإدخال إلى حاوية الإخراج بدون تعديلها. فهذا يتجنب التكلفة الحاسوبية وفقدان الجودة المحتمل لفك الترميز وإعادة الترميز بالتنسيق نفسه.
ضبط وضع النطاق العالي الديناميكية
إذا كان ملف الوسائط المُدخل بتنسيق HDR، يمكنك الاختيار من بين عدة
أوضاع مختلفة لكيفية معالجة Transformer لمعلومات HDR. ربما تريد استخدام HDR_MODE_KEEP_HDR
أو HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
.
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
---|---|---|
الوصف | الحفاظ على بيانات HDR، ما يعني أنّ تنسيق إخراج HDR هو نفسه تنسيق إدخال HDR | يمكنك ضبط تنسيق HDR على تنسيق SDR باستخدام برنامج تحديد تدرّج ألوان OpenGL، ما يعني أنّ تنسيق الإخراج سيكون بتنسيق SDR. |
الدعم | تتوفّر هذه الميزة على مستويات واجهة برمجة التطبيقات 31 والإصدارات الأحدث للأجهزة التي تتضمّن برنامج ترميز مزوّدًا بإمكانية FEATURE_HdrEditing . |
تتوفّر هذه الميزة في الإصدارات 29 من واجهة برمجة التطبيقات والإصدارات الأحدث. |
الأخطاء | إذا لم يكن متوافقًا، يحاول استخدام HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL بدلاً منه. |
إذا لم يكن متوافقًا، يتم طرح ExportException . |
على الأجهزة التي تتيح إمكانات التشفير المطلوبة وتعمل بالإصدار 13 من نظام التشغيل Android
(المستوى 33 لواجهة برمجة التطبيقات) أو إصدار أحدث، تتيح لك عناصر Transformer
تعديل الفيديوهات بدقة عالية الديناميكية.
HDR_MODE_KEEP_HDR
هو الوضع التلقائي عند إنشاء عنصر Composition
،
كما هو موضّح في الرمز البرمجي التالي:
Kotlin
val composition = Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(HDR_MODE_KEEP_HDR) .build()
Java
Composition composition = new Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(Composition.HDR_MODE_KEEP_HDR) .build();
تحضير عنصر وسائط
يمثّل MediaItem
عنصرًا صوتيًا
أو فيديو في تطبيقك. يجمع EditedMediaItem
MediaItem
مع
عمليات التحويل التي سيتم تطبيقها عليه.
قطع فيديو
لإزالة أجزاء غير مرغوب فيها من الفيديو، يمكنك ضبط مواضع مخصّصة للبدء والنهاية
من خلال إضافة ClippingConfiguration
إلى MediaItem
.
Kotlin
val clippingConfiguration = MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build() val mediaItem = MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build()
Java
ClippingConfiguration clippingConfiguration = new MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build(); MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build();
استخدام التأثيرات المدمَجة
تتضمّن Media3 عددًا من تأثيرات الفيديو المدمجة للتحويلات الشائعة، مثل:
الفئة | التأثير |
---|---|
Presentation |
تغيير حجم عنصر الوسائط حسب درجة الدقة أو نسبة العرض إلى الارتفاع |
ScaleAndRotateTransformation |
تغيير حجم عنصر الوسائط من خلال مُضاعِف و/أو تدوير عنصر الوسائط |
Crop |
اقتصاص ملف الوسائط إلى إطار أصغر أو أكبر |
OverlayEffect |
إضافة نص أو صورة على سطح عنصر الوسائط |
بالنسبة إلى التأثيرات الصوتية، يمكنك إضافة تسلسل من
AudioProcessor
نماذج ستحوّل بيانات الصوت الأوّلية (PCM). على سبيل المثال، يمكنك استخدام
ChannelMixingAudioProcessor
لخلط قنوات الصوت وتغيير حجمها.
لاستخدام هذه التأثيرات، أنشئ مثيلًا للتأثير أو وحدة معالجة الصوت، ثم أنشئ مثيلًا لعنصر Effects
يتضمّن تأثيرات الصوت والفيديو التي تريد تطبيقها على ملف الوسائط، ثم أضِف عنصر Effects
إلى عنصر EditedMediaItem
.
Kotlin
val channelMixingProcessor = ChannelMixingAudioProcessor() val rotateEffect = ScaleAndRotateTransformation.Builder().setRotationDegrees(60f).build() val cropEffect = Crop(-0.5f, 0.5f, -0.5f, 0.5f) val effects = Effects(listOf(channelMixingProcessor), listOf(rotateEffect, cropEffect)) val editedMediaItem = EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build()
Java
ChannelMixingAudioProcessor channelMixingProcessor = new ChannelMixingAudioProcessor(); ScaleAndRotateTransformation rotateEffect = new ScaleAndRotateTransformation.Builder() .setRotationDegrees(60f) .build(); Crop cropEffect = new Crop(-0.5f, 0.5f, -0.5f, 0.5f); Effects effects = new Effects( ImmutableList.of(channelMixingProcessor), ImmutableList.of(rotateEffect, cropEffect) ); EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build();
إنشاء تأثيرات مخصّصة
من خلال توسيع نطاق التأثيرات المضمّنة في Media3، يمكنك إنشاء تأثيرات مخصّصة
خاصة بحالات الاستخدام. في المثال التالي، استخدِم الفئة الفرعية MatrixTransformation
لتكبير الفيديو لملء الإطار خلال الثانية الأولى من التشغيل:
Kotlin
val zoomEffect = MatrixTransformation { presentationTimeUs -> val transformationMatrix = Matrix() // Set the scaling factor based on the playback position val scale = min(1f, presentationTimeUs / 1_000f) transformationMatrix.postScale(/* x */ scale, /* y */ scale) transformationMatrix } val editedMediaItem = EditedMediaItem.Builder(inputMediaItem) .setEffects(Effects(listOf(), listOf(zoomEffect)) .build()
Java
MatrixTransformation zoomEffect = presentationTimeUs -> { Matrix transformationMatrix = new Matrix(); // Set the scaling factor based on the playback position float scale = min(1f, presentationTimeUs / 1_000f); transformationMatrix.postScale(/* x */ scale, /* y */ scale); return transformationMatrix; }; EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(inputMediaItem) .setEffects(new Effects(ImmutableList.of(), ImmutableList.of(zoomEffect))) .build();
لتخصيص سلوك أحد التأثيرات بشكل أكبر، نفِّذ GlShaderProgram
. تُستخدَم الطريقة
queueInputFrame()
لمعالجة إطارات الإدخال. على سبيل المثال، لاستفادة
من إمكانات تعلُّم الآلة في
MediaPipe، يمكنك استخدام
FrameProcessor
MediaPipe
لإرسال كل إطار من خلال رسم بياني في MediaPipe. يمكنك الاطّلاع على مثال على ذلك في
تطبيق Transformer التجريبي.
معاينة التأثيرات
باستخدام ExoPlayer، يمكنك معاينة المؤثرات
المُضافة إلى عنصر وسائط قبل بدء عملية التصدير. باستخدام كائن Effects
نفسه كما في EditedMediaItem
، يمكنك طلب setVideoEffects()
على مثيل ExoPlayer.
Kotlin
val player = ExoPlayer.builder(context) .build() .also { exoPlayer -> exoPlayer.setMediaItem(inputMediaItem) exoPlayer.setVideoEffects(effects) exoPlayer.prepare() }
Java
ExoPlayer player = new ExoPlayer.builder(context).build(); player.setMediaItem(inputMediaItem); player.setVideoEffects(effects); exoPlayer.prepare();
ويمكنك أيضًا معاينة التأثيرات الصوتية باستخدام ExoPlayer. عند إنشاء مثيل ExoPlayer
، عليك استخدام RenderersFactory
مخصّص لضبط أدوات عرض
الصوت في المشغّل لإخراج الصوت إلى AudioSink
يستخدم تسلسل AudioProcessor
. في المثال أدناه، نفعل ذلك من خلال إلغاء طريقة
buildAudioSink()
في DefaultRenderersFactory
.
Kotlin
val player = ExoPlayer.Builder(context, object : DefaultRenderersFactory(context) { override fun buildAudioSink( context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean ): AudioSink? { return DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode(if (enableOffload) { DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED } else { DefaultAudioSink.OFFLOAD_MODE_DISABLED }) .setAudioProcessors(arrayOf(channelMixingProcessor)) .build() } }).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context, new DefaultRenderersFactory(context) { @Nullable @Override protected AudioSink buildAudioSink( Context context, boolean enableFloatOutput, boolean enableAudioTrackPlaybackParams, boolean enableOffload ) { return new DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode( enableOffload ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED : DefaultAudioSink.OFFLOAD_MODE_DISABLED) .setAudioProcessors(new AudioProcessor[]{channelMixingProcessor}) .build(); } }).build();
بدء عملية تحويل
أخيرًا، أنشئ Transformer
لتطبيق تعديلاتك وبدء تصدير
عنصر الوسائط الناتج.
Kotlin
val transformer = Transformer.Builder(context) .addListener(listener) .build() transformer.start(editedMediaItem, outputPath)
Java
Transformer transformer = new Transformer.Builder(context) .addListener(listener) .build(); transformer.start(editedMediaItem, outputPath);
يمكنك أيضًا إلغاء عملية التصدير إذا لزم الأمر باستخدام الرمز
Transformer.cancel()
.
البحث عن تحديثات حول مستوى التقدّم
يعود Transformer.start
على الفور ويعمل بشكل غير متزامن. للاستعلام عن
التقدّم الحالي لعملية التحويل، اتصل بالرقم
Transformer.getProgress()
.
تأخذ هذه الطريقة ProgressHolder
، وإذا كانت حالة التقدّم متاحة،
أي إذا كانت الطريقة تعرض PROGRESS_STATE_AVAILABLE
، سيتم تعديل
ProgressHolder
المقدَّم باستخدام النسبة المئوية الحالية للتقدّم.
يمكنك أيضًا إرفاق مستمع بـ Transformer
لتلقّي إشعارات بشأن أحداث اكتمال أو خطأ.