تم تصميم واجهات برمجة التطبيقات Transformer في Jetpack Media3 لتعديل الوسائط. أداءً وموثوقًا به. يدعم المحول عددًا من العمليات، بما في ذلك:
- تعديل فيديو من خلال قطع الفيديو وتغيير حجمه وتدويره
- إضافة تأثيرات مثل العناصر المركّبة والفلاتر
- معالجة تنسيقات خاصة، مثل النطاق العالي الديناميكية (HDR) والفيديوهات بالتصوير البطيء
- تصدير ملف وسائط بعد تطبيق التعديلات
وتُطلعك هذه الصفحة على بعض حالات الاستخدام الرئيسية التي تتناولها المحوِّل. لمزيد من التفاصيل، يمكنك التوجه إلى الأدلّة الكاملة حول تحويل Media3:
البدء
للبدء، أضِف تبعية على وحدات "المحول" و"التأثير" و"الشائعة". في 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();
إذا كان تنسيق وسائط الإدخال مطابقًا لطلب تحويل الصوت أو فيديو، يتحول المحوّل تلقائيًا إلى التحويل، وهو نسخ العينات المضغوطة من حاوية الإدخال إلى حاوية الإخراج بدون التعديل. وهذا يتجنب التكلفة الحاسوبية وفقدان الجودة المحتمل فك الترميز وإعادة تشفيره بالتنسيق ذاته.
ضبط وضع النطاق العالي الديناميكية
إذا كان ملف وسائط الإدخال بتنسيق 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 . |
على الأجهزة المتوافقة مع إمكانات الترميز المطلوبة والتي تعمل بنظام التشغيل Android 13
(المستوى 33 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، تتيح لك عناصر Transformer
تعديل فيديوهات HDR.
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، يمكنك استخدام
MediaPipe FrameProcessor
لإرسال كل إطار من خلال مخطط 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
لتلقّي إشعارات بشأن أحداث الاكتمال أو الأخطاء.