ایجاد برنامه ویرایش ویدیو پایه بااستفاده از Media3 Transformer

میاناهای برنامه‌سازی کاربردی Transformer در Jetpack Media3 برای ویرایش رسانه با عملکرد بالا و قابل‌اطمینان طراحی شده‌اند. Transformer از تعدادی عملیات پشتیبانی می‌کند، ازجمله:

  • اصلاح ویدیو با برش، مقیاس‌بندی، و چرخش
  • افزودن جلوه‌هایی مثل رونهادها و فیلترها
  • پردازش قالب‌های خاص مثل HDR و ویدیو صحنه آهسته
  • صادر کردن فایل رسانه‌ای پس‌از اعمال ویرایش‌ها

این صفحه شما را با برخی‌از موارد استفاده کلیدی که Transformer پوشش می‌دهد آشنا می‌کند. برای جزئیات بیشتر می‌توانید به راهنماهای کامل ما درباره Media3 Transformer مراجعه کنید.

شروع کنید

برای شروع، وابستگی به ماژول‌های Transformer،‏ Effect، و Common در Jetpack Media3 اضافه کنید:

کاتلین

implementation("androidx.media3:media3-transformer:1.11.1")
implementation("androidx.media3:media3-effect:1.11.1")
implementation("androidx.media3:media3-common:1.11.1")

شیک

implementation "androidx.media3:media3-transformer:1.11.1"
implementation "androidx.media3:media3-effect:1.11.1"
implementation "androidx.media3:media3-common:1.11.1"

حتماً 1.11.1 را با نسخه ترجیحی‌تان از کتابخانه جایگزین کنید. برای دیدن جدیدترین نسخه، می‌توانید به یادداشت‌های انتشار مراجعه کنید.

کلاس‌های مهم

کلاس هدف
Transformer تبدیل‌ها را شروع و متوقف کنید و به‌روزرسانی‌های پیشرفت را در تبدیل درحال اجرا بررسی کنید.
EditedMediaItem نشان‌دهنده فایل رسانه‌ای برای پردازش و ویرایش‌های اعمال‌شده روی آن است.
Effects مجموعه‌ای از جلوه‌های صوتی و تصویری.

پیکربندی خروجی

با Transformer.Builder، اکنون می‌توانید videoMimeType و audioMimetype را مستقیماً با تنظیم تابع بدون نیاز به ایجاد شیء TransformationRequest مشخص کنید.

تراتبدیل بین قالب‌ها

کد زیر نحوه پیکربندی شیء Transformer را برای خروجی ویدیو H.265/AVC و صدای AAC نشان می‌دهد:

کاتلین

val transformer = Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H265)
    .setAudioMimeType(MimeTypes.AUDIO_AAC)
    .build()

جاوا

Transformer transformer = new Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H265)
    .setAudioMimeType(MimeTypes.AUDIO_AAC)
    .build();

اگر قالب رسانه ورودی ازقبل با درخواست تبدیل برای صدا یا ویدیو مطابقت داشته باشد، Transformer به‌طور خودکار به تبدیل محفظه تغییر می‌کند، یعنی نمونه‌های فشرده‌شده را بدون تغییر از محفظه ورودی به محفظه خروجی کپی می‌کند. این کار از هزینه محاسباتی و افت کیفیت احتمالی ناشی از رمزگشایی و رمزگذاری مجدد در همان قالب جلوگیری می‌کند.

تنظیم حالت HDR

اگر فایل رسانه ورودی در قالب HDR باشد، می‌توانید از بین چند حالت مختلف برای نحوه پردازش اطلاعات HDR توسط Transformer انتخاب کنید. احتمالاً می‌خواهید از 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 را بااستفاده از نگاشت‌گر رنگ OpenGL به SDR نگاشت رنگ می‌کند، یعنی قالب خروجی SDR خواهد بود.
پشتیبانی در سطح میانای برنامه‌سازی کاربردی ۳۱ و بالاتر برای دستگاه‌هایی که شامل رمزگذار با قابلیت FEATURE_HdrEditing هستند پشتیبانی می‌شود. در سطح‌های میانای برنامه‌سازی کاربردی ۲۹ و بالاتر پشتیبانی می‌شود.
خطاها اگر پشتیبانی نشود، تلاش می‌کند به‌جای آن از HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL استفاده کند. اگر پشتیبانی نشود، ExportException را برمی‌گرداند.

