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

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

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

এই পৃষ্ঠাটি ট্রান্সফরমার দ্বারা আচ্ছাদিত কিছু মূল ব্যবহারের ক্ষেত্রে আপনাকে নিয়ে যায়। আরও বিশদ বিবরণের জন্য আপনি মিডিয়া3 ট্রান্সফরমারের আমাদের সম্পূর্ণ গাইডগুলিতে যেতে পারেন।

এবার শুরু করা যাক

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

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

লাইব্রেরির আপনার পছন্দের সংস্করণের সাথে 1.4.0 প্রতিস্থাপন করা নিশ্চিত করুন। সর্বশেষ সংস্করণ দেখতে আপনি রিলিজ নোট উল্লেখ করতে পারেন.

গুরুত্বপূর্ণ ক্লাস

ক্লাস উদ্দেশ্য
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();

যদি ইনপুট মিডিয়া ফরম্যাট ইতিমধ্যেই অডিও বা ভিডিওর জন্য রূপান্তর অনুরোধের সাথে মিলে যায়, ট্রান্সফরমার স্বয়ংক্রিয়ভাবে ট্রান্সমক্সিং -এ স্যুইচ করে, অর্থাৎ, পরিবর্তন ছাড়াই ইনপুট কন্টেইনার থেকে আউটপুট কন্টেইনারে সংকুচিত নমুনাগুলি অনুলিপি করে। এটি একই বিন্যাসে ডিকোডিং এবং পুনরায় এনকোডিংয়ের কম্পিউটেশনাল খরচ এবং সম্ভাব্য মানের ক্ষতি এড়ায়।

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

প্রয়োজনীয় এনকোডিং ক্ষমতা সমর্থন করে এবং Android 13 (API স্তর 33) বা উচ্চতর চালায় এমন ডিভাইসগুলিতে 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();

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

মিডিয়া3 সাধারণ রূপান্তরের জন্য অনেকগুলি অন্তর্নির্মিত ভিডিও প্রভাব অন্তর্ভুক্ত করে, উদাহরণস্বরূপ:

ক্লাস প্রভাব
Presentation রেজোলিউশন বা আকৃতি অনুপাত দ্বারা মিডিয়া আইটেম স্কেল
ScaleAndRotateTransformation মিডিয়া আইটেমটিকে একটি গুণক দ্বারা স্কেল করুন এবং/অথবা মিডিয়া আইটেমটি ঘোরান৷
Crop মিডিয়া আইটেমটি একটি ছোট বা বড় ফ্রেমে ক্রপ করুন
OverlayEffect মিডিয়া আইটেমের উপরে একটি পাঠ্য বা চিত্র ওভারলে যোগ করুন

অডিও ইফেক্টের জন্য, আপনি AudioProcessor একটি ক্রম যুক্ত করতে পারেন যা কাঁচা (পিসিএম) অডিও ডেটাকে রূপান্তরিত করবে। উদাহরণস্বরূপ, আপনি অডিও চ্যানেলগুলিকে মিশ্রিত করতে এবং স্কেল করতে একটি ChannelMixingAudioProcessor ব্যবহার করতে পারেন।

এই প্রভাবগুলি ব্যবহার করতে, প্রভাব বা অডিও প্রসেসরের একটি উদাহরণ তৈরি করুন, আপনি মিডিয়া আইটেমটিতে যে অডিও এবং ভিডিও প্রভাবগুলি প্রয়োগ করতে চান তার সাথে Effects একটি উদাহরণ তৈরি করুন, তারপরে একটি EditedMediaItemEffects অবজেক্ট যুক্ত করুন৷

কোটলিন

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 গ্রাফের মাধ্যমে পাঠাতে। ট্রান্সফরমার ডেমো অ্যাপে এর একটি উদাহরণ দেখুন।

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

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 পাস করুন যা প্লেয়ারের অডিও রেন্ডারারগুলিকে একটি AudioSink অডিও আউটপুট করতে কনফিগার করে যা আপনার AudioProcessor ক্রম ব্যবহার করে৷ নীচের উদাহরণে, আমরা একটি 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 সাথে একজন শ্রোতাকে সংযুক্ত করতে পারেন যাতে সমাপ্তি বা ত্রুটির ঘটনা সম্পর্কে অবহিত করা যায়।