Transformer API в Jetpack Media3 предназначены для эффективного и надежного редактирования медиафайлов. Transformer поддерживает ряд операций, в том числе:
- Изменение видео: обрезка, масштабирование и поворот.
- Добавление эффектов, например оверлеев и фильтров.
- Обработка видео в специальных форматах, например HDR и замедленной съемки.
- Экспорт мультимедийного объекта после применения изменений
На этой странице описаны некоторые из основных вариантов использования Transformer. Подробную информацию вы найдете в руководствах по Media3 Transformer.
Начать
Для начала добавьте зависимость от модулей Transformer, Effect и Common в Jetpack Media3:
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")
Яркий
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.
Перекодирование между форматами
В следующем коде показано, как настроить объект 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, вы можете выбрать один из нескольких различных режимов обработки информации HDR в 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 |
|
|---|---|---|
| Описание | Сохранить данные 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 вместе с преобразованиями, которые нужно к нему применить.
Как обрезать видео
Чтобы удалить ненужные части видео, вы можете задать время начала и окончания воспроизведения, добавив 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 вы можете посмотреть, как будут выглядеть эффекты, добавленные в мультимедийный объект, прежде чем начать экспорт. Используя те же объекты Effect, что и для EditedMediaItem, вызовите setVideoEffects() в экземпляре ExoPlayer.
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. В примере ниже мы делаем это, переопределяя метод 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, чтобы получать уведомления о завершении или ошибках.