1--- 2title: Transforming media 3--- 4 5The [Transformer API][] can be used to convert media streams. It takes an input 6media stream, applies changes to it as configured by the app, and produces the 7corresponding output file. The available transformations are: 8 9* Track removal. 10* Flattening of slow motion videos or, in other words, their conversion into 11 normal videos that retain the desired slow motion effects, but can be played 12 with a player that is not aware of slow motion video formats. The purpose of 13 this transformation is to make slow motion videos suitable for sharing with 14 other apps or uploading to a server. 15 16## Starting a transformation ## 17 18To transform media, you need to add the following dependency to your app’s 19`build.gradle` file: 20 21~~~ 22implementation 'com.google.android.exoplayer:exoplayer-transformer:2.X.X' 23~~~ 24{: .language-gradle} 25 26where `2.X.X` is your preferred ExoPlayer version. 27 28You can then start a transformation by building a `Transformer` instance and 29calling `startTransformation` on it. The code sample below starts a 30transformation that removes the audio track from the input: 31 32~~~ 33// Configure and create a Transformer instance. 34Transformer transformer = 35 new Transformer.Builder(context) 36 .setRemoveAudio(true) 37 .addListener(transformerListener) 38 .build(); 39// Start the transformation. 40transformer.startTransformation(inputMediaItem, outputPath); 41~~~ 42{: .language-java} 43 44Other parameters, such as the `MediaSource.Factory`, can be passed to the 45builder. 46 47`startTransformation` receives a `MediaItem` describing the input, and a path or 48a `ParcelFileDescriptor` indicating where the output should be written. The 49input can be a progressive or an adaptive stream, but the output is always a 50progressive stream. For adaptive inputs, the highest resolution tracks are 51always selected for the transformation. The input can be of any container format 52supported by ExoPlayer (see the [Supported formats page][] for details), but the 53output is always an MP4 file. 54 55Multiple transformations can be executed sequentially with the same 56`Transformer` instance, but concurrent transformations with the same instance 57are not supported. 58 59## Listening to events ## 60 61The `startTransformation` method is asynchronous. It returns immediately and the 62app is notified of events via the listener passed to the `Transformer` builder. 63 64~~~ 65Transformer.Listener transformerListener = 66 new Transformer.Listener() { 67 @Override 68 public void onTransformationCompleted(MediaItem inputMediaItem, TransformationResult transformationResult) { 69 playOutput(); 70 } 71 72 @Override 73 public void onTransformationError(MediaItem inputMediaItem, TransformationException e) { 74 displayError(e); 75 } 76 }; 77~~~ 78{: .language-java} 79 80## Displaying progress updates ## 81 82`Transformer.getProgress` can be called to query the current progress of a 83transformation. The returned value indicates the progress state. If the progress 84state is `PROGRESS_STATE_AVAILABLE` then the passed `ProgressHolder` will have 85been updated with the current progress percentage. The snippet below 86demonstrates how to periodically query the progress of a transformation, where 87the `updateProgressInUi` method could be implemented to update a progress bar 88displayed to the user. 89 90~~~ 91transformer.startTransformation(inputMediaItem, outputPath); 92ProgressHolder progressHolder = new ProgressHolder(); 93mainHandler.post( 94 new Runnable() { 95 @Override 96 public void run() { 97 @ProgressState int progressState = transformer.getProgress(progressHolder); 98 updateProgressInUi(progressState, progressHolder); 99 if (progressState != PROGRESS_STATE_NO_TRANSFORMATION) { 100 mainHandler.postDelayed(/* r= */ this, /* delayMillis= */ 500); 101 } 102 } 103 }); 104~~~ 105{: .language-java} 106 107## Flattening slow motion videos ## 108 109We define a slow motion video as a media stream whose metadata points to 110sections of the stream that should be slowed during playback. Flattening is the 111process of converting a slow motion video to a regular media format (for example 112MP4) where the slow motion sections are played at the requested speed. The slow 113motion metadata is removed, and the video and audio streams are modified so as 114to produce the desired effect when the output is played with a standard player 115(that is, a player that is not aware of slow motion formats). 116 117To flatten slow motion streams, use the `setFlattenForSlowMotion` builder 118method. 119 120~~~ 121Transformer transformer = 122 new Transformer.Builder(context) 123 .setFlattenForSlowMotion(true) 124 .addListener(transformerListener) 125 .build(); 126transformer.startTransformation(inputMediaItem, outputPath); 127~~~ 128{: .language-java} 129 130This allows apps to support slow motion videos without having to worry about 131handling these special formats. All they need to do is to store and play the 132flattened version of the video instead of the original one. 133 134Currently, Samsung's slow motion format is the only one supported. 135 136[Transformer API]: {{ site.exo_sdk }}/transformer/Transformer.html 137[Supported formats page]: {{ site.baseurl }}/supported-formats.html 138 139