تم تصميم Transformer APIs في Jetpack Media3 لتوفير أداء وموثوقية لتعديل الوسائط. يدعم المحول عددًا من العمليات، بما في ذلك:
- تعديل فيديو عن طريق قطعه وتغيير حجمه وتدويره
- إضافة تأثيرات مثل التراكبات والفلاتر
- معالجة تنسيقات خاصة مثل النطاق العالي الديناميكية (HDR) والفيديوهات بالتصوير البطيء
- تصدير عنصر وسائط بعد تطبيق التعديلات
ترشدك هذه الصفحة إلى بعض حالات الاستخدام الرئيسية التي تتناولها Transformer. للحصول على مزيد من التفاصيل، يمكنك الانتقال إلى أدلةنا الكاملة حول Media3 Transformer.
بدء
للبدء، أضف تبعية إلى المحول والتأثير والوحدات الشائعة في Jetpack Media3:
implementation "androidx.media3:media3-transformer:1.3.1" implementation "androidx.media3:media3-effect:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
احرص على استبدال 1.3.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)
إذا كان ملف وسائط الإدخال بتنسيق نطاق عالي الديناميكية (HDR)، يمكنك الاختيار بين بضعة أوضاع مختلفة لكيفية معالجة برنامج التحويل لمعلومات النطاق العالي الديناميكية (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) | ربط إدخال النطاق العالي الديناميكية على نطاق SDR باستخدام أداة ربط نغمات OpenGL، ما يعني أنّ تنسيق الإخراج سيكون بتنسيق SDR |
الدعم | تتوفّر هذه الميزة على المستويات 31 والإصدارات الأحدث من واجهة برمجة التطبيقات للأجهزة التي تتضمّن برنامج ترميز مع إمكانية FEATURE_HdrEditing . |
متوافق مع مستويات واجهة برمجة التطبيقات 29 والمستويات الأعلى. |
الأخطاء | إذا لم يكن الأمر كذلك، يمكنك محاولة استخدام HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL بدلاً من ذلك. |
وإذا لم يكن متوافقًا، يتم عرض الرمز ExportException . |
على الأجهزة التي تتيح إمكانات الترميز المطلوبة والتي تعمل بنظام التشغيل Android 13
(المستوى 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، يمكنك استخدام 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
لتلقّي إشعار بشأن أحداث الاكتمال أو الأخطاء.