Media3 Transformer를 사용하여 기본 동영상 편집 앱 만들기

Jetpack Media3의 Transformer API는 미디어 편집 높은 성능을 발휘하고 있습니다 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()

자바

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

입력 미디어 형식이 이미 오디오 변환 요청과 일치하는 경우 Transformer는 transmuxing으로 자동 전환되어 압축된 샘플을 입력 컨테이너에서 출력 컨테이너로 있습니다. 이를 통해 시스템의 전산 비용과 잠재적 품질 손실을 디코딩 및 다시 인코딩하는 데 사용됩니다.

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 톤 매퍼를 사용하여 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_HDRComposition 객체를 빌드할 때의 기본 모드입니다. 다음과 같습니다.

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을(를) 수집합니다. 적용할 변환과 함께 표시됩니다.

동영상 자르기

동영상에서 원하지 않는 부분을 삭제하려면 맞춤 시작 및 종료 시간을 설정하세요. MediaItemClippingConfiguration를 추가하여 위치를 조정합니다.

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 미디어 항목 위에 텍스트 또는 이미지 오버레이를 추가합니다.

오디오 효과에 사용할 오디오 효과음을 AudioProcessor 드림 원시 (PCM) 오디오 데이터를 변환하는 인스턴스입니다. 예를 들어 ChannelMixingAudioProcessor 오디오 채널을 믹싱하고 스케일링할 수 있습니다

이러한 효과를 사용하려면 효과 또는 오디오 프로세서의 인스턴스를 만들고 적용하려는 오디오 및 동영상 효과가 있는 Effects의 인스턴스 미디어 항목을 클릭한 다음 EditedMediaItemEffects 객체를 추가합니다.

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

효과의 동작을 추가로 맞춤설정하려면 다음을 구현합니다. GlShaderProgramqueueInputFrame() 메서드는 입력 프레임을 처리하는 데 사용됩니다. 예를 들어 머신러닝 기능을 활용하여 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()
    }

자바

ExoPlayer player = new ExoPlayer.builder(context).build();
player.setMediaItem(inputMediaItem);
player.setVideoEffects(effects);
exoPlayer.prepare();

ExoPlayer로 오디오 효과를 미리 볼 수도 있습니다. GCP 리소스를 ExoPlayer 인스턴스는RenderersFactory 오디오 렌더러를 추가하여 AudioSink AudioProcessor 시퀀스. 아래 예에서는 DefaultRenderersFactorybuildAudioSink() 메서드

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에 전달하여 완료 또는 오류 이벤트에 대한 알림을 받습니다.