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