Transformations

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.