Jetpack Media3의 Transformer API는 미디어 편집을 실적이 우수하고 안정적으로 만들도록 설계되었습니다. 변환기는 다음을 비롯한 여러 작업을 지원합니다.
- 자르기, 크기 조절, 회전을 사용하여 동영상 수정
- 오버레이 및 필터와 같은 효과 추가
- HDR 및 슬로 모션 동영상과 같은 특수 형식 처리
- 수정사항을 적용한 후 미디어 항목 내보내기
이 페이지에서는 Transformer에서 다루는 몇 가지 주요 사용 사례를 안내합니다. 자세한 내용은 Media3 Transformer에 관한 전체 가이드를 참고하세요.
시작하기
시작하려면 Jetpack Media3의 Transformer, Effect, Common 모듈에 종속 항목을 추가합니다.
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
를 사용하면 TransformationRequest
객체를 만들 필요 없이 함수를 설정하여 videoMimeType
및 audioMimetype
디렉터리를 지정할 수 있습니다.
형식 간 트랜스코딩
다음 코드는 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 톤 매퍼를 사용하여 HDR 입력을 SDR로 톤 매핑합니다. 즉, 출력 형식은 SDR이 됩니다. |
지원 | FEATURE_HdrEditing 기능이 있는 인코더가 포함된 기기의 경우 API 수준 31 이상에서 지원됩니다. |
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()
자바
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 |
미디어 항목 위에 텍스트 또는 이미지 오버레이를 추가합니다. |
오디오 효과의 경우 원시 (PCM) 오디오 데이터를 변환하는 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()
자바
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
와 동일한 Effects
객체를 사용하여 ExoPlayer 인스턴스에서 setVideoEffects()
를 호출합니다.
Kotlin
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
인스턴스를 빌드할 때 AudioProcessor
시퀀스를 사용하는 AudioSink
에 오디오를 출력하도록 플레이어의 오디오 렌더러를 구성하는 맞춤 RenderersFactory
를 전달합니다. 아래 예에서는 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
에 리스너를 연결할 수도 있습니다.