Transcode between formats
You can specify the output audio and video formats you want to produce when building Transformer. For example, the following code shows how to configure Transformer to output H.264/AVC video and AAC audio:
Kotlin
Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H264) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build()
Java
new Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H264) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build();
If the input media format already matches the configurations for audio or video, Transformer automatically switches to transmuxing, that is, copying the compressed samples from the input container to the output container without modification. This avoids the computational cost and potential quality loss of decoding and re-encoding in the same format.
Remove audio or video
Remove audio or video using EditedMediaItem.Builder
, for example:
Kotlin
EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()
Java
new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();
Trim a clip
You can remove any media outside specified start and end timestamps by setting the clipping configuration on the input media item. For example, to produce a clip containing only the media between 10 seconds and 20 seconds:
Kotlin
val inputMediaItem = MediaItem.Builder() .setUri(uri) .setClippingConfiguration( ClippingConfiguration.Builder() .setStartPositionMs(10_000) .setEndPositionMs(20_000) .build()) .build()
Java
MediaItem inputMediaItem = new MediaItem.Builder() .setUri(uri) .setClippingConfiguration( new MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) .setEndPositionMs(20_000) .build()) .build();
Optimizing trims
To reduce the latency of trimming the beginning of a video, enable trim optimization.
Kotlin
Transformer.Builder(context) .experimentalSetTrimOptimizationEnabled(true) .build()
Java
new Transformer.Builder(context) .experimentalSetTrimOptimizationEnabled(true) .build();
This speeds up the export by decoding and re-encoding as little of the video as
possible, then stitching the re-encoded data with the rest of the original
video. The optimization relies on being able to stitch part of the input file
with newly-encoded output, which means that the encoder's output format and the
input format must be compatible. So, for example, if the file was originally
produced on a device with a different encoder implementation then it's likely
that it won't be possible to apply the optimization.
For the optimization to succeed, the encoder provided to Transformer via the
EncoderFactory
must have a level and profile compatible with the input format.
This optimization only works with single-asset MP4 input with no effects except
no op video effects and rotations divisible by 90 degrees. If the optimization
fails, Transformer automatically falls back to normal export, and reports the
outcome of the optimization in ExportResult.OptimizationResult
.
We are validating this functionality and expect it to become non-experimental in a later release.
Video edits
EditedMediaItems
have lists of audio processors and video effects to apply in
order. The library includes video effect implementations for common use cases,
or you can write custom effects and pass them in when building edited media
items.
You can rescale media, which can be useful to save on processing resources or bandwidth when dealing with very high resolution input, such as 4k or 8k video. For example, to scale proportionally to 480 pixels high:
Kotlin
EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects(Effects( /* audioProcessors= */ listOf(), /* videoEffects= */ listOf(Presentation.createForHeight(480)) )).build()
Java
new EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects(new Effects( /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ ImmutableList.of(Presentation.createForHeight(480)))) .build();
Alternatively, you can scale by a given factor, for example, to halve the size:
Kotlin
val editedMediaItem = EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects(Effects( /* audioProcessors= */ listOf(), /* videoEffects= */ listOf( ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build()) )).build()
Java
new EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects(new Effects( /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ ImmutableList.of( new ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build()))) .build();
You can configure rotation in the same way:
Kotlin
EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects(Effects( /* audioProcessors= */ listOf(), /* videoEffects= */ listOf( ScaleAndRotateTransformation.Builder() .setRotationDegrees(90f) .build()) )).build()
Java
new EditedMediaItem.Builder(MediaItem.fromUri(uri)) .setEffects(new Effects( /* audioProcessors= */ ImmutableList.of(), /* videoEffects= */ ImmutableList.of( new ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build()))) .build();
Custom video effects
The Effects
constructor accepts a list of audio and video effects to apply.
Internally, Transformer's effects framework converts the list of video effects
into a sequence of GL shader programs that are applied in order. In some cases,
the effects framework is able to apply multiple effects with one shader program.
For example, one shader program can apply multiple consecutive matrix
transformations, which improves efficiency and quality.
Video effects are also supported for preview in ExoPlayer, using
ExoPlayer.setVideoEffects
.
The demo app includes examples of custom video effects.
Audio edits
Audio effects are implemented by applying a sequence of AudioProcessor
instances to raw (PCM) audio. ExoPlayer supports passing audio processors to the
DefaultAudioSink.Builder
, which allows previewing audio edits.