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

Jetpack Media3-এর Transformer API-গুলো মিডিয়া সম্পাদনাকে কর্মক্ষম ও নির্ভরযোগ্য করার জন্য ডিজাইন করা হয়েছে। Transformer বিভিন্ন ধরনের অপারেশন সমর্থন করে, যার মধ্যে রয়েছে:

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

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

শুরু করুন

শুরু করার জন্য, Jetpack Media3-এর Transformer, Effect, এবং Common মডিউলগুলিতে একটি ডিপেন্ডেন্সি যোগ করুন:

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

আপনার পছন্দের লাইব্রেরি সংস্করণ দিয়ে 1.9.3 প্রতিস্থাপন করতে ভুলবেন না। সর্বশেষ সংস্করণটি জানতে আপনি রিলিজ নোট দেখতে পারেন।

গুরুত্বপূর্ণ শ্রেণী

শ্রেণী উদ্দেশ্য
Transformer রূপান্তর শুরু ও বন্ধ করুন এবং চলমান রূপান্তরের অগ্রগতির হালনাগাদ দেখুন।
EditedMediaItem এটি প্রক্রিয়াকরণযোগ্য একটি মিডিয়া আইটেম এবং তাতে প্রয়োগ করার জন্য সম্পাদনাগুলো উপস্থাপন করে।
Effects অডিও এবং ভিডিও ইফেক্টের একটি সংগ্রহ।

আউটপুট কনফিগার করুন

Transformer.Builder সাহায্যে, এখন আপনি TransformationRequest অবজেক্ট তৈরি না করেই ফাংশন সেট করার মাধ্যমে videoMimeType এবং audioMimetype ডিরেক্টরি নির্দিষ্ট করতে পারেন।

ফরম্যাটের মধ্যে ট্রান্সকোড করুন

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

কোটলিন

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

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

কোটলিন

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 যোগ করে নিজস্ব শুরু ও শেষের অবস্থান নির্ধারণ করতে পারেন।

কোটলিন

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

অন্তর্নির্মিত প্রভাব ব্যবহার করুন

মিডিয়া৩-এ সাধারণ রূপান্তরের জন্য বেশ কিছু অন্তর্নির্মিত ভিডিও এফেক্ট রয়েছে, যেমন:

শ্রেণী প্রভাব
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 গ্রাফের মধ্য দিয়ে পাঠাতে একটি MediaPipe FrameProcessor ব্যবহার করতে পারেন। Transformer ডেমো অ্যাপে এর একটি উদাহরণ দেখুন।

পূর্বরূপ প্রভাব

ExoPlayer ব্যবহার করে, আপনি এক্সপোর্ট প্রক্রিয়া শুরু করার আগে একটি মিডিয়া আইটেমে যোগ করা ইফেক্টগুলো প্রিভিউ করতে পারেন। EditedMediaItem এর জন্য ব্যবহৃত একই Effects অবজেক্টটি ব্যবহার করে, আপনার ExoPlayer ইনস্ট্যান্সে setVideoEffects() কল করুন।

কোটলিন

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 পাস করুন যা প্লেয়ারের অডিও রেন্ডারারগুলিকে কনফিগার করে, যাতে এটি আপনার AudioProcessor সিকোয়েন্স ব্যবহার করে একটি AudioSink এ অডিও আউটপুট করতে পারে। নীচের উদাহরণে, আমরা একটি DefaultRenderersFactory এর buildAudioSink() মেথড ওভাররাইড করে এটি করেছি।

কোটলিন

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 একটি লিসেনারও সংযুক্ত করতে পারেন।