mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Improvements for 608 positioning
- Infer likely left/center/right alignment for pop-on captions. This makes the rendering much better in practice, particularly when the captions were intended to be center aligned. - Fix line anchoring. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=141156222
This commit is contained in:
parent
88c0695bd0
commit
e86bfd6dbe
@ -95,10 +95,22 @@ public class Cue {
|
|||||||
* <p>
|
* <p>
|
||||||
* {@link #LINE_TYPE_NUMBER} indicates that {@link #line} is a line number, where the size of each
|
* {@link #LINE_TYPE_NUMBER} indicates that {@link #line} is a line number, where the size of each
|
||||||
* line is taken to be the size of the first line of the cue. When {@link #line} is greater than
|
* line is taken to be the size of the first line of the cue. When {@link #line} is greater than
|
||||||
* or equal to 0, lines count from the start of the viewport (the first line is numbered 0). When
|
* or equal to 0 lines count from the start of the viewport, with 0 indicating zero offset from
|
||||||
* {@link #line} is negative, lines count from the end of the viewport (the last line is numbered
|
* the start edge. When {@link #line} is negative lines count from the end of the viewport, with
|
||||||
* -1). For horizontal text the size of the first line of the cue is its height, and the start
|
* -1 indicating zero offset from the end edge. For horizontal text the line spacing is the height
|
||||||
* and end of the viewport are the top and bottom respectively.
|
* of the first line of the cue, and the start and end of the viewport are the top and bottom
|
||||||
|
* respectively.
|
||||||
|
* <p>
|
||||||
|
* Note that it's particularly important to consider the effect of {@link #lineAnchor} when using
|
||||||
|
* {@link #LINE_TYPE_NUMBER}. {@code (line == 0 && lineAnchor == ANCHOR_TYPE_START)} positions a
|
||||||
|
* (potentially multi-line) cue at the very top of the viewport.
|
||||||
|
* {@code (line == -1 && lineAnchor == ANCHOR_TYPE_END)} positions a (potentially multi-line) cue
|
||||||
|
* at the very bottom of the viewport. {@code (line == 0 && lineAnchor == ANCHOR_TYPE_END)}
|
||||||
|
* and {@code (line == -1 && lineAnchor == ANCHOR_TYPE_START)} position cues entirely outside of
|
||||||
|
* the viewport. {@code (line == 1 && lineAnchor == ANCHOR_TYPE_END)} positions a cue so that only
|
||||||
|
* the last line is visible at the top of the viewport.
|
||||||
|
* {@code (line == -2 && lineAnchor == ANCHOR_TYPE_START)} position a cue so that only its first
|
||||||
|
* line is visible at the bottom of the viewport.
|
||||||
*/
|
*/
|
||||||
@LineType
|
@LineType
|
||||||
public final int lineType;
|
public final int lineType;
|
||||||
|
@ -404,14 +404,18 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
|
|
||||||
// cc2 - 0|1|N|ATTRBTE|U
|
// cc2 - 0|1|N|ATTRBTE|U
|
||||||
// N is the next row down toggle, ATTRBTE is the 4-byte encoded attribute, and U is the
|
// N is the next row down toggle, ATTRBTE is the 4-byte encoded attribute, and U is the
|
||||||
// underline toggle. The next row down toggle isn't applicable for roll-up captions.
|
// underline toggle.
|
||||||
boolean nextRowDown = captionMode != CC_MODE_ROLL_UP && (cc2 & 0x20) != 0;
|
boolean nextRowDown = (cc2 & 0x20) != 0;
|
||||||
if (row != currentCueBuilder.getRow() || nextRowDown) {
|
if (nextRowDown) {
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row != currentCueBuilder.getRow()) {
|
||||||
if (captionMode != CC_MODE_ROLL_UP && !currentCueBuilder.isEmpty()) {
|
if (captionMode != CC_MODE_ROLL_UP && !currentCueBuilder.isEmpty()) {
|
||||||
currentCueBuilder = new CueBuilder(captionMode, captionRowCount);
|
currentCueBuilder = new CueBuilder(captionMode, captionRowCount);
|
||||||
cueBuilders.add(currentCueBuilder);
|
cueBuilders.add(currentCueBuilder);
|
||||||
}
|
}
|
||||||
currentCueBuilder.setRow(nextRowDown ? ++row : row);
|
currentCueBuilder.setRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cc2 & 0x01) == 0x01) {
|
if ((cc2 & 0x01) == 0x01) {
|
||||||
@ -492,7 +496,10 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
private List<Cue> getDisplayCues() {
|
private List<Cue> getDisplayCues() {
|
||||||
List<Cue> displayCues = new ArrayList<>();
|
List<Cue> displayCues = new ArrayList<>();
|
||||||
for (int i = 0; i < cueBuilders.size(); i++) {
|
for (int i = 0; i < cueBuilders.size(); i++) {
|
||||||
displayCues.add(cueBuilders.get(i).build());
|
Cue cue = cueBuilders.get(i).build();
|
||||||
|
if (cue != null) {
|
||||||
|
displayCues.add(cue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return displayCues;
|
return displayCues;
|
||||||
}
|
}
|
||||||
@ -727,36 +734,62 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
|
|
||||||
public Cue build() {
|
public Cue build() {
|
||||||
SpannableStringBuilder cueString = new SpannableStringBuilder();
|
SpannableStringBuilder cueString = new SpannableStringBuilder();
|
||||||
|
// Add any rolled up captions, separated by new lines.
|
||||||
// add any rolled up captions, separated by new lines
|
|
||||||
for (int i = 0; i < rolledUpCaptions.size(); i++) {
|
for (int i = 0; i < rolledUpCaptions.size(); i++) {
|
||||||
cueString.append(rolledUpCaptions.get(i));
|
cueString.append(rolledUpCaptions.get(i));
|
||||||
cueString.append('\n');
|
cueString.append('\n');
|
||||||
}
|
}
|
||||||
|
// Add the current line.
|
||||||
// add the current line
|
|
||||||
cueString.append(buildSpannableString());
|
cueString.append(buildSpannableString());
|
||||||
|
|
||||||
float position = (float) (indent + tabOffset) / SCREEN_CHARWIDTH;
|
if (cueString.length() == 0) {
|
||||||
// adjust the position to fit within the safe area
|
// The cue is empty.
|
||||||
position = position * 0.8f + 0.1f;
|
return null;
|
||||||
|
|
||||||
float line;
|
|
||||||
int lineType;
|
|
||||||
if (captionMode == CC_MODE_ROLL_UP) {
|
|
||||||
lineType = Cue.LINE_TYPE_NUMBER;
|
|
||||||
line = row - BASE_ROW;
|
|
||||||
// adjust the line to fit within the safe area
|
|
||||||
line--;
|
|
||||||
} else {
|
|
||||||
lineType = Cue.LINE_TYPE_FRACTION;
|
|
||||||
line = (float) row / BASE_ROW;
|
|
||||||
// adjust the line to fit within the safe area
|
|
||||||
line = line * 0.8f + 0.1f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Cue(cueString, Alignment.ALIGN_NORMAL, line, lineType, Cue.ANCHOR_TYPE_END,
|
float position;
|
||||||
position, Cue.ANCHOR_TYPE_START, Cue.DIMEN_UNSET);
|
int positionAnchor;
|
||||||
|
// The number of empty columns before the start of the text, in the range [0-31].
|
||||||
|
int startPadding = indent + tabOffset;
|
||||||
|
// The number of empty columns after the end of the text, in the same range.
|
||||||
|
int endPadding = SCREEN_CHARWIDTH - startPadding - cueString.length();
|
||||||
|
int startEndPaddingDelta = startPadding - endPadding;
|
||||||
|
if (captionMode == CC_MODE_POP_ON && Math.abs(startEndPaddingDelta) < 3) {
|
||||||
|
// Treat approximately centered pop-on captions are middle aligned.
|
||||||
|
position = 0.5f;
|
||||||
|
positionAnchor = Cue.ANCHOR_TYPE_MIDDLE;
|
||||||
|
} else if (captionMode == CC_MODE_POP_ON && startEndPaddingDelta > 0) {
|
||||||
|
// Treat pop-on captions with less padding at the end than the start as end aligned.
|
||||||
|
position = (float) (SCREEN_CHARWIDTH - endPadding) / SCREEN_CHARWIDTH;
|
||||||
|
// Adjust the position to fit within the safe area.
|
||||||
|
position = position * 0.8f + 0.1f;
|
||||||
|
positionAnchor = Cue.ANCHOR_TYPE_END;
|
||||||
|
} else {
|
||||||
|
// For all other cases assume start aligned.
|
||||||
|
position = (float) startPadding / SCREEN_CHARWIDTH;
|
||||||
|
// Adjust the position to fit within the safe area.
|
||||||
|
position = position * 0.8f + 0.1f;
|
||||||
|
positionAnchor = Cue.ANCHOR_TYPE_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lineAnchor;
|
||||||
|
int line;
|
||||||
|
// Note: Row indices are in the range [1-15].
|
||||||
|
if (captionMode == CC_MODE_ROLL_UP || row > (BASE_ROW / 2)) {
|
||||||
|
lineAnchor = Cue.ANCHOR_TYPE_END;
|
||||||
|
line = row - BASE_ROW;
|
||||||
|
// Two line adjustments. The first is because line indices from the bottom of the window
|
||||||
|
// start from -1 rather than 0. The second is a blank row to act as the safe area.
|
||||||
|
line -= 2;
|
||||||
|
} else {
|
||||||
|
lineAnchor = Cue.ANCHOR_TYPE_START;
|
||||||
|
// Line indices from the top of the window start from 0, but we want a blank row to act as
|
||||||
|
// the safe area. As a result no adjustment is necessary.
|
||||||
|
line = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Cue(cueString, Alignment.ALIGN_NORMAL, line, Cue.LINE_TYPE_NUMBER, lineAnchor,
|
||||||
|
position, positionAnchor, Cue.DIMEN_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -256,7 +256,13 @@ import java.util.regex.Pattern;
|
|||||||
if (s.endsWith("%")) {
|
if (s.endsWith("%")) {
|
||||||
builder.setLine(WebvttParserUtil.parsePercentage(s)).setLineType(Cue.LINE_TYPE_FRACTION);
|
builder.setLine(WebvttParserUtil.parsePercentage(s)).setLineType(Cue.LINE_TYPE_FRACTION);
|
||||||
} else {
|
} else {
|
||||||
builder.setLine(Integer.parseInt(s)).setLineType(Cue.LINE_TYPE_NUMBER);
|
int lineNumber = Integer.parseInt(s);
|
||||||
|
if (lineNumber < 0) {
|
||||||
|
// WebVTT defines line -1 as last visible row when lineAnchor is ANCHOR_TYPE_START, where-as
|
||||||
|
// Cue defines it to be the first row that's not visible.
|
||||||
|
lineNumber--;
|
||||||
|
}
|
||||||
|
builder.setLine(lineNumber).setLineType(Cue.LINE_TYPE_NUMBER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
if (cueLine >= 0) {
|
if (cueLine >= 0) {
|
||||||
anchorPosition = Math.round(cueLine * firstLineHeight) + parentTop;
|
anchorPosition = Math.round(cueLine * firstLineHeight) + parentTop;
|
||||||
} else {
|
} else {
|
||||||
anchorPosition = Math.round(cueLine * firstLineHeight) + parentBottom;
|
anchorPosition = Math.round((cueLine + 1) * firstLineHeight) + parentBottom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textTop = cueLineAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textHeight
|
textTop = cueLineAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textHeight
|
||||||
|
Loading…
x
Reference in New Issue
Block a user