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

API های 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 ، اکنون می توانید با تنظیم تابع بدون نیاز به ایجاد یک شی TransformationRequest ، فهرست videoMimeType و audioMimetype را مشخص کنید.

رمزگذاری بین فرمت ها

کد زیر نحوه پیکربندی یک شی 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 به طور خودکار به transmuxing تغییر می کند، یعنی نمونه های فشرده شده را از ظرف ورودی به محفظه خروجی بدون تغییر کپی می کند. این امر از هزینه محاسباتی و کاهش کیفیت بالقوه رمزگشایی و رمزگذاری مجدد در همان قالب جلوگیری می کند.

حالت 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 است. Tonemap ورودی HDR به SDR با استفاده از یک نقشه‌نگار تن OpenGL، به این معنی که فرمت خروجی در SDR خواهد بود.
پشتیبانی کنید در سطوح API 31+ برای دستگاه‌هایی که دارای رمزگذار با قابلیت FEATURE_HdrEditing هستند پشتیبانی می‌شود. در سطوح API 29+ پشتیبانی می شود.
خطاها اگر پشتیبانی نمی‌شود، سعی می‌کند به جای آن از HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL استفاده کند. اگر پشتیبانی نمی شود، ExportException می اندازد.

در دستگاه‌هایی که از قابلیت‌های رمزگذاری مورد نیاز پشتیبانی می‌کنند و Android 13 (سطح API 33) یا بالاتر را اجرا می‌کنند، اشیاء 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 ، می‌توانید از MediaPipe FrameProcessor برای ارسال هر فریم از طریق یک نمودار MediaPipe استفاده کنید. نمونه ای از این را در برنامه نمایشی Transformer مشاهده کنید.

پیش نمایش افکت ها

با ExoPlayer ، می‌توانید پیش‌نمایش افکت‌های اضافه‌شده به یک آیتم رسانه را قبل از شروع فرآیند صادرات مشاهده کنید. با استفاده از همان شیء Effects برای EditedMediaItem ، setVideoEffects() را در نمونه ExoPlayer خود فراخوانی کنید.

کاتلین

val player = ExoPlayer.builder(context)
    .build()
    .also { exoPlayer ->
        exoPlayer.setMediaItem(inputMediaItem)
        exoPlayer.setVideoEffects(effects)
        exoPlayer.prepare()
    }

جاوا

ExoPlayer player = new ExoPlayer.builder(context).build();
player.setMediaItem(inputMediaItem);
player.setVideoEffects(effects);
exoPlayer.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 خود متصل کنید تا از اتمام یا رخدادهای خطا مطلع شود.