در دستگاه‌هایی که از قابلیت‌های کدبندی لازم پشتیبانی می‌کنند و Android نسخه ۱۳ (سطح میانای برنامه‌سازی کاربردی ۳۳) یا بالاتر را اجرا می‌کنند، اشیای Transformer به شما امکان می‌دهند ویدیوهای HDR را ویرایش کنید. HDR_MODE_KEEP_HDR حالت پیش‌فرض هنگام ساختن شیء Composition است، همان‌طور که در کد زیر نشان داده شده است:

کاتلین

val composition = Composition.Builder(
    ImmutableList.of(videoSequence))
    .setHdrMode(HDR_MODE_KEEP_HDR)
    .build()

جاوا

Composition composition = new Composition.Builder(
    ImmutableList.of(videoSequence))
    .setHdrMode(Composition.HDR_MODE_KEEP_HDR)
    .build();

آماده کردن فایل رسانه‌ای

MediaItem نشان‌دهنده یک مورد صوتی یا ویدیویی در برنامه شما است. EditedMediaItem یک MediaItem را همراه با تبدیل‌هایی که باید روی آن اعمال شود جمع‌آوری می‌کند.

برش دادن ویدیو

برای برداشتن بخش‌های ناخواسته ویدیو، می‌توانید با افزودن ClippingConfiguration به MediaItem، موقعیت‌های شروع و پایان سفارشی تنظیم کنید.

کاتلین

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()

جاوا

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 اضافه کنید.

کاتلین

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()

جاوا

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 برای بزرگ‌نمایی ویدیو استفاده کنید تا قاب را در ثانیه اول بازپخش پر کند:

کاتلین

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()

جاوا

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، می‌توانید جلوه‌های اضافه‌شده به فایل رسانه‌ای را قبل‌از شروع فرایند صادر کردن پیش‌دید کنید. بااستفاده از همان اشیاء Effect که برای EditedMediaItem استفاده کردید، setVideoEffects() را در نمونه ExoPlayer خود فراخوانی کنید.

کاتلین

val player = ExoPlayer.Builder(context)
    .build()
    .also { exoPlayer ->
        exoPlayer.setMediaItem(inputMediaItem)
        exoPlayer.setVideoEffects(listOf(zoomEffect))
        exoPlayer.prepare()
    }

جاوا

ExoPlayer player = new ExoPlayer.Builder(context).build();
player.setMediaItem(inputMediaItem);
player.setVideoEffects(ImmutableList.of(zoomEffect));
player.prepare();

همچنین می‌توانید جلوه‌های صوتی را با ExoPlayer پیش‌نمایش کنید. هنگام ساختن نمونه ExoPlayer، یک RenderersFactory سفارشی را ارسال کنید که پردازنده صوتی پخش‌کننده را برای خروجی صدا به یک AudioSink که از توالی AudioProcessor شما استفاده می‌کند پیکربندی کند. در مثال زیر، این کار را با لغو کردن روش buildAudioSink() از DefaultRenderersFactory انجام می‌دهیم.

کاتلین

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()

جاوا

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 ایجاد کنید تا ویرایش‌هایتان اعمال شود و صادر کردن فایل رسانه‌ای حاصل شروع شود.

کاتلین

val transformer = Transformer.Builder(context)
    .addListener(listener)
    .build()
transformer.start(editedMediaItem, outputPath)

جاوا

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 خود متصل کنید تا از رویدادهای تکمیل یا خطا مطلع شوید.