Media3 Transformer ব্যবহার করে একটি বেসিক ভিডিও এডিটিং অ্যাপ তৈরি করুন

Jetpack Media3-তে ট্রান্সফর্মার API-কে এমনভাবে ডিজাইন করা হয়েছে যাতে মিডিয়া এডিটিং পারফর্ম্যান্ট ও নির্ভরযোগ্য হয়। Transformer-এ বিভিন্ন অপারেশন করা যায়, যার মধ্যে রয়েছে:

  • ভিডিও ট্রিম, স্কেল ও রোটেট করে পরিবর্তন করা
  • ওভারলে ও ফিল্টারের মতো এফেক্ট যোগ করা
  • HDR এবং স্লো-মোশন ভিডিওর মতো বিশেষ ফর্ম্যাট প্রসেস করা
  • এডিট প্রয়োগ করার পরে মিডিয়া আইটেম এক্সপোর্ট করা হচ্ছে

এই পৃষ্ঠায় Transformer-এর মাধ্যমে কভার করা কিছু গুরুত্বপূর্ণ ব্যবহারের উদাহরণ দেখানো হয়েছে। আরও বিবরণের জন্য আপনি Media3 Transformer-এর সম্পূর্ণ গাইড দেখতে পারেন।

শুরু করুন

শুরু করতে, Jetpack Media3-এর ট্রান্সফর্মার, এফেক্ট ও সাধারণ মডিউলে ডিপেন্ডেন্সি যোগ করুন:

Kotlin

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 অবজেক্ট তৈরি করতে হবে না।

বিভিন্ন ফর্ম্যাটের মধ্যে ট্রান্সকোড করা

H.265/AVC ভিডিও এবং AAC অডিও আউটপুট পেতে কীভাবে Transformer অবজেক্ট কনফিগার করতে হয় তা নিম্নলিখিত কোড থেকে জানতে পারবেন:

Kotlin

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 ফর্ম্যাটে থাকলে, 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 ইনপুট ফর্ম্যাটের মতোই হয়। OpenGL টোন-ম্যাপার ব্যবহার করে SDR-এ HDR ইনপুট টোনম্যাপ করুন, যার অর্থ হল আউটপুট ফর্ম্যাট SDR-এ হবে।
সহায়তা FEATURE_HdrEditing ক্ষমতা সহ এনকোডার আছে এমন ডিভাইসের জন্য API লেভেল ৩১+ ভার্সনে কাজ করে। API লেভেল ২৯+ ভার্সনে কাজ করে।
সমস্যা কাজ না করলে, পরিবর্তে HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL ব্যবহার করার চেষ্টা করে। কাজ না করলে, ExportException দেখায়।

প্রয়োজনীয় এনকোডিং ক্ষমতা আছে এবং Android 13 (API লেভেল 33) বা তার পরবর্তী ভার্সনে চলে এমন ডিভাইসে, Transformer অবজেক্ট আপনাকে HDR ভিডিও এডিট করতে দেয়। Composition অবজেক্ট তৈরি করার সময় HDR_MODE_KEEP_HDR হল ডিফল্ট মোড, যেমন নিম্নলিখিত কোডে দেখানো হয়েছে:

Kotlin

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-এর সাথে এতে প্রয়োগ করার জন্য ট্রান্সফর্মেশন সংগ্রহ করে।

ভিডিও কাটছাঁট করা

ভিডিওর অবাঞ্ছিত অংশ সরাতে, MediaItem-এ ClippingConfiguration যোগ করে আপনি কাস্টম শুরু ও শেষ হওয়ার পজিশন সেট করতে পারবেন।

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

জাভা

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-এর ইনস্ট্যান্স তৈরি করুন, তারপর EditedMediaItem-এ Effects অবজেক্ট যোগ করুন।

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

জাভা

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

জাভা

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-এর মাধ্যমে, এক্সপোর্ট প্রসেস শুরু করার আগে আপনি মিডিয়া আইটেমে যোগ করা এফেক্ট প্রিভিউ করতে পারবেন। EditedMediaItem-এর জন্য একই Effect অবজেক্ট ব্যবহার করে, আপনার ExoPlayer ইনস্ট্যান্সে setVideoEffects() কল করুন।

Kotlin

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 সিকোয়েন্স ব্যবহার করে। নিচের উদাহরণে, আমরা DefaultRenderersFactory-এর buildAudioSink() পদ্ধতি ওভাররাইড করে এটি করি।

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

জাভা

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)

জাভা

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-এর সাথে একটি লিসনার অ্যাটাচ করতে পারেন যাতে সম্পূর্ণ হওয়া বা সমস্যার ইভেন্ট সম্পর্কে বিজ্ঞপ্তি পেতে পারেন।