use of androidx.media3.common.text.Cue in project media by androidx.
the class SubtitleExtractor method decode.
/**
* Decodes the subtitle data and stores the samples in the memory of the extractor.
*/
private void decode() throws IOException {
try {
@Nullable SubtitleInputBuffer inputBuffer = subtitleDecoder.dequeueInputBuffer();
while (inputBuffer == null) {
Thread.sleep(5);
inputBuffer = subtitleDecoder.dequeueInputBuffer();
}
inputBuffer.ensureSpaceForWrite(bytesRead);
inputBuffer.data.put(subtitleData.getData(), /* offset= */
0, bytesRead);
inputBuffer.data.limit(bytesRead);
subtitleDecoder.queueInputBuffer(inputBuffer);
@Nullable SubtitleOutputBuffer outputBuffer = subtitleDecoder.dequeueOutputBuffer();
while (outputBuffer == null) {
Thread.sleep(5);
outputBuffer = subtitleDecoder.dequeueOutputBuffer();
}
for (int i = 0; i < outputBuffer.getEventTimeCount(); i++) {
List<Cue> cues = outputBuffer.getCues(outputBuffer.getEventTime(i));
byte[] cuesSample = cueEncoder.encode(cues);
timestamps.add(outputBuffer.getEventTime(i));
samples.add(new ParsableByteArray(cuesSample));
}
outputBuffer.release();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new InterruptedIOException();
} catch (SubtitleDecoderException e) {
throw ParserException.createForMalformedContainer("SubtitleDecoder failed.", e);
}
}
use of androidx.media3.common.text.Cue in project media by androidx.
the class Cea608Decoder method getDisplayCues.
private List<Cue> getDisplayCues() {
// CEA-608 does not define middle and end alignment, however content providers artificially
// introduce them using whitespace. When each cue is built, we try and infer the alignment based
// on the amount of whitespace either side of the text. To avoid consecutive cues being aligned
// differently, we force all cues to have the same alignment, with start alignment given
// preference, then middle alignment, then end alignment.
@Cue.AnchorType int positionAnchor = Cue.ANCHOR_TYPE_END;
int cueBuilderCount = cueBuilders.size();
List<@NullableType Cue> cueBuilderCues = new ArrayList<>(cueBuilderCount);
for (int i = 0; i < cueBuilderCount; i++) {
@Nullable Cue cue = cueBuilders.get(i).build(/* forcedPositionAnchor= */
Cue.TYPE_UNSET);
cueBuilderCues.add(cue);
if (cue != null) {
positionAnchor = min(positionAnchor, cue.positionAnchor);
}
}
// Skip null cues and rebuild any that don't have the preferred alignment.
List<Cue> displayCues = new ArrayList<>(cueBuilderCount);
for (int i = 0; i < cueBuilderCount; i++) {
@Nullable Cue cue = cueBuilderCues.get(i);
if (cue != null) {
if (cue.positionAnchor != positionAnchor) {
// The last time we built this cue it was non-null, it will be non-null this time too.
cue = Assertions.checkNotNull(cueBuilders.get(i).build(positionAnchor));
}
displayCues.add(cue);
}
}
return displayCues;
}
use of androidx.media3.common.text.Cue in project media by androidx.
the class PgsDecoder method readNextSection.
@Nullable
private static Cue readNextSection(ParsableByteArray buffer, CueBuilder cueBuilder) {
int limit = buffer.limit();
int sectionType = buffer.readUnsignedByte();
int sectionLength = buffer.readUnsignedShort();
int nextSectionPosition = buffer.getPosition() + sectionLength;
if (nextSectionPosition > limit) {
buffer.setPosition(limit);
return null;
}
Cue cue = null;
switch(sectionType) {
case SECTION_TYPE_PALETTE:
cueBuilder.parsePaletteSection(buffer, sectionLength);
break;
case SECTION_TYPE_BITMAP_PICTURE:
cueBuilder.parseBitmapSection(buffer, sectionLength);
break;
case SECTION_TYPE_IDENTIFIER:
cueBuilder.parseIdentifierSection(buffer, sectionLength);
break;
case SECTION_TYPE_END:
cue = cueBuilder.build();
cueBuilder.reset();
break;
default:
break;
}
buffer.setPosition(nextSectionPosition);
return cue;
}
use of androidx.media3.common.text.Cue in project media by androidx.
the class SsaDecoder method decode.
@Override
protected Subtitle decode(byte[] bytes, int length, boolean reset) {
List<List<Cue>> cues = new ArrayList<>();
List<Long> cueTimesUs = new ArrayList<>();
ParsableByteArray data = new ParsableByteArray(bytes, length);
if (!haveInitializationData) {
parseHeader(data);
}
parseEventBody(data, cues, cueTimesUs);
return new SsaSubtitle(cues, cueTimesUs);
}
use of androidx.media3.common.text.Cue in project media by androidx.
the class SsaDecoder method createCue.
private static Cue createCue(String text, @Nullable SsaStyle style, SsaStyle.Overrides styleOverrides, float screenWidth, float screenHeight) {
SpannableString spannableText = new SpannableString(text);
Cue.Builder cue = new Cue.Builder().setText(spannableText);
if (style != null) {
if (style.primaryColor != null) {
spannableText.setSpan(new ForegroundColorSpan(style.primaryColor), /* start= */
0, /* end= */
spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.fontSize != Cue.DIMEN_UNSET && screenHeight != Cue.DIMEN_UNSET) {
cue.setTextSize(style.fontSize / screenHeight, Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING);
}
if (style.bold && style.italic) {
spannableText.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), /* start= */
0, /* end= */
spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (style.bold) {
spannableText.setSpan(new StyleSpan(Typeface.BOLD), /* start= */
0, /* end= */
spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (style.italic) {
spannableText.setSpan(new StyleSpan(Typeface.ITALIC), /* start= */
0, /* end= */
spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.underline) {
spannableText.setSpan(new UnderlineSpan(), /* start= */
0, /* end= */
spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (style.strikeout) {
spannableText.setSpan(new StrikethroughSpan(), /* start= */
0, /* end= */
spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
@SsaStyle.SsaAlignment int alignment;
if (styleOverrides.alignment != SsaStyle.SSA_ALIGNMENT_UNKNOWN) {
alignment = styleOverrides.alignment;
} else if (style != null) {
alignment = style.alignment;
} else {
alignment = SsaStyle.SSA_ALIGNMENT_UNKNOWN;
}
cue.setTextAlignment(toTextAlignment(alignment)).setPositionAnchor(toPositionAnchor(alignment)).setLineAnchor(toLineAnchor(alignment));
if (styleOverrides.position != null && screenHeight != Cue.DIMEN_UNSET && screenWidth != Cue.DIMEN_UNSET) {
cue.setPosition(styleOverrides.position.x / screenWidth);
cue.setLine(styleOverrides.position.y / screenHeight, LINE_TYPE_FRACTION);
} else {
// TODO: Read the MarginL, MarginR and MarginV values from the Style & Dialogue lines.
cue.setPosition(computeDefaultLineOrPosition(cue.getPositionAnchor()));
cue.setLine(computeDefaultLineOrPosition(cue.getLineAnchor()), LINE_TYPE_FRACTION);
}
return cue.build();
}
Aggregations