Search in sources :

Example 6 with Cue

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);
    }
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) InterruptedIOException(java.io.InterruptedIOException) Cue(androidx.media3.common.text.Cue) Nullable(androidx.annotation.Nullable)

Example 7 with Cue

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;
}
Also used : Cue(androidx.media3.common.text.Cue) ArrayList(java.util.ArrayList) Nullable(androidx.annotation.Nullable)

Example 8 with Cue

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;
}
Also used : Cue(androidx.media3.common.text.Cue) Nullable(androidx.annotation.Nullable)

Example 9 with 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);
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List)

Example 10 with Cue

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();
}
Also used : SpannableString(android.text.SpannableString) Cue(androidx.media3.common.text.Cue) ForegroundColorSpan(android.text.style.ForegroundColorSpan) StyleSpan(android.text.style.StyleSpan) UnderlineSpan(android.text.style.UnderlineSpan) StrikethroughSpan(android.text.style.StrikethroughSpan)

Aggregations

Cue (androidx.media3.common.text.Cue)58 Test (org.junit.Test)47 Nullable (androidx.annotation.Nullable)12 ArrayList (java.util.ArrayList)12 Subtitle (androidx.media3.extractor.text.Subtitle)11 Spanned (android.text.Spanned)8 Bundle (android.os.Bundle)4 UnderlineSpan (android.text.style.UnderlineSpan)4 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)4 LargeTest (androidx.test.filters.LargeTest)4 List (java.util.List)4 SpannableString (android.text.SpannableString)3 AdPlaybackState (androidx.media3.common.AdPlaybackState)3 Format (androidx.media3.common.Format)3 Player (androidx.media3.common.Player)3 HorizontalTextInVerticalContextSpan (androidx.media3.common.text.HorizontalTextInVerticalContextSpan)3 RubySpan (androidx.media3.common.text.RubySpan)3 FakeExtractorOutput (androidx.media3.test.utils.FakeExtractorOutput)3 Context (android.content.Context)2 Bitmap (android.graphics.Bitmap)2