Commit 71d83f3e by Rik Heijdens

Caption lines as separate cues

parent 7cd94819
package com.google.android.exoplayer2.text.eia608;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.Assertions;
import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* A Builder for EIA-608 cues.
*/
/* package */ final class Eia608CueBuilder {
private static final int BASE_ROW = 15;
/**
* The caption string.
*/
private SpannableStringBuilder captionStringBuilder;
/**
* The caption styles to apply to the caption string.
*/
private HashMap<Integer, CharacterStyle> captionStyles;
/**
* The row on which the Cue should be displayed.
*/
private int row;
/**
* The indent of the cue - horizontal positioning.
*/
private int indent;
/**
* The setTabOffset offset for the cue.
*/
private int tabOffset;
public Eia608CueBuilder() {
row = BASE_ROW;
indent = 0;
tabOffset = 0;
captionStringBuilder = new SpannableStringBuilder();
captionStyles = new HashMap<>();
}
/**
* Sets the row for this cue.
* @param row the row to set.
*/
public void setRow(int row) {
Assertions.checkArgument(row >= 1 && row <= 15);
this.row = row;
}
public int getRow() {
return row;
}
/**
* Rolls up the Cue one row.
* @return true if rolling was possible.
*/
public boolean rollUp() {
if (row < 1) {
return false;
}
setRow(row - 1);
return true;
}
/**
* Sets the indent for this cue.
* @param indent an indent value, must be a multiple of 4 within the range [0,28]
*/
public void setIndent(int indent) {
Assertions.checkArgument(indent % 4 == 0 && indent <= 28);
this.indent = indent;
}
public void tab(int tabs) {
tabOffset += tabs;
}
/**
* Indents the cue position with amountOfTabs.
* @param tabOffset the amount of tabs the cue position should be indented.
*/
public void setTabOffset(int tabOffset) {
this.tabOffset = tabOffset;
}
/**
* Appends a character to the current Cue.
* @param character the character to append.
*/
public void append(char character) {
captionStringBuilder.append(character);
}
/**
* Removes the last character of the caption string.
*/
public void backspace() {
if (captionStringBuilder.length() > 0) {
captionStringBuilder.delete(captionStringBuilder.length() - 1, captionStringBuilder.length());
}
}
/**
* Opens a character style at the current cueIndex.
* Takes care of style priorities.
*
* @param style the style to set.
*/
public void setCharacterStyle(CharacterStyle style) {
int startIndex = getSpanStartIndex();
// Close all open spans of the same type, and add a new one.
if (style instanceof ForegroundColorSpan) {
// Setting a foreground color clears the italics style.
closeSpan(StyleSpan.class); // Italics is a style span.
}
closeSpan(style.getClass());
captionStyles.put(startIndex, style);
}
/**
* Closes all open spans of the spansToApply class.
* @param spansToClose the class of which the spans should be closed.
*/
private void closeSpan(Class<? extends CharacterStyle> spansToClose) {
for (Integer index : captionStyles.keySet()) {
CharacterStyle style = captionStyles.get(index);
if (spansToClose.isInstance(style)) {
if (index < captionStringBuilder.length()) {
captionStringBuilder.setSpan(style, index,
captionStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
captionStyles.remove(index);
}
}
}
/**
* Applies all currently opened spans to the SpannableStringBuilder.
*/
public void closeSpans() {
// Check if we have to do anything.
if (captionStyles.size() == 0) {
return;
}
for (Integer startIndex : captionStyles.keySet()) {
// There may be cases, e.g. when seeking where the startIndex becomes greater
// than what is actually in the string builder, in that case, just discard the span.
if (startIndex < captionStringBuilder.length()) {
CharacterStyle captionStyle = captionStyles.get(startIndex);
captionStringBuilder.setSpan(captionStyle, startIndex,
captionStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
captionStyles.remove(startIndex);
}
}
public Cue build() {
closeSpans();
float cueLine = 10 + (5.33f * row);
float cuePosition = 10 + (2.5f * indent);
cuePosition = (tabOffset * 2.5f) + cuePosition;
return new Cue(captionStringBuilder, Layout.Alignment.ALIGN_NORMAL, cueLine / 100, Cue.LINE_TYPE_FRACTION,
Cue.ANCHOR_TYPE_START, cuePosition / 100, Cue.TYPE_UNSET, Cue.DIMEN_UNSET);
}
private int getSpanStartIndex() {
return captionStringBuilder.length() > 0 ? captionStringBuilder.length() - 1 : 0;
}
public static List<Cue> buildCues(List<Eia608CueBuilder> builders) {
if (builders.isEmpty()) {
return Collections.emptyList();
}
LinkedList<Cue> cues = new LinkedList<>();
for (Eia608CueBuilder builder : builders) {
if (builder.captionStringBuilder.length() == 0) {
continue;
}
cues.add(builder.build());
}
return cues;
}
}
......@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.text.eia608;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.Subtitle;
import java.util.LinkedList;
import java.util.List;
/**
......@@ -25,9 +26,13 @@ import java.util.List;
*/
/* package */ final class Eia608Subtitle implements Subtitle {
private final List<Cue> cues;
private List<Cue> cues;
public Eia608Subtitle(List<Cue> cues) {
public Eia608Subtitle() {
cues = new LinkedList<>();
}
/* package */ void setCues(List<Cue> cues) {
this.cues = cues;
}
......
......@@ -15,6 +15,10 @@
*/
package com.google.android.exoplayer2.ui;
import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.Util;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
......@@ -30,9 +34,6 @@ import android.text.TextPaint;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import com.google.android.exoplayer2.text.CaptionStyleCompat;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.Util;
/**
* Paints subtitle {@link Cue}s.
......
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