Search in sources :

Example 1 with SubtitleDecoderException

use of androidx.media3.extractor.text.SubtitleDecoderException in project media by androidx.

the class TtmlDecoder method parseFontSize.

private static void parseFontSize(String expression, TtmlStyle out) throws SubtitleDecoderException {
    String[] expressions = Util.split(expression, "\\s+");
    Matcher matcher;
    if (expressions.length == 1) {
        matcher = FONT_SIZE.matcher(expression);
    } else if (expressions.length == 2) {
        matcher = FONT_SIZE.matcher(expressions[1]);
        Log.w(TAG, "Multiple values in fontSize attribute. Picking the second value for vertical font" + " size and ignoring the first.");
    } else {
        throw new SubtitleDecoderException("Invalid number of entries for fontSize: " + expressions.length + ".");
    }
    if (matcher.matches()) {
        String unit = Assertions.checkNotNull(matcher.group(3));
        switch(unit) {
            case "px":
                out.setFontSizeUnit(TtmlStyle.FONT_SIZE_UNIT_PIXEL);
                break;
            case "em":
                out.setFontSizeUnit(TtmlStyle.FONT_SIZE_UNIT_EM);
                break;
            case "%":
                out.setFontSizeUnit(TtmlStyle.FONT_SIZE_UNIT_PERCENT);
                break;
            default:
                throw new SubtitleDecoderException("Invalid unit for fontSize: '" + unit + "'.");
        }
        out.setFontSize(Float.parseFloat(Assertions.checkNotNull(matcher.group(1))));
    } else {
        throw new SubtitleDecoderException("Invalid expression for fontSize: '" + expression + "'.");
    }
}
Also used : Matcher(java.util.regex.Matcher) SubtitleDecoderException(androidx.media3.extractor.text.SubtitleDecoderException)

Example 2 with SubtitleDecoderException

use of androidx.media3.extractor.text.SubtitleDecoderException in project media by androidx.

the class Tx3gDecoder method decode.

@Override
protected Subtitle decode(byte[] bytes, int length, boolean reset) throws SubtitleDecoderException {
    parsableByteArray.reset(bytes, length);
    String cueTextString = readSubtitleText(parsableByteArray);
    if (cueTextString.isEmpty()) {
        return Tx3gSubtitle.EMPTY;
    }
    // Attach default styles.
    SpannableStringBuilder cueText = new SpannableStringBuilder(cueTextString);
    attachFontFace(cueText, defaultFontFace, DEFAULT_FONT_FACE, 0, cueText.length(), SPAN_PRIORITY_LOW);
    attachColor(cueText, defaultColorRgba, DEFAULT_COLOR, 0, cueText.length(), SPAN_PRIORITY_LOW);
    attachFontFamily(cueText, defaultFontFamily, 0, cueText.length());
    float verticalPlacement = defaultVerticalPlacement;
    // Find and attach additional styles.
    while (parsableByteArray.bytesLeft() >= SIZE_ATOM_HEADER) {
        int position = parsableByteArray.getPosition();
        int atomSize = parsableByteArray.readInt();
        int atomType = parsableByteArray.readInt();
        if (atomType == TYPE_STYL) {
            assertTrue(parsableByteArray.bytesLeft() >= SIZE_SHORT);
            int styleRecordCount = parsableByteArray.readUnsignedShort();
            for (int i = 0; i < styleRecordCount; i++) {
                applyStyleRecord(parsableByteArray, cueText);
            }
        } else if (atomType == TYPE_TBOX && customVerticalPlacement) {
            assertTrue(parsableByteArray.bytesLeft() >= SIZE_SHORT);
            int requestedVerticalPlacement = parsableByteArray.readUnsignedShort();
            verticalPlacement = (float) requestedVerticalPlacement / calculatedVideoTrackHeight;
            verticalPlacement = Util.constrainValue(verticalPlacement, 0.0f, 0.95f);
        }
        parsableByteArray.setPosition(position + atomSize);
    }
    return new Tx3gSubtitle(new Cue.Builder().setText(cueText).setLine(verticalPlacement, LINE_TYPE_FRACTION).setLineAnchor(ANCHOR_TYPE_START).build());
}
Also used : Cue(androidx.media3.common.text.Cue) SpannableStringBuilder(android.text.SpannableStringBuilder)

Example 3 with SubtitleDecoderException

use of androidx.media3.extractor.text.SubtitleDecoderException 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 4 with SubtitleDecoderException

use of androidx.media3.extractor.text.SubtitleDecoderException in project media by androidx.

the class Cea608Decoder method dequeueOutputBuffer.

