Media3 Transformer का इस्तेमाल करके वीडियो एडिटिंग के लिए एक बेसिक ऐप्लिकेशन बनाएं

Jetpack Media3 में मौजूद Transformer API, मीडिया एडिटिंग को बेहतर और भरोसेमंद बनाने के लिए डिज़ाइन किए गए हैं. ट्रांसफ़ॉर्मर कई तरह के ऑपरेशन के साथ काम करता है. इनमें ये शामिल हैं:

  • वीडियो में बदलाव करना, जैसे कि उसे ट्रिम करना, उसका साइज़ बदलना, और उसे घुमाना
  • ओवरले और फ़िल्टर जैसे इफ़ेक्ट जोड़ना
  • एचडीआर और स्लो-मोशन वीडियो जैसे खास फ़ॉर्मैट को प्रोसेस करना
  • बदलाव लागू करने के बाद, मीडिया आइटम को एक्सपोर्ट करना

इस पेज पर, ट्रांसफ़ॉर्मर के इस्तेमाल के कुछ मुख्य उदाहरणों के बारे में बताया गया है. ज़्यादा जानकारी के लिए, Media3 Transformer से जुड़ी हमारी पूरी गाइड देखें.

शुरू करें

शुरू करने के लिए, Jetpack Media3 के Transformer, Effect, और Common मॉड्यूल पर डिपेंडेंसी जोड़ें:

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

Groovy

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

Java

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

अगर इनपुट मीडिया फ़ॉर्मैट, ऑडियो या वीडियो के लिए ट्रांसफ़ॉर्मेशन के अनुरोध से पहले से ही मैच करता है, तो ट्रांसफ़ॉर्मर अपने-आप ट्रांसमक्सिंग पर स्विच हो जाता है. इसका मतलब है कि कंप्रेस किए गए सैंपल को इनपुट कंटेनर से आउटपुट कंटेनर में कॉपी किया जाता है. इसके लिए, सैंपल में कोई बदलाव नहीं किया जाता. इससे, एक ही फ़ॉर्मैट में डिकोड और फिर से एन्कोड करने की कंप्यूटेशनल लागत और क्वालिटी में होने वाली संभावित कमी से बचा जा सकता है.

एचडीआर मोड सेट करना

अगर इनपुट मीडिया फ़ाइल एचडीआर फ़ॉर्मैट में है, तो 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
ब्यौरा एचडीआर डेटा को सुरक्षित रखना. इसका मतलब है कि एचडीआर आउटपुट फ़ॉर्मैट, एचडीआर इनपुट फ़ॉर्मैट जैसा ही हो. OpenGL टोन-मैपर का इस्तेमाल करके, एचडीआर इनपुट को एसडीआर में टोनमैप करना. इसका मतलब है कि आउटपुट फ़ॉर्मैट एसडीआर में होगा.
सहायता यह सुविधा, एपीआई लेवल 31 और इसके बाद के वर्शन वाले उन डिवाइसों पर काम करती है जिनमें FEATURE_HdrEditing की सुविधा वाला एन्कोडर शामिल है. यह एपीआई लेवल 29 और इसके बाद के वर्शन पर काम करता है.
गड़बड़ियां अगर यह काम नहीं करता है, तो HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL का इस्तेमाल करने की कोशिश की जाती है. अगर यह काम नहीं करता है, तो ExportException दिखाता है.

ज़रूरी एन्कोडिंग सुविधाओं के साथ काम करने वाले और Android 13 (एपीआई लेवल 33) या इसके बाद के वर्शन वाले डिवाइसों पर, Transformer ऑब्जेक्ट की मदद से एचडीआर वीडियो में बदलाव किया जा सकता है. Composition ऑब्जेक्ट बनाते समय, HDR_MODE_KEEP_HDR डिफ़ॉल्ट मोड होता है. इसे इस कोड में दिखाया गया है:

Kotlin

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

Java

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

Java

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 इंस्टेंस का क्रम जोड़ा जा सकता है. इससे रॉ (पीसीएम) ऑडियो डेटा में बदलाव होगा. उदाहरण के लिए, ऑडियो चैनलों को मिक्स और स्केल करने के लिए, ChannelMixingAudioProcessor का इस्तेमाल किया जा सकता है.

इन इफ़ेक्ट का इस्तेमाल करने के लिए, इफ़ेक्ट या ऑडियो प्रोसेसर का इंस्टेंस बनाएं. इसके बाद, मीडिया आइटम पर लागू किए जाने वाले ऑडियो और वीडियो इफ़ेक्ट के साथ Effects का इंस्टेंस बनाएं. इसके बाद, Effects ऑब्जेक्ट को EditedMediaItem में जोड़ें.

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

Java

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

Java

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

Java

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

Java

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)

Java

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 में लिसनर भी अटैच किया जा सकता है.