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