@Nullable
@Override
public SubtitleOutputBuffer dequeueOutputBuffer() throws SubtitleDecoderException {
    SubtitleOutputBuffer outputBuffer = super.dequeueOutputBuffer();
    if (outputBuffer != null) {
        return outputBuffer;
    }
    if (shouldClearStuckCaptions()) {
        outputBuffer = getAvailableOutputBuffer();
        if (outputBuffer != null) {
            cues = Collections.emptyList();
            lastCueUpdateUs = C.TIME_UNSET;
            Subtitle subtitle = createSubtitle();
            outputBuffer.setContent(getPositionUs(), subtitle, Format.OFFSET_SAMPLE_RELATIVE);
            return outputBuffer;
        }
    }
    return null;
}
Also used : Subtitle(androidx.media3.extractor.text.Subtitle) SubtitleOutputBuffer(androidx.media3.extractor.text.SubtitleOutputBuffer) Nullable(androidx.annotation.Nullable)

Example 5 with SubtitleDecoderException

use of androidx.media3.extractor.text.SubtitleDecoderException in project media by androidx.

the class TtmlDecoder method parseTimeExpression.

/**
 * Parses a time expression, returning the parsed timestamp.
 *
 * <p>For the format of a time expression, see: <a
 * href="http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
 *
 * @param time A string that includes the time expression.
 * @param frameAndTickRate The effective frame and tick rates of the stream.
 * @return The parsed timestamp in microseconds.
 * @throws SubtitleDecoderException If the given string does not contain a valid time expression.
 */
private static long parseTimeExpression(String time, FrameAndTickRate frameAndTickRate) throws SubtitleDecoderException {
    Matcher matcher = CLOCK_TIME.matcher(time);
    if (matcher.matches()) {
        String hours = Assertions.checkNotNull(matcher.group(1));
        double durationSeconds = Long.parseLong(hours) * 3600;
        String minutes = Assertions.checkNotNull(matcher.group(2));
        durationSeconds += Long.parseLong(minutes) * 60;
        String seconds = Assertions.checkNotNull(matcher.group(3));
        durationSeconds += Long.parseLong(seconds);
        @Nullable String fraction = matcher.group(4);
        durationSeconds += (fraction != null) ? Double.parseDouble(fraction) : 0;
        @Nullable String frames = matcher.group(5);
        durationSeconds += (frames != null) ? Long.parseLong(frames) / frameAndTickRate.effectiveFrameRate : 0;
        @Nullable String subframes = matcher.group(6);
        durationSeconds += (subframes != null) ? ((double) Long.parseLong(subframes)) / frameAndTickRate.subFrameRate / frameAndTickRate.effectiveFrameRate : 0;
        return (long) (durationSeconds * C.MICROS_PER_SECOND);
    }
    matcher = OFFSET_TIME.matcher(time);
    if (matcher.matches()) {
        String timeValue = Assertions.checkNotNull(matcher.group(1));
        double offsetSeconds = Double.parseDouble(timeValue);
        String unit = Assertions.checkNotNull(matcher.group(2));
        switch(unit) {
            case "h":
                offsetSeconds *= 3600;
                break;
            case "m":
                offsetSeconds *= 60;
                break;
            case "s":
                // Do nothing.
                break;
            case "ms":
                offsetSeconds /= 1000;
                break;
            case "f":
                offsetSeconds /= frameAndTickRate.effectiveFrameRate;
                break;
            case "t":
                offsetSeconds /= frameAndTickRate.tickRate;
                break;
        }
        return (long) (offsetSeconds * C.MICROS_PER_SECOND);
    }
    throw new SubtitleDecoderException("Malformed time expression: " + time);
}
Also used : Matcher(java.util.regex.Matcher) Nullable(androidx.annotation.Nullable) SubtitleDecoderException(androidx.media3.extractor.text.SubtitleDecoderException)

Aggregations

Cue (androidx.media3.common.text.Cue)13 Test (org.junit.Test)11 Nullable (androidx.annotation.Nullable)8 SubtitleDecoderException (androidx.media3.extractor.text.SubtitleDecoderException)6 Subtitle (androidx.media3.extractor.text.Subtitle)5 SubtitleOutputBuffer (androidx.media3.extractor.text.SubtitleOutputBuffer)4 Matcher (java.util.regex.Matcher)3 SubtitleInputBuffer (androidx.media3.extractor.text.SubtitleInputBuffer)2 ArrayList (java.util.ArrayList)2 SpannableStringBuilder (android.text.SpannableStringBuilder)1 Format (androidx.media3.common.Format)1 ParserException (androidx.media3.common.ParserException)1 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)1 ReadDataResult (androidx.media3.exoplayer.source.SampleStream.ReadDataResult)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 InterruptedIOException (java.io.InterruptedIOException)1 ArrayDeque (java.util.ArrayDeque)1 HashMap (java.util.HashMap)1 XmlPullParser (org.xmlpull.v1.XmlPullParser)1