LiTr (pronounced "lai-tr") is a lightweight video/audio transformation tool which supports transcoding video and audio tracks with optional frame modification.
In its current iteration LiTr supports:
By default, LiTr uses Android MediaCodec stack for hardware accelerated decoding/encoding and OpenGL for rendering. It also uses MediaExtractor and MediaMuxer to read/write media.
Simply grab via Gradle:
implementation 'com.linkedin.android.litr:litr:1.5.7'
...or Maven:
<dependency>
<groupId>com.linkedin.android.litr</groupId>
<artifactId>litr</artifactId>
<version>1.5.7</version>
</dependency>
First, instantiate MediaTransformer
with a Context
that can access Uri
s you will be using for input and output. Most commonly, that will be an application context.
MediaTransformer mediaTransformer = new MediaTransformer(getApplicationContext());
Then simply call transform
method to transform your video:
mediaTransformer.transform(requestId,
sourceVideoUri,
targetVideoFilePath,
targetVideoFormat,
targetAudioFormat,
videoTransformationListener,
transformationOptions);
Few notable things related to transformation:
requestId
, it will be used when calling back on a listener, or needed when cancelling an ongoing transformationnull
target format means that you don't want to modify track(s) of that typeGlFilter
s in TransformationOptions
, which will be applied in orderBufferFilter
s in TransformationOptions
, which will be applied in ordertransform
multiple times, to queue transformation requestsTransformationOptions
MediaRange
in TransformationOptions
Ongoing transformation can be cancelled by calling cancel
with its requestId
:
mediaTransformer.cancel(requestId);
When you no longer need MediaTransformer
, please release it. Note that MediaTransformer
instance becomes unusable after you release it, you will have to instantiate a new one.
mediaTransformer.release();
When transformation fails, exception is not thrown, but rather provided in TransformationListener.onError
callback. LiTr defines its own exceptions for different scenarios. For API >= 23, LiTr exception will also contain MediaCodec.CodecException
as a cause.
When possible, transformation statistics will be provided in listener callbacks. Statistics include source and target track formats, codecs used and transformation result and time for each track.
By default, LiTr uses Android MediaCodec stack to do all media work, and OpenGl for rendering. But this is not set in stone.
At high level, LiTr breaks down transformation into five essential steps:
Each transformation step is performed by a component. Each component is abstracted as an interface:
MediaSource
Decoder
Renderer
Encoder
MediaTarget
When using your own component implementations, make sure that output of a component matches the expected input of a next component. For example, if you are using a custom Encoder
(AV1?), make sure it accepts whatever frame format Renderer
produces (GlSurface
, ByteBuffer
) and outputs what MediaTarget
expects as an input.
Custom components can be used in TrackTransform
s in below "low level" transform method:
transform(requestId,
List<TrackTransform> trackTransforms,
listener,
granularity)
This API allows defining components and parameters per media track, thus allowing track based operations, such as muxing/demuxing tracks, transcoding different tracks differently, changing track order, etc.
You can use custom filters to modify video/audio frames. If you are writing a custom video filter, implement GlFilter
interface to make extra OpenGL draw operations. If you need to change how source video frame is rendered onto a target video frame, implement GlFrameRender
interface. For audio filter, implement BufferFilter
.
LiTr now has 40 new GPU accelerated video filters ported from Mp4Composer-android and android-gpuimage projects. You can also create your own filter simply by configuring VideoFrameRenderFilter with your custom shader, with no extra coding!
All video/audio filters live in "filter pack" library, which is available via Gradle:
implementation 'com.linkedin.android.litr:litr-filters:1.5.7'
...or Maven:
<dependency>
<groupId>com.linkedin.android.litr</groupId>
<artifactId>litr-filters</artifactId>
<version>1.5.7</version>
</dependency>
You can pass in a list of filters when transforming a video or audio track. Keep in mind that filters will be applied in the order they are in the list, so ordering matters.
MediaTransformer
is very intentionally not a singleton, to allow easy mocking of it in unit tests. There is also MockMediaTransformer
for UI tests, which can synchronously "play back" a sequence of listener callbacks.
Core business logic in LiTr is well covered by unit tests. LiTr is designed to use dependency injection pattern, which makes it very easy to write JVM tests with mocked dependencies. We use Mockito framework for mocking.
LiTr comes with pretty useful demo app, which lets you transcode video/audio tracks with different parameters, in addition to providing sample code.
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
For the versions available, see the tags on this repository.
You can use snapshot builds to test the latest unreleased changes. A new snapshot is published after every merge to the main branch by the Deploy Snapshot Github Action workflow.
Just add the Sonatype snapshot repository to your Gradle scripts:
repositories {
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
You can find the latest snapshot version to use in the gradle.properties file.
See also the list of contributors who participated in this project.
This project is licensed under the BSD 2-Clause License - see the LICENSE file for details