Commit 7bc1241e by Oliver Woodman

Reflect subtitle parsers.

parent 6082bb67
...@@ -31,18 +31,77 @@ import android.os.Looper; ...@@ -31,18 +31,77 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* A {@link TrackRenderer} for textual subtitles. The actual rendering of each line of text to a * A {@link TrackRenderer} for subtitles. Text is parsed from sample data using a
* suitable output (e.g. the display) is delegated to a {@link TextRenderer}. * {@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) @TargetApi(16)
public class TextTrackRenderer extends TrackRenderer implements Callback { public class TextTrackRenderer extends TrackRenderer implements Callback {
private static final int MSG_UPDATE_OVERLAY = 0; 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 Handler textRendererHandler;
private final TextRenderer textRenderer; private final TextRenderer textRenderer;
private final SampleSourceReader source; private final SampleSourceReader source;
...@@ -68,8 +127,8 @@ public class TextTrackRenderer extends TrackRenderer implements Callback { ...@@ -68,8 +127,8 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
* normally be the looper associated with the applications' main thread, which can be * 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 * 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. * 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 * @param subtitleParsers {@link SubtitleParser}s to parse text samples, in order of decreasing
* to render a subtitle, the one with the lowest index will be preferred. * priority. If omitted, the default parsers will be used.
*/ */
public TextTrackRenderer(SampleSource source, TextRenderer textRenderer, public TextTrackRenderer(SampleSource source, TextRenderer textRenderer,
Looper textRendererLooper, SubtitleParser... subtitleParsers) { Looper textRendererLooper, SubtitleParser... subtitleParsers) {
...@@ -77,7 +136,17 @@ public class TextTrackRenderer extends TrackRenderer implements Callback { ...@@ -77,7 +136,17 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
this.textRenderer = Assertions.checkNotNull(textRenderer); this.textRenderer = Assertions.checkNotNull(textRenderer);
this.textRendererHandler = textRendererLooper == null ? null this.textRendererHandler = textRendererLooper == null ? null
: new Handler(textRendererLooper, this); : 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(); formatHolder = new MediaFormatHolder();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment