Reflect subtitle parsers.

This commit is contained in:
Oliver Woodman 2015-07-21 09:59:22 +01:00
parent 6082bb6769
commit 7bc1241e06

View file

@ -31,18 +31,77 @@ import android.os.Looper;
import android.os.Message;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A {@link TrackRenderer} for textual subtitles. The actual rendering of each line of text to a
* suitable output (e.g. the display) is delegated to a {@link TextRenderer}.
* A {@link TrackRenderer} for subtitles. Text is parsed from sample data using a
* {@link SubtitleParser}. The actual rendering of each line of text is delegated to a
* {@link TextRenderer}.
* <p>
* If no {@link SubtitleParser} instances are passed to the constructor, the subtitle type will be
* detected automatically for the following supported formats:
*
* <ul>
* <li>WebVTT ({@link com.google.android.exoplayer.text.webvtt.WebvttParser})</li>
* <li>TTML
* ({@link com.google.android.exoplayer.text.ttml.TtmlParser})</li>
* <li>SubRip
* ({@link com.google.android.exoplayer.text.subrip.SubripParser})</li>
* <li>TX3G
* ({@link com.google.android.exoplayer.text.tx3g.Tx3gParser})</li>
* </ul>
*
* <p>To override the default parsers, pass one or more {@link SubtitleParser} instances to the
* constructor. The first {@link SubtitleParser} that returns {@code true} from
* {@link SubtitleParser#canParse(String)} will be used.
*/
@TargetApi(16)
public class TextTrackRenderer extends TrackRenderer implements Callback {
private static final int MSG_UPDATE_OVERLAY = 0;
/**
* Default parser classes in priority order. They are referred to indirectly so that it is
* possible to remove unused parsers.
*/
private static final List<Class<? extends SubtitleParser>> DEFAULT_PARSER_CLASSES;
static {
DEFAULT_PARSER_CLASSES = new ArrayList<>();
// Load parsers using reflection so that they can be deleted cleanly.
// Class.forName(<class name>) appears for each parser so that automated tools like proguard
// can detect the use of reflection (see http://proguard.sourceforge.net/FAQ.html#forname).
try {
DEFAULT_PARSER_CLASSES.add(
Class.forName("com.google.android.exoplayer.text.webvtt.WebvttParser")
.asSubclass(SubtitleParser.class));
} catch (ClassNotFoundException e) {
// Parser not found.
}
try {
DEFAULT_PARSER_CLASSES.add(
Class.forName("com.google.android.exoplayer.text.ttml.TtmlParser")
.asSubclass(SubtitleParser.class));
} catch (ClassNotFoundException e) {
// Parser not found.
}
try {
DEFAULT_PARSER_CLASSES.add(
Class.forName("com.google.android.exoplayer.text.subrip.SubripParser")
.asSubclass(SubtitleParser.class));
} catch (ClassNotFoundException e) {
// Parser not found.
}
try {
DEFAULT_PARSER_CLASSES.add(
Class.forName("com.google.android.exoplayer.text.tx3g.Tx3gParser")
.asSubclass(SubtitleParser.class));
} catch (ClassNotFoundException e) {
// Parser not found.
}
}
private final Handler textRendererHandler;
private final TextRenderer textRenderer;
private final SampleSourceReader source;
@ -68,8 +127,8 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
* normally be the looper associated with the applications' main thread, which can be
* obtained using {@link android.app.Activity#getMainLooper()}. Null may be passed if the
* renderer should be invoked directly on the player's internal rendering thread.
* @param subtitleParsers An array of available subtitle parsers. Where multiple parsers are able
* to render a subtitle, the one with the lowest index will be preferred.
* @param subtitleParsers {@link SubtitleParser}s to parse text samples, in order of decreasing
* priority. If omitted, the default parsers will be used.
*/
public TextTrackRenderer(SampleSource source, TextRenderer textRenderer,
Looper textRendererLooper, SubtitleParser... subtitleParsers) {
@ -77,7 +136,17 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
this.textRenderer = Assertions.checkNotNull(textRenderer);
this.textRendererHandler = textRendererLooper == null ? null
: new Handler(textRendererLooper, this);
this.subtitleParsers = Assertions.checkNotNull(subtitleParsers);
if (subtitleParsers == null || subtitleParsers.length == 0) {
subtitleParsers = new SubtitleParser[DEFAULT_PARSER_CLASSES.size()];
for (int i = 0; i < subtitleParsers.length; i++) {
try {
subtitleParsers[i] = DEFAULT_PARSER_CLASSES.get(i).newInstance();
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Unexpected error creating default parser", e);
}
}
}
this.subtitleParsers = subtitleParsers;
formatHolder = new MediaFormatHolder();
}