Transformer API ใน Jetpack Media3 ออกแบบมาเพื่อการตัดต่อสื่อที่มีประสิทธิภาพและเชื่อถือได้ Transformer รองรับการดำเนินงานหลายอย่าง ดังนี้
- การแก้ไขวิดีโอด้วยการครอบตัด การปรับขนาด และการหมุน
- การเพิ่มเอฟเฟกต์ เช่น การวางซ้อนและฟิลเตอร์
- การประมวลผลรูปแบบพิเศษ เช่น 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
ตอนนี้คุณระบุไดเรกทอรี videoMimeType
และ audioMimetype
ได้แล้วโดยการตั้งค่าฟังก์ชันโดยไม่ต้องสร้างออบเจ็กต์ TransformationRequest
แปลงระหว่างรูปแบบ
โค้ดต่อไปนี้แสดงวิธีกำหนดค่าออบเจ็กต์ Transformer
ไปยังเอาต์พุตวิดีโอ H.265/AVC และเสียง AAC
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
หากไฟล์สื่ออินพุตอยู่ในรูปแบบ HDR คุณสามารถเลือกระหว่างโหมดต่างๆ 2-3 โหมดสำหรับวิธีที่ 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 | ปรับโทนสีอินพุต 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
ดังที่แสดงในโค้ดต่อไปนี้
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
ลงใน MediaItem
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
อินสแตนซ์ที่จะเปลี่ยนรูปแบบข้อมูลเสียงดิบ (PCM) เช่น คุณสามารถใช้ 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 จะช่วยให้คุณดูตัวอย่างเอฟเฟกต์ที่เพิ่มลงในรายการสื่อได้ก่อนที่จะเริ่มกระบวนการส่งออก ใช้ออบเจ็กต์ Effects
เดียวกันกับ EditedMediaItem
แล้วเรียกใช้ setVideoEffects()
ในอินสแตนซ์ ExoPlayer
Kotlin
val player = ExoPlayer.builder(context) .build() .also { exoPlayer -> exoPlayer.setMediaItem(inputMediaItem) exoPlayer.setVideoEffects(effects) exoPlayer.prepare() }
Java
ExoPlayer player = new ExoPlayer.builder(context).build(); player.setMediaItem(inputMediaItem); player.setVideoEffects(effects); exoPlayer.prepare();
นอกจากนี้ คุณยังดูตัวอย่างเอฟเฟกต์เสียงด้วย ExoPlayer ได้ด้วย เมื่อสร้างอินสแตนซ์ ExoPlayer
ให้ส่ง RenderersFactory
ที่กําหนดเองซึ่งกําหนดค่าโปรแกรมแสดงผลเสียงของโปรแกรมเล่นให้ส่งออกเสียงไปยัง AudioSink
ที่ใช้ลําดับ AudioProcessor
ในตัวอย่างด้านล่าง เราทำเช่นนี้โดยการลบล้างวิธี buildAudioSink()
ของ DefaultRenderersFactory
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
เพื่อรับการแจ้งเตือนเกี่ยวกับเหตุการณ์ที่เสร็จสมบูรณ์หรือข้อผิดพลาดได้ด้วย