139 lines
5.0 KiB
Markdown
139 lines
5.0 KiB
Markdown
---
|
||
title: Transforming media
|
||
---
|
||
|
||
The [Transformer API][] can be used to convert media streams. It takes an input
|
||
media stream, applies changes to it as configured by the app, and produces the
|
||
corresponding output file. The available transformations are:
|
||
|
||
* Track removal.
|
||
* Flattening of slow motion videos or, in other words, their conversion into
|
||
normal videos that retain the desired slow motion effects, but can be played
|
||
with a player that is not aware of slow motion video formats. The purpose of
|
||
this transformation is to make slow motion videos suitable for sharing with
|
||
other apps or uploading to a server.
|
||
|
||
## Starting a transformation ##
|
||
|
||
To transform media, you need to add the following dependency to your app’s
|
||
`build.gradle` file:
|
||
|
||
~~~
|
||
implementation 'com.google.android.exoplayer:exoplayer-transformer:2.X.X'
|
||
~~~
|
||
{: .language-gradle}
|
||
|
||
where `2.X.X` is your preferred ExoPlayer version.
|
||
|
||
You can then start a transformation by building a `Transformer` instance and
|
||
calling `startTransformation` on it. The code sample below starts a
|
||
transformation that removes the audio track from the input:
|
||
|
||
~~~
|
||
// Configure and create a Transformer instance.
|
||
Transformer transformer =
|
||
new Transformer.Builder(context)
|
||
.setRemoveAudio(true)
|
||
.setListener(transformerListener)
|
||
.build();
|
||
// Start the transformation.
|
||
transformer.startTransformation(inputMediaItem, outputPath);
|
||
~~~
|
||
{: .language-java}
|
||
|
||
Other parameters, such as the `MediaSource.Factory`, can be passed to the
|
||
builder.
|
||
|
||
`startTransformation` receives a `MediaItem` describing the input, and a path or
|
||
a `ParcelFileDescriptor` indicating where the output should be written. The
|
||
input can be a progressive or an adaptive stream, but the output is always a
|
||
progressive stream. For adaptive inputs, the highest resolution tracks are
|
||
always selected for the transformation. The input can be of any container format
|
||
supported by ExoPlayer (see the [Supported formats page][] for details), but the
|
||
output is always an MP4 file.
|
||
|
||
Multiple transformations can be executed sequentially with the same
|
||
`Transformer` instance, but concurrent transformations with the same instance
|
||
are not supported.
|
||
|
||
## Listening to events ##
|
||
|
||
The `startTransformation` method is asynchronous. It returns immediately and the
|
||
app is notified of events via the listener passed to the `Transformer` builder.
|
||
|
||
~~~
|
||
Transformer.Listener transformerListener =
|
||
new Transformer.Listener() {
|
||
@Override
|
||
public void onTransformationCompleted(MediaItem inputMediaItem) {
|
||
playOutput();
|
||
}
|
||
|
||
@Override
|
||
public void onTransformationError(MediaItem inputMediaItem, TransformationException e) {
|
||
displayError(e);
|
||
}
|
||
};
|
||
~~~
|
||
{: .language-java}
|
||
|
||
## Displaying progress updates ##
|
||
|
||
`Transformer.getProgress` can be called to query the current progress of a
|
||
transformation. The returned value indicates the progress state. If the progress
|
||
state is `PROGRESS_STATE_AVAILABLE` then the passed `ProgressHolder` will have
|
||
been updated with the current progress percentage. The snippet below
|
||
demonstrates how to periodically query the progress of a transformation, where
|
||
the `updateProgressInUi` method could be implemented to update a progress bar
|
||
displayed to the user.
|
||
|
||
~~~
|
||
transformer.startTransformation(inputMediaItem, outputPath);
|
||
ProgressHolder progressHolder = new ProgressHolder();
|
||
mainHandler.post(
|
||
new Runnable() {
|
||
@Override
|
||
public void run() {
|
||
@ProgressState int progressState = transformer.getProgress(progressHolder);
|
||
updateProgressInUi(progressState, progressHolder);
|
||
if (progressState != PROGRESS_STATE_NO_TRANSFORMATION) {
|
||
mainHandler.postDelayed(/* r= */ this, /* delayMillis= */ 500);
|
||
}
|
||
}
|
||
});
|
||
~~~
|
||
{: .language-java}
|
||
|
||
## Flattening slow motion videos ##
|
||
|
||
We define a slow motion video as a media stream whose metadata points to
|
||
sections of the stream that should be slowed during playback. Flattening is the
|
||
process of converting a slow motion video to a regular media format (for example
|
||
MP4) where the slow motion sections are played at the requested speed. The slow
|
||
motion metadata is removed, and the video and audio streams are modified so as
|
||
to produce the desired effect when the output is played with a standard player
|
||
(that is, a player that is not aware of slow motion formats).
|
||
|
||
To flatten slow motion streams, use the `setFlattenForSlowMotion` builder
|
||
method.
|
||
|
||
~~~
|
||
Transformer transformer =
|
||
new Transformer.Builder(context)
|
||
.setFlattenForSlowMotion(true)
|
||
.setListener(transformerListener)
|
||
.build();
|
||
transformer.startTransformation(inputMediaItem, outputPath);
|
||
~~~
|
||
{: .language-java}
|
||
|
||
This allows apps to support slow motion videos without having to worry about
|
||
handling these special formats. All they need to do is to store and play the
|
||
flattened version of the video instead of the original one.
|
||
|
||
Currently, Samsung's slow motion format is the only one supported.
|
||
|
||
[Transformer API]: {{ site.exo_sdk }}/transformer/Transformer.html
|
||
[Supported formats page]: {{ site.baseurl }}/supported-formats.html
|
||
|