use of com.google.android.exoplayer2.text.Cue in project ExoPlayer by google.
the class PgsDecoder method decode.
@Override
protected Subtitle decode(byte[] data, int size, boolean reset) throws SubtitleDecoderException {
buffer.reset(data, size);
maybeInflateData(buffer);
cueBuilder.reset();
ArrayList<Cue> cues = new ArrayList<>();
while (buffer.bytesLeft() >= 3) {
Cue cue = readNextSection(buffer, cueBuilder);
if (cue != null) {
cues.add(cue);
}
}
return new PgsSubtitle(Collections.unmodifiableList(cues));
}
use of com.google.android.exoplayer2.text.Cue in project ExoPlayer by google.
the class SubripDecoder method decode.
@Override
protected Subtitle decode(byte[] bytes, int length, boolean reset) {
ArrayList<Cue> cues = new ArrayList<>();
LongArray cueTimesUs = new LongArray();
ParsableByteArray subripData = new ParsableByteArray(bytes, length);
@Nullable String currentLine;
while ((currentLine = subripData.readLine()) != null) {
if (currentLine.length() == 0) {
// Skip blank lines.
continue;
}
// Parse and check the index line.
try {
Integer.parseInt(currentLine);
} catch (NumberFormatException e) {
Log.w(TAG, "Skipping invalid index: " + currentLine);
continue;
}
// Read and parse the timing line.
currentLine = subripData.readLine();
if (currentLine == null) {
Log.w(TAG, "Unexpected end");
break;
}
Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine);
if (matcher.matches()) {
cueTimesUs.add(parseTimecode(matcher, /* groupOffset= */
1));
cueTimesUs.add(parseTimecode(matcher, /* groupOffset= */
6));
} else {
Log.w(TAG, "Skipping invalid timing: " + currentLine);
continue;
}
// Read and parse the text and tags.
textBuilder.setLength(0);
tags.clear();
currentLine = subripData.readLine();
while (!TextUtils.isEmpty(currentLine)) {
if (textBuilder.length() > 0) {
textBuilder.append("<br>");
}
textBuilder.append(processLine(currentLine, tags));
currentLine = subripData.readLine();
}
Spanned text = Html.fromHtml(textBuilder.toString());
@Nullable String alignmentTag = null;
for (int i = 0; i < tags.size(); i++) {
String tag = tags.get(i);
if (tag.matches(SUBRIP_ALIGNMENT_TAG)) {
alignmentTag = tag;
// Subsequent alignment tags should be ignored.
break;
}
}
cues.add(buildCue(text, alignmentTag));
cues.add(Cue.EMPTY);
}
Cue[] cuesArray = cues.toArray(new Cue[0]);
long[] cueTimesUsArray = cueTimesUs.toArray();
return new SubripSubtitle(cuesArray, cueTimesUsArray);
}
use of com.google.android.exoplayer2.text.Cue in project ExoPlayer by google.
the class TtmlNode method getCues.
public List<Cue> getCues(long timeUs, Map<String, TtmlStyle> globalStyles, Map<String, TtmlRegion> regionMap, Map<String, String> imageMap) {
List<Pair<String, String>> regionImageOutputs = new ArrayList<>();
traverseForImage(timeUs, regionId, regionImageOutputs);
TreeMap<String, Cue.Builder> regionTextOutputs = new TreeMap<>();
traverseForText(timeUs, false, regionId, regionTextOutputs);
traverseForStyle(timeUs, globalStyles, regionMap, regionId, regionTextOutputs);
List<Cue> cues = new ArrayList<>();
// Create image based cues.
for (Pair<String, String> regionImagePair : regionImageOutputs) {
@Nullable String encodedBitmapData = imageMap.get(regionImagePair.second);
if (encodedBitmapData == null) {
// Image reference points to an invalid image. Do nothing.
continue;
}
byte[] bitmapData = Base64.decode(encodedBitmapData, Base64.DEFAULT);
Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, /* offset= */
0, bitmapData.length);
TtmlRegion region = Assertions.checkNotNull(regionMap.get(regionImagePair.first));
cues.add(new Cue.Builder().setBitmap(bitmap).setPosition(region.position).setPositionAnchor(Cue.ANCHOR_TYPE_START).setLine(region.line, Cue.LINE_TYPE_FRACTION).setLineAnchor(region.lineAnchor).setSize(region.width).setBitmapHeight(region.height).setVerticalType(region.verticalType).build());
}
// Create text based cues.
for (Map.Entry<String, Cue.Builder> entry : regionTextOutputs.entrySet()) {
TtmlRegion region = Assertions.checkNotNull(regionMap.get(entry.getKey()));
Cue.Builder regionOutput = entry.getValue();
cleanUpText((SpannableStringBuilder) Assertions.checkNotNull(regionOutput.getText()));
regionOutput.setLine(region.line, region.lineType);
regionOutput.setLineAnchor(region.lineAnchor);
regionOutput.setPosition(region.position);
regionOutput.setSize(region.width);
regionOutput.setTextSize(region.textSize, region.textSizeType);
regionOutput.setVerticalType(region.verticalType);
cues.add(regionOutput.build());
}
return cues;
}
use of com.google.android.exoplayer2.text.Cue in project ExoPlayer by google.
the class WebvttDecoder method decode.
@Override
protected Subtitle decode(byte[] bytes, int length, boolean reset) throws SubtitleDecoderException {
parsableWebvttData.reset(bytes, length);
List<WebvttCssStyle> definedStyles = new ArrayList<>();
// Validate the first line of the header, and skip the remainder.
try {
WebvttParserUtil.validateWebvttHeaderLine(parsableWebvttData);
} catch (ParserException e) {
throw new SubtitleDecoderException(e);
}
while (!TextUtils.isEmpty(parsableWebvttData.readLine())) {
}
int event;
List<WebvttCueInfo> cueInfos = new ArrayList<>();
while ((event = getNextEvent(parsableWebvttData)) != EVENT_END_OF_FILE) {
if (event == EVENT_COMMENT) {
skipComment(parsableWebvttData);
} else if (event == EVENT_STYLE_BLOCK) {
if (!cueInfos.isEmpty()) {
throw new SubtitleDecoderException("A style block was found after the first cue.");
}
// Consume the "STYLE" header.
parsableWebvttData.readLine();
definedStyles.addAll(cssParser.parseBlock(parsableWebvttData));
} else if (event == EVENT_CUE) {
@Nullable WebvttCueInfo cueInfo = WebvttCueParser.parseCue(parsableWebvttData, definedStyles);
if (cueInfo != null) {
cueInfos.add(cueInfo);
}
}
}
return new WebvttSubtitle(cueInfos);
}
use of com.google.android.exoplayer2.text.Cue in project ExoPlayer by google.
the class WebvttSubtitle method getCues.
@Override
public List<Cue> getCues(long timeUs) {
List<Cue> currentCues = new ArrayList<>();
List<WebvttCueInfo> cuesWithUnsetLine = new ArrayList<>();
for (int i = 0; i < cueInfos.size(); i++) {
if ((cueTimesUs[i * 2] <= timeUs) && (timeUs < cueTimesUs[i * 2 + 1])) {
WebvttCueInfo cueInfo = cueInfos.get(i);
if (cueInfo.cue.line == Cue.DIMEN_UNSET) {
cuesWithUnsetLine.add(cueInfo);
} else {
currentCues.add(cueInfo.cue);
}
}
}
// Steps 4 - 10 of https://www.w3.org/TR/webvtt1/#cue-computed-line
// (steps 1 - 3 are handled by WebvttCueParser#computeLine(float, int))
Collections.sort(cuesWithUnsetLine, (c1, c2) -> Long.compare(c1.startTimeUs, c2.startTimeUs));
for (int i = 0; i < cuesWithUnsetLine.size(); i++) {
Cue cue = cuesWithUnsetLine.get(i).cue;
currentCues.add(cue.buildUpon().setLine((float) (-1 - i), Cue.LINE_TYPE_NUMBER).build());
}
return currentCues;
}
Aggregations