Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0d82da4

Browse files
committed
Add docs
1 parent 6927bc2 commit 0d82da4

File tree

2 files changed

+286
-7
lines changed

2 files changed

+286
-7
lines changed

README.md

+286-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,41 @@
11
# Transcoder
22

3-
This project is an improved fork of [ypresto/android-transcoder](https://github.com/ypresto/android-transcoder).
4-
Lots of changes were made, so the documentation must be rewritten. You can, however, take a look at the
5-
demo app which provides a working example of the new API.
3+
Transcodes and compresses video files into the MP4 format, with audio support.
64

75
```groovy
86
implementation 'com.otaliastudios:transcoder:0.4.0'
97
```
108

9+
This project is an improved fork of [ypresto/android-transcoder](https://github.com/ypresto/android-transcoder).
10+
It features a lot of improvements over the original project, including:
11+
12+
- Multithreading support
13+
- Various bugs fixed
14+
- Accept content:// Uris and other types of input
15+
- Real error handling instead of errors being thrown
16+
- Source project is over-conservative when choosing options that *might* not be supported. We prefer to try and let the codec fail
17+
- More convenient APIs for transcoding & choosing options
18+
- Do **not** perform transcoding if the source video already matches our options (configurable)
19+
- Expose internal logs through Logger (so they can be reported to e.g. Crashlytics)
20+
21+
Using Transcoder in the most basic form is pretty simple:
22+
23+
```java
24+
MediaTranscoder.into(filePath)
25+
.setDataSource(context, uri) // or...
26+
.setDataSource(filePath) // or...
27+
.setDataSource(fileDescriptor) // or...
28+
.setDataSource(dataSource)
29+
.setListener(new MediaTranscoder.Listener() {
30+
public void onTranscodeProgress(double progress) {}
31+
public void onTranscodeCompleted(int successCode) {}
32+
public void onTranscodeCanceled() {}
33+
public void onTranscodeFailed(@NonNull Throwable exception) {}
34+
}).transcode()
35+
```
36+
37+
Take a look at the demo app for a real example or keep reading below for documentation.
38+
1139
## Setup
1240

1341
This library requires API level 18 (Android 4.3, JELLY_BEAN_MR2) or later.
@@ -21,6 +49,261 @@ adding this line to your manifest file:
2149
In this case you should check at runtime that API level is at least 18, before
2250
calling any method here.
2351

52+
## DataSource
53+
54+
Starting a transcoding operation will require a source for our data, which is not necessarily
55+
a `File`. The `DataSource` objects will automatically take care about releasing streams / resources,
56+
which is convenient but it means that they can not be used twice.
57+
58+
### `UriDataSource`
59+
60+
The Android friendly source can be created with `new UriDataSource(context, uri)` or simply
61+
using `setDataSource(context, uri)` in the transcoding builder.
62+
63+
### `FileDescriptorDataSource`
64+
65+
A data source backed by a file descriptor. Use `new FileDescriptorDataSource(descriptor)` or
66+
simply `setDataSource(descriptor)` in the transcoding builder.
67+
68+
### `FilePathDataSource`
69+
70+
A data source backed by a file absolute path. Use `new FilePathDataSource(path)` or
71+
simply `setDataSource(path)` in the transcoding builder.
72+
73+
## Listening for events
74+
75+
Transcoding will happen on a background thread, but we will send updates through the `MediaTranscoder.Listener`
76+
interface, which can be applied when building the request:
77+
78+
```java
79+
MediaTranscoder.into(filePath)
80+
.setListenerHandler(handler)
81+
.setListener(new MediaTranscoder.Listener() {
82+
public void onTranscodeProgress(double progress) {}
83+
public void onTranscodeCompleted(int successCode) {}
84+
public void onTranscodeCanceled() {}
85+
public void onTranscodeFailed(@NonNull Throwable exception) {}
86+
})
87+
// ...
88+
```
89+
90+
All of the listener callbacks are called:
91+
92+
- If present, on the handler specified by `setListenerHandler()`
93+
- If it has a handler, on the thread that started the `transcode()` call
94+
- As a last resort, on the UI thread
95+
96+
### `onTranscodeProgress`
97+
98+
This simply sends a double indicating the current progress. The value is typically between 0 and 1,
99+
but can be a negative value to indicate that we are not able to compute progress (yet?).
100+
101+
This is the right place to update a ProgressBar, for example.
102+
103+
### `onTranscodeCanceled`
104+
105+
The transcoding operation was canceled. This can happen when the `Future` returned by `transcode()`
106+
is cancelled by the user.
107+
108+
### `onTranscodeFailed`
109+
110+
This can happen in a number of cases and is typically out of our control. Input options might be
111+
wrong, write permissions might be missing, codec might be absent, input file might be not supported
112+
or simply corrupted.
113+
114+
You can take a look at the `Throwable` being passed to know more about the exception.
115+
116+
### `onTranscodeCompleted`
117+
118+
Transcoding operation did succeed. The success code can be:
119+
120+
|Code|Meaning|
121+
|----|-------|
122+
|`MediaTranscoder.SUCCESS_TRANSCODED`|Transcoding was executed successfully. Transcoded file was written to the output path.|
123+
|`MediaTranscoder.SUCCESS_NOT_NEEDED`|Transcoding was not executed because it was considered **not needed** by the `Validator`.|
124+
125+
Keep reading [below](#validators) to know about `Validator`s.
126+
127+
## Validators
128+
129+
Validators tell the engine whether the transcoding process should start or not based on the status
130+
of the audio and video track.
131+
132+
```java
133+
MediaTranscoder.into(filePath)
134+
.setValidator(validator)
135+
// ...
136+
```
137+
138+
This can be used, for example, to:
139+
140+
- avoid transcoding when video resolution is already OK with our needs
141+
- avoid operating on files without an audio/video stream
142+
- avoid operating on files with an audio/video stream
143+
144+
Validators should implement the `validate(TrackStatus, TrackStatus)` and inspect the status for video
145+
and audio tracks. When `false` is returned, transcoding will complete with the `SUCCESS_NOT_NEEDED` status code.
146+
The TrackStatus enum contains the following values:
147+
148+
|Value|Meaning|
149+
|-----|-------|
150+
|`TrackStatus.ABSENT`|This track was absent in the source file.|
151+
|`TrackStatus.PASS_THROUGH`|This track is about to be copied as-is in the target file.|
152+
|`TrackStatus.COMPRESSING`|This track is about to be processed and compressed in the target file.|
153+
|`TrackStatus.REMOVING`|This track will be removed in the target file.|
154+
155+
The `TrackStatus` value depends on the [output strategy](#output-strategies) that was used.
156+
We provide a few validators that can be injected for typical usage.
157+
158+
### `DefaultValidator`
159+
160+
This is the default validator and it returns true when any of the track is `COMPRESSING` or `REMOVING`.
161+
In the other cases, transcoding is typically not needed so we abort the operation.
162+
163+
### `WriteAlwaysValidator`
164+
165+
This validator always returns true and as such will always write to target file, no matter the track status,
166+
presence of tracks and so on. For instance, the output container file might have no tracks.
167+
168+
### `WriteVideoValidator`
169+
170+
A Validator that gives priority to the video track. Transcoding will not happen if the video track does not need it,
171+
even if the audio track might need it. If reducing file size is your only concern, this can avoid compressing
172+
files that would not benefit so much from compressing the audio track only.
173+
174+
## Output Strategies
175+
176+
Output strategies return options for each track (audio or video) for the engine to understand **how**
177+
and **if** this track should be transcoded, and whether the whole process should be aborted.
178+
179+
```java
180+
MediaTranscoder.into(filePath)
181+
.setVideoOutputStrategy(videoStrategy)
182+
.setAudioOutputStrategy(audioStrategy)
183+
// ...
184+
```
185+
186+
The point of `OutputStrategy` is to inspect the input `android.media.MediaFormat` and return
187+
the output `android.media.MediaFormat`, filled with required options.
188+
189+
This library offers track specific strategies that help with audio and video options (see
190+
[Audio Strategies](#audio-strategies) and [Video Strategies](#video-strategies)).
191+
In addition, we have a few built-in strategies that can work for both audio and video:
192+
193+
### `PassThroughTrackStrategy`
194+
195+
An OutputStrategy that asks the encoder to keep this track as is, by returning the same input
196+
format. Note that this is risky, as the input track format might not be supported my the MP4 container.
197+
198+
This will set the `TrackStatus` to `TrackStatus.PASS_THROUGH`.
199+
200+
### `RemoveTrackStrategy`
201+
202+
An OutputStrategy that asks the encoder to remove this track from the output container, by returning null.
203+
For instance, this can be used as an audio strategy to remove audio from video/audio streams.
204+
205+
This will set the `TrackStatus` to `TrackStatus.REMOVING`.
206+
207+
## Audio Strategies
208+
209+
The default internal strategy for audio is a `DefaultAudioStrategy`, which converts the
210+
audio stream to AAC format with the specified number of channels.
211+
212+
```java
213+
MediaTranscoder.into(filePath)
214+
.setAudioOutputStrategy(DefaultAudioStrategy(1)) // or..
215+
.setAudioOutputStrategy(DefaultAudioStrategy(2)) // or..
216+
.setAudioOutputStrategy(DefaultAudioStrategy(DefaultAudioStrategy.AUDIO_CHANNELS_AS_IS))
217+
// ...
218+
```
219+
220+
Take a look at the source code to understand how to manage the `android.media.MediaFormat` object.
221+
222+
## Video Strategies
223+
224+
The default internal strategy for video is a `DefaultVideoStrategy`, which converts the
225+
video stream to AVC format and is very configurable. The class helps in defining an output size
226+
that matches the aspect ratio of the input stream size, which is a basic requirement for video strategies.
227+
228+
### Video Size
229+
230+
We provide helpers for common tasks:
231+
232+
```java
233+
DefaultVideoStrategy strategy;
234+
235+
// Sets an exact size. Of course this is risky if you don't read the input size first.
236+
strategy = DefaultVideoStrategy.exact(1080, 720).build()
237+
238+
// Keeps the aspect ratio, but scales down the input size with the given fraction.
239+
strategy = DefaultVideoStrategy.fraction(0.5F).build()
240+
241+
// Ensures that each video size is at most the given value - scales down otherwise.
242+
strategy = DefaultVideoStrategy.atMost(1000).build()
243+
244+
// Ensures that minor and major dimension are at most the given values - scales down otherwise.
245+
strategy = DefaultVideoStrategy.atMost(500, 1000).build()
246+
```
247+
248+
In fact, all of these will simply call `new DefaultVideoStrategy.Builder(resizer)` with a special
249+
resizer. We offer handy resizers:
250+
251+
|Name|Description|
252+
|----|-----------|
253+
|`ExactResizer`|Returns the dimensions passed to the constructor. Throws if aspect ratio does not match.|
254+
|`FractionResizer`|Reduces the input size by the given fraction (0..1).|
255+
|`AtMostResizer`|If needed, reduces the input size so that the "at most" constraints are matched. Aspect ratio is kept.|
256+
|`PassThroughResizer`|Returns the input size unchanged.|
257+
258+
You can also group resizers through `MultiResizer`, which applies resizers in chain:
259+
260+
```java
261+
// First scales down, then ensures size is at most 1000. Order matters!
262+
Resizer resizer = new MultiResizer()
263+
resizer.addResizer(new FractionResizer(0.5F))
264+
resizer.addResizer(new AtMostResizer(1000))
265+
```
266+
267+
This option is already available through the DefaultVideoStrategy builder, so you can do:
268+
269+
```java
270+
DefaultVideoStrategy strategy = new DefaultVideoStrategy.Builder()
271+
.addResizer(new FractionResizer(0.5F))
272+
.addResizer(new AtMostResizer(1000))
273+
.build()
274+
```
275+
276+
### Other options
277+
278+
You can configure the `DefaultVideoStrategy` with other options unrelated to the video size:
279+
280+
```java
281+
DefaultVideoStrategy strategy = new DefaultVideoStrategy.Builder()
282+
.bitRate(bitRate)
283+
.bitRate(DefaultVideoStrategy.BITRATE_UNKNOWN) // tries to estimate
284+
.frameRate(frameRate) // will be capped to the input frameRate
285+
.iFrameInterval(interval) // interval between I-frames in seconds
286+
.build()
287+
```
288+
289+
## Compatibility
290+
291+
As stated pretty much everywhere, **not all codecs/devices/manufacturers support all sizes/options**.
292+
This is a complex issue which is especially important for video strategies, as a wrong size can lead
293+
to a transcoding error or corrupted file.
294+
295+
Android platform specifies requirements for manufacturers through the [CTS (Compatibility test suite)](https://source.android.com/compatibility/cts).
296+
Only a few codecs and sizes are strictly required to work.
297+
298+
We collect common presets in the `DefaultVideoStrategies` class:
299+
300+
```java
301+
MediaTranscoder.into(filePath)
302+
.setVideoOutputStrategy(DefaultVideoStrategies.for720x1280()) // 16:9
303+
.setVideoOutputStrategy(DefaultVideoStrategies.for360x480()) // 4:3
304+
// ...
305+
```
306+
24307
## License
25308

26309
This project is licensed under Apache 2.0. It consists of improvements over

lib/src/main/java/com/otaliastudios/transcoder/engine/MediaTranscoderEngine.java

-4
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ public void setDataSource(DataSource dataSource) {
6868
mDataSource = dataSource;
6969
}
7070

71-
public ProgressCallback getProgressCallback() {
72-
return mProgressCallback;
73-
}
74-
7571
public void setProgressCallback(ProgressCallback progressCallback) {
7672
mProgressCallback = progressCallback;
7773
}

0 commit comments

Comments
 (0)