API-интерфейсы Transformer в Jetpack Media3 разработаны для обеспечения высокой производительности и надежности при редактировании медиафайлов. Transformer поддерживает ряд операций, в том числе:
- Редактирование видео с помощью обрезки, масштабирования и поворота.
- Добавление эффектов, таких как наложения и фильтры.
- Обработка специальных форматов, таких как HDR и замедленное видео.
- Экспорт медиафайла после внесения изменений.
На этой странице описаны некоторые ключевые сценарии использования Transformer. Для получения более подробной информации вы можете обратиться к нашим полным руководствам по Media3 Transformer .
Начать
Для начала добавьте зависимость от модулей Transformer, Effect и Common из пакета Jetpack Media3:
Котлин
implementation("androidx.media3:media3-transformer:1.10.1")
implementation("androidx.media3:media3-effect:1.10.1")
implementation("androidx.media3:media3-common:1.10.1")
Классный
implementation "androidx.media3:media3-transformer:1.10.1"
implementation "androidx.media3:media3-effect:1.10.1"
implementation "androidx.media3:media3-common:1.10.1"
Обязательно замените 1.10.1 на предпочитаемую вами версию библиотеки. Актуальную версию можно найти в примечаниях к выпуску .
Важные классы
| Сорт | Цель |
|---|---|
Transformer | Запускать и останавливать преобразования, а также отслеживать ход выполнения текущих преобразований. |
EditedMediaItem | Представляет собой медиафайл для обработки и необходимые для него правки. |
Effects | Подборка аудио- и видеоэффектов. |
Настройте вывод
С помощью Transformer.Builder теперь можно напрямую указывать videoMimeType и audioMimetype , задавая соответствующие параметры функции, без необходимости создания объекта TransformationRequest .
Транскодирование между форматами
Приведенный ниже код показывает, как настроить объект Transformer для вывода видео в формате H.265/AVC и аудио в формате AAC:
Котлин
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-файла. | Преобразование входного сигнала 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 , как показано в следующем коде:
Котлин
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 .
Котлин
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 .
Котлин
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 , чтобы увеличить масштаб видео и заполнить кадр в течение первой секунды воспроизведения:
Котлин
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.
Котлин
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 .
Котлин
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 , чтобы применить внесенные изменения, и начните экспорт полученного медиафайла.
Котлин
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 обработчик событий, чтобы получать уведомления о завершении или об ошибках.