Java Code Examples for com.google.android.exoplayer2.text.Cue#ANCHOR_TYPE_START

The following examples show how to use com.google.android.exoplayer2.text.Cue#ANCHOR_TYPE_START . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: WebvttCue.java    From MediaSDK with Apache License 2.0 6 votes vote down vote up
public void reset() {
  startTime = 0;
  endTime = 0;
  text = null;
  // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment
  textAlignment = TEXT_ALIGNMENT_CENTER;
  line = Cue.DIMEN_UNSET;
  // Defaults to NUMBER (true): https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag
  lineType = Cue.LINE_TYPE_NUMBER;
  // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-line-alignment
  lineAnchor = Cue.ANCHOR_TYPE_START;
  position = Cue.DIMEN_UNSET;
  positionAnchor = Cue.TYPE_UNSET;
  // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-size
  width = 1.0f;
}
 
Example 2
Source File: SsaDecoder.java    From MediaSDK with Apache License 2.0 6 votes vote down vote up
@Cue.AnchorType
private static int toLineAnchor(@SsaStyle.SsaAlignment int alignment) {
  switch (alignment) {
    case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT:
    case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER:
    case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT:
      return Cue.ANCHOR_TYPE_END;
    case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT:
    case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER:
    case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT:
      return Cue.ANCHOR_TYPE_MIDDLE;
    case SsaStyle.SSA_ALIGNMENT_TOP_LEFT:
    case SsaStyle.SSA_ALIGNMENT_TOP_CENTER:
    case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT:
      return Cue.ANCHOR_TYPE_START;
    case SsaStyle.SSA_ALIGNMENT_UNKNOWN:
      return Cue.TYPE_UNSET;
    default:
      Log.w(TAG, "Unknown alignment: " + alignment);
      return Cue.TYPE_UNSET;
  }
}
 
Example 3
Source File: WebvttCue.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
private Builder derivePositionAnchorFromAlignment() {
  if (textAlignment == null) {
    positionAnchor = Cue.TYPE_UNSET;
  } else {
    switch (textAlignment) {
      case ALIGN_NORMAL:
        positionAnchor = Cue.ANCHOR_TYPE_START;
        break;
      case ALIGN_CENTER:
        positionAnchor = Cue.ANCHOR_TYPE_MIDDLE;
        break;
      case ALIGN_OPPOSITE:
        positionAnchor = Cue.ANCHOR_TYPE_END;
        break;
      default:
        Log.w(TAG, "Unrecognized alignment: " + textAlignment);
        positionAnchor = Cue.ANCHOR_TYPE_START;
        break;
    }
  }
  return this;
}
 
Example 4
Source File: WebvttCue.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
private Builder derivePositionAnchorFromAlignment() {
  if (textAlignment == null) {
    positionAnchor = Cue.TYPE_UNSET;
  } else {
    switch (textAlignment) {
      case ALIGN_NORMAL:
        positionAnchor = Cue.ANCHOR_TYPE_START;
        break;
      case ALIGN_CENTER:
        positionAnchor = Cue.ANCHOR_TYPE_MIDDLE;
        break;
      case ALIGN_OPPOSITE:
        positionAnchor = Cue.ANCHOR_TYPE_END;
        break;
      default:
        Log.w(TAG, "Unrecognized alignment: " + textAlignment);
        positionAnchor = Cue.ANCHOR_TYPE_START;
        break;
    }
  }
  return this;
}
 
Example 5
Source File: Tx3gDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@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, DEFAULT_FONT_FAMILY, 0, cueText.length(),
      SPAN_PRIORITY_LOW);
  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(cueText, null, verticalPlacement, Cue.LINE_TYPE_FRACTION,
      Cue.ANCHOR_TYPE_START, Cue.DIMEN_UNSET, Cue.TYPE_UNSET, Cue.DIMEN_UNSET));
}
 
Example 6
Source File: SubripDecoder.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
static float getFractionalPositionForAnchorType(@Cue.AnchorType int anchorType) {
  switch (anchorType) {
    case Cue.ANCHOR_TYPE_START:
      return SubripDecoder.START_FRACTION;
    case Cue.ANCHOR_TYPE_MIDDLE:
      return SubripDecoder.MID_FRACTION;
    case Cue.ANCHOR_TYPE_END:
      return SubripDecoder.END_FRACTION;
    case Cue.TYPE_UNSET:
    default:
      // Should never happen.
      throw new IllegalArgumentException();
  }
}
 
Example 7
Source File: WebvttCueParser.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
private static int parsePositionAnchor(String s) {
  switch (s) {
    case "start":
      return Cue.ANCHOR_TYPE_START;
    case "center":
    case "middle":
      return Cue.ANCHOR_TYPE_MIDDLE;
    case "end":
      return Cue.ANCHOR_TYPE_END;
    default:
      Log.w(TAG, "Invalid anchor value: " + s);
      return Cue.TYPE_UNSET;
  }
}
 
Example 8
Source File: SubripDecoder.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
static float getFractionalPositionForAnchorType(@Cue.AnchorType int anchorType) {
  switch (anchorType) {
    case Cue.ANCHOR_TYPE_START:
      return SubripDecoder.START_FRACTION;
    case Cue.ANCHOR_TYPE_MIDDLE:
      return SubripDecoder.MID_FRACTION;
    case Cue.ANCHOR_TYPE_END:
      return SubripDecoder.END_FRACTION;
    case Cue.TYPE_UNSET:
    default:
      // Should never happen.
      throw new IllegalArgumentException();
  }
}
 
Example 9
Source File: WebvttCueParser.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
private static int parsePositionAnchor(String s) {
  switch (s) {
    case "start":
      return Cue.ANCHOR_TYPE_START;
    case "center":
    case "middle":
      return Cue.ANCHOR_TYPE_MIDDLE;
    case "end":
      return Cue.ANCHOR_TYPE_END;
    default:
      Log.w(TAG, "Invalid anchor value: " + s);
      return Cue.TYPE_UNSET;
  }
}
 
Example 10
Source File: WebvttCueParser.java    From K-Sonic with MIT License 5 votes vote down vote up
private static int parsePositionAnchor(String s) {
  switch (s) {
    case "start":
      return Cue.ANCHOR_TYPE_START;
    case "center":
    case "middle":
      return Cue.ANCHOR_TYPE_MIDDLE;
    case "end":
      return Cue.ANCHOR_TYPE_END;
    default:
      Log.w(TAG, "Invalid anchor value: " + s);
      return Cue.TYPE_UNSET;
  }
}
 
Example 11
Source File: Cea708Decoder.java    From K-Sonic with MIT License 4 votes vote down vote up
public Cea708Cue build() {
  if (isEmpty()) {
    // The cue is empty.
    return null;
  }

  SpannableStringBuilder cueString = new SpannableStringBuilder();

  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildSpannableString());

  // TODO: Add support for right-to-left languages (i.e. where right would correspond to normal
  // alignment).
  Alignment alignment;
  switch (justification) {
    case JUSTIFICATION_FULL:
      // TODO: Add support for full justification.
    case JUSTIFICATION_LEFT:
      alignment = Alignment.ALIGN_NORMAL;
      break;
    case JUSTIFICATION_RIGHT:
      alignment = Alignment.ALIGN_OPPOSITE;
      break;
    case JUSTIFICATION_CENTER:
      alignment = Alignment.ALIGN_CENTER;
      break;
    default:
      throw new IllegalArgumentException("Unexpected justification value: " + justification);
  }

  float position;
  float line;
  if (relativePositioning) {
    position = (float) horizontalAnchor / RELATIVE_CUE_SIZE;
    line = (float) verticalAnchor / RELATIVE_CUE_SIZE;
  } else {
    position = (float) horizontalAnchor / HORIZONTAL_SIZE;
    line = (float) verticalAnchor / VERTICAL_SIZE;
  }
  // Apply screen-edge padding to the line and position.
  position = (position * 0.9f) + 0.05f;
  line = (line * 0.9f) + 0.05f;

  // anchorId specifies where the anchor should be placed on the caption cue/window. The 9
  // possible configurations are as follows:
  //   0-----1-----2
  //   |           |
  //   3     4     5
  //   |           |
  //   6-----7-----8
  @AnchorType int verticalAnchorType;
  if (anchorId % 3 == 0) {
    verticalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId % 3 == 1) {
    verticalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    verticalAnchorType = Cue.ANCHOR_TYPE_END;
  }
  // TODO: Add support for right-to-left languages (i.e. where start is on the right).
  @AnchorType int horizontalAnchorType;
  if (anchorId / 3 == 0) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId / 3 == 1) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    horizontalAnchorType = Cue.ANCHOR_TYPE_END;
  }

  boolean windowColorSet = (windowFillColor != COLOR_SOLID_BLACK);

  return new Cea708Cue(cueString, alignment, line, Cue.LINE_TYPE_FRACTION, verticalAnchorType,
      position, horizontalAnchorType, Cue.DIMEN_UNSET, windowColorSet, windowFillColor,
      priority);
}
 
Example 12
Source File: Cea608Decoder.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
public Cue build(@Cue.AnchorType int forcedPositionAnchor) {
  SpannableStringBuilder cueString = new SpannableStringBuilder();
  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildCurrentLine());

  if (cueString.length() == 0) {
    // The cue is empty.
    return null;
  }

  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 (forcedPositionAnchor != Cue.TYPE_UNSET) {
    positionAnchor = forcedPositionAnchor;
  } else if (captionMode == CC_MODE_POP_ON
      && (Math.abs(startEndPaddingDelta) < 3 || endPadding < 0)) {
    // Treat approximately centered pop-on captions as middle aligned. We also treat captions
    // that are wider than they should be in this way. See
    // https://github.com/google/ExoPlayer/issues/3534.
    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.
    positionAnchor = Cue.ANCHOR_TYPE_END;
  } else {
    // For all other cases assume start aligned.
    positionAnchor = Cue.ANCHOR_TYPE_START;
  }

  float position;
  switch (positionAnchor) {
    case Cue.ANCHOR_TYPE_MIDDLE:
      position = 0.5f;
      break;
    case Cue.ANCHOR_TYPE_END:
      position = (float) (SCREEN_CHARWIDTH - endPadding) / SCREEN_CHARWIDTH;
      // Adjust the position to fit within the safe area.
      position = position * 0.8f + 0.1f;
      break;
    case Cue.ANCHOR_TYPE_START:
    default:
      position = (float) startPadding / SCREEN_CHARWIDTH;
      // Adjust the position to fit within the safe area.
      position = position * 0.8f + 0.1f;
      break;
  }

  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);
}
 
Example 13
Source File: Cea708Decoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
public Cea708Cue build() {
  if (isEmpty()) {
    // The cue is empty.
    return null;
  }

  SpannableStringBuilder cueString = new SpannableStringBuilder();

  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildSpannableString());

  // TODO: Add support for right-to-left languages (i.e. where right would correspond to normal
  // alignment).
  Alignment alignment;
  switch (justification) {
    case JUSTIFICATION_FULL:
      // TODO: Add support for full justification.
    case JUSTIFICATION_LEFT:
      alignment = Alignment.ALIGN_NORMAL;
      break;
    case JUSTIFICATION_RIGHT:
      alignment = Alignment.ALIGN_OPPOSITE;
      break;
    case JUSTIFICATION_CENTER:
      alignment = Alignment.ALIGN_CENTER;
      break;
    default:
      throw new IllegalArgumentException("Unexpected justification value: " + justification);
  }

  float position;
  float line;
  if (relativePositioning) {
    position = (float) horizontalAnchor / RELATIVE_CUE_SIZE;
    line = (float) verticalAnchor / RELATIVE_CUE_SIZE;
  } else {
    position = (float) horizontalAnchor / HORIZONTAL_SIZE;
    line = (float) verticalAnchor / VERTICAL_SIZE;
  }
  // Apply screen-edge padding to the line and position.
  position = (position * 0.9f) + 0.05f;
  line = (line * 0.9f) + 0.05f;

  // anchorId specifies where the anchor should be placed on the caption cue/window. The 9
  // possible configurations are as follows:
  //   0-----1-----2
  //   |           |
  //   3     4     5
  //   |           |
  //   6-----7-----8
  @AnchorType int verticalAnchorType;
  if (anchorId % 3 == 0) {
    verticalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId % 3 == 1) {
    verticalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    verticalAnchorType = Cue.ANCHOR_TYPE_END;
  }
  // TODO: Add support for right-to-left languages (i.e. where start is on the right).
  @AnchorType int horizontalAnchorType;
  if (anchorId / 3 == 0) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId / 3 == 1) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    horizontalAnchorType = Cue.ANCHOR_TYPE_END;
  }

  boolean windowColorSet = (windowFillColor != COLOR_SOLID_BLACK);

  return new Cea708Cue(cueString, alignment, line, Cue.LINE_TYPE_FRACTION, verticalAnchorType,
      position, horizontalAnchorType, Cue.DIMEN_UNSET, windowColorSet, windowFillColor,
      priority);
}
 
Example 14
Source File: PgsDecoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
public Cue build() {
  if (planeWidth == 0
      || planeHeight == 0
      || bitmapWidth == 0
      || bitmapHeight == 0
      || bitmapData.limit() == 0
      || bitmapData.getPosition() != bitmapData.limit()
      || !colorsSet) {
    return null;
  }
  // Build the bitmapData.
  bitmapData.setPosition(0);
  int[] argbBitmapData = new int[bitmapWidth * bitmapHeight];
  int argbBitmapDataIndex = 0;
  while (argbBitmapDataIndex < argbBitmapData.length) {
    int colorIndex = bitmapData.readUnsignedByte();
    if (colorIndex != 0) {
      argbBitmapData[argbBitmapDataIndex++] = colors[colorIndex];
    } else {
      int switchBits = bitmapData.readUnsignedByte();
      if (switchBits != 0) {
        int runLength =
            (switchBits & 0x40) == 0
                ? (switchBits & 0x3F)
                : (((switchBits & 0x3F) << 8) | bitmapData.readUnsignedByte());
        int color = (switchBits & 0x80) == 0 ? 0 : colors[bitmapData.readUnsignedByte()];
        Arrays.fill(
            argbBitmapData, argbBitmapDataIndex, argbBitmapDataIndex + runLength, color);
        argbBitmapDataIndex += runLength;
      }
    }
  }
  Bitmap bitmap =
      Bitmap.createBitmap(argbBitmapData, bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
  // Build the cue.
  return new Cue(
      bitmap,
      (float) bitmapX / planeWidth,
      Cue.ANCHOR_TYPE_START,
      (float) bitmapY / planeHeight,
      Cue.ANCHOR_TYPE_START,
      (float) bitmapWidth / planeWidth,
      (float) bitmapHeight / planeHeight);
}
 
Example 15
Source File: Cea708Decoder.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
public Cea708Cue build() {
  if (isEmpty()) {
    // The cue is empty.
    return null;
  }

  SpannableStringBuilder cueString = new SpannableStringBuilder();

  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildSpannableString());

  // TODO: Add support for right-to-left languages (i.e. where right would correspond to normal
  // alignment).
  Alignment alignment;
  switch (justification) {
    case JUSTIFICATION_FULL:
      // TODO: Add support for full justification.
    case JUSTIFICATION_LEFT:
      alignment = Alignment.ALIGN_NORMAL;
      break;
    case JUSTIFICATION_RIGHT:
      alignment = Alignment.ALIGN_OPPOSITE;
      break;
    case JUSTIFICATION_CENTER:
      alignment = Alignment.ALIGN_CENTER;
      break;
    default:
      throw new IllegalArgumentException("Unexpected justification value: " + justification);
  }

  float position;
  float line;
  if (relativePositioning) {
    position = (float) horizontalAnchor / RELATIVE_CUE_SIZE;
    line = (float) verticalAnchor / RELATIVE_CUE_SIZE;
  } else {
    position = (float) horizontalAnchor / HORIZONTAL_SIZE;
    line = (float) verticalAnchor / VERTICAL_SIZE;
  }
  // Apply screen-edge padding to the line and position.
  position = (position * 0.9f) + 0.05f;
  line = (line * 0.9f) + 0.05f;

  // anchorId specifies where the anchor should be placed on the caption cue/window. The 9
  // possible configurations are as follows:
  //   0-----1-----2
  //   |           |
  //   3     4     5
  //   |           |
  //   6-----7-----8
  @AnchorType int verticalAnchorType;
  if (anchorId % 3 == 0) {
    verticalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId % 3 == 1) {
    verticalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    verticalAnchorType = Cue.ANCHOR_TYPE_END;
  }
  // TODO: Add support for right-to-left languages (i.e. where start is on the right).
  @AnchorType int horizontalAnchorType;
  if (anchorId / 3 == 0) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId / 3 == 1) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    horizontalAnchorType = Cue.ANCHOR_TYPE_END;
  }

  boolean windowColorSet = (windowFillColor != COLOR_SOLID_BLACK);

  return new Cea708Cue(cueString, alignment, line, Cue.LINE_TYPE_FRACTION, verticalAnchorType,
      position, horizontalAnchorType, Cue.DIMEN_UNSET, windowColorSet, windowFillColor,
      priority);
}
 
Example 16
Source File: Tx3gDecoder.java    From MediaSDK with Apache License 2.0 4 votes vote down vote up
@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, DEFAULT_FONT_FAMILY, 0, cueText.length(),
      SPAN_PRIORITY_LOW);
  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(
          cueText,
          /* textAlignment= */ null,
          verticalPlacement,
          Cue.LINE_TYPE_FRACTION,
          Cue.ANCHOR_TYPE_START,
          Cue.DIMEN_UNSET,
          Cue.TYPE_UNSET,
          Cue.DIMEN_UNSET));
}
 
Example 17
Source File: Cea708Decoder.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
public Cea708Cue build() {
  if (isEmpty()) {
    // The cue is empty.
    return null;
  }

  SpannableStringBuilder cueString = new SpannableStringBuilder();

  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildSpannableString());

  // TODO: Add support for right-to-left languages (i.e. where right would correspond to normal
  // alignment).
  Alignment alignment;
  switch (justification) {
    case JUSTIFICATION_FULL:
      // TODO: Add support for full justification.
    case JUSTIFICATION_LEFT:
      alignment = Alignment.ALIGN_NORMAL;
      break;
    case JUSTIFICATION_RIGHT:
      alignment = Alignment.ALIGN_OPPOSITE;
      break;
    case JUSTIFICATION_CENTER:
      alignment = Alignment.ALIGN_CENTER;
      break;
    default:
      throw new IllegalArgumentException("Unexpected justification value: " + justification);
  }

  float position;
  float line;
  if (relativePositioning) {
    position = (float) horizontalAnchor / RELATIVE_CUE_SIZE;
    line = (float) verticalAnchor / RELATIVE_CUE_SIZE;
  } else {
    position = (float) horizontalAnchor / HORIZONTAL_SIZE;
    line = (float) verticalAnchor / VERTICAL_SIZE;
  }
  // Apply screen-edge padding to the line and position.
  position = (position * 0.9f) + 0.05f;
  line = (line * 0.9f) + 0.05f;

  // anchorId specifies where the anchor should be placed on the caption cue/window. The 9
  // possible configurations are as follows:
  //   0-----1-----2
  //   |           |
  //   3     4     5
  //   |           |
  //   6-----7-----8
  @AnchorType int verticalAnchorType;
  if (anchorId % 3 == 0) {
    verticalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId % 3 == 1) {
    verticalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    verticalAnchorType = Cue.ANCHOR_TYPE_END;
  }
  // TODO: Add support for right-to-left languages (i.e. where start is on the right).
  @AnchorType int horizontalAnchorType;
  if (anchorId / 3 == 0) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId / 3 == 1) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    horizontalAnchorType = Cue.ANCHOR_TYPE_END;
  }

  boolean windowColorSet = (windowFillColor != COLOR_SOLID_BLACK);

  return new Cea708Cue(cueString, alignment, line, Cue.LINE_TYPE_FRACTION, verticalAnchorType,
      position, horizontalAnchorType, Cue.DIMEN_UNSET, windowColorSet, windowFillColor,
      priority);
}
 
Example 18
Source File: Cea608Decoder.java    From K-Sonic with MIT License 4 votes vote down vote up
public Cue build() {
  SpannableStringBuilder cueString = new SpannableStringBuilder();
  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildSpannableString());

  if (cueString.length() == 0) {
    // The cue is empty.
    return null;
  }

  float position;
  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);
}
 
Example 19
Source File: Cea708Decoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
public Cea708Cue build() {
  if (isEmpty()) {
    // The cue is empty.
    return null;
  }

  SpannableStringBuilder cueString = new SpannableStringBuilder();

  // Add any rolled up captions, separated by new lines.
  for (int i = 0; i < rolledUpCaptions.size(); i++) {
    cueString.append(rolledUpCaptions.get(i));
    cueString.append('\n');
  }
  // Add the current line.
  cueString.append(buildSpannableString());

  // TODO: Add support for right-to-left languages (i.e. where right would correspond to normal
  // alignment).
  Alignment alignment;
  switch (justification) {
    case JUSTIFICATION_FULL:
      // TODO: Add support for full justification.
    case JUSTIFICATION_LEFT:
      alignment = Alignment.ALIGN_NORMAL;
      break;
    case JUSTIFICATION_RIGHT:
      alignment = Alignment.ALIGN_OPPOSITE;
      break;
    case JUSTIFICATION_CENTER:
      alignment = Alignment.ALIGN_CENTER;
      break;
    default:
      throw new IllegalArgumentException("Unexpected justification value: " + justification);
  }

  float position;
  float line;
  if (relativePositioning) {
    position = (float) horizontalAnchor / RELATIVE_CUE_SIZE;
    line = (float) verticalAnchor / RELATIVE_CUE_SIZE;
  } else {
    position = (float) horizontalAnchor / HORIZONTAL_SIZE;
    line = (float) verticalAnchor / VERTICAL_SIZE;
  }
  // Apply screen-edge padding to the line and position.
  position = (position * 0.9f) + 0.05f;
  line = (line * 0.9f) + 0.05f;

  // anchorId specifies where the anchor should be placed on the caption cue/window. The 9
  // possible configurations are as follows:
  //   0-----1-----2
  //   |           |
  //   3     4     5
  //   |           |
  //   6-----7-----8
  @AnchorType int verticalAnchorType;
  if (anchorId % 3 == 0) {
    verticalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId % 3 == 1) {
    verticalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    verticalAnchorType = Cue.ANCHOR_TYPE_END;
  }
  // TODO: Add support for right-to-left languages (i.e. where start is on the right).
  @AnchorType int horizontalAnchorType;
  if (anchorId / 3 == 0) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_START;
  } else if (anchorId / 3 == 1) {
    horizontalAnchorType = Cue.ANCHOR_TYPE_MIDDLE;
  } else {
    horizontalAnchorType = Cue.ANCHOR_TYPE_END;
  }

  boolean windowColorSet = (windowFillColor != COLOR_SOLID_BLACK);

  return new Cea708Cue(cueString, alignment, line, Cue.LINE_TYPE_FRACTION, verticalAnchorType,
      position, horizontalAnchorType, Cue.DIMEN_UNSET, windowColorSet, windowFillColor,
      priority);
}
 
Example 20
Source File: PgsDecoder.java    From MediaSDK with Apache License 2.0 4 votes vote down vote up
@Nullable
public Cue build() {
  if (planeWidth == 0
      || planeHeight == 0
      || bitmapWidth == 0
      || bitmapHeight == 0
      || bitmapData.limit() == 0
      || bitmapData.getPosition() != bitmapData.limit()
      || !colorsSet) {
    return null;
  }
  // Build the bitmapData.
  bitmapData.setPosition(0);
  int[] argbBitmapData = new int[bitmapWidth * bitmapHeight];
  int argbBitmapDataIndex = 0;
  while (argbBitmapDataIndex < argbBitmapData.length) {
    int colorIndex = bitmapData.readUnsignedByte();
    if (colorIndex != 0) {
      argbBitmapData[argbBitmapDataIndex++] = colors[colorIndex];
    } else {
      int switchBits = bitmapData.readUnsignedByte();
      if (switchBits != 0) {
        int runLength =
            (switchBits & 0x40) == 0
                ? (switchBits & 0x3F)
                : (((switchBits & 0x3F) << 8) | bitmapData.readUnsignedByte());
        int color = (switchBits & 0x80) == 0 ? 0 : colors[bitmapData.readUnsignedByte()];
        Arrays.fill(
            argbBitmapData, argbBitmapDataIndex, argbBitmapDataIndex + runLength, color);
        argbBitmapDataIndex += runLength;
      }
    }
  }
  Bitmap bitmap =
      Bitmap.createBitmap(argbBitmapData, bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
  // Build the cue.
  return new Cue(
      bitmap,
      (float) bitmapX / planeWidth,
      Cue.ANCHOR_TYPE_START,
      (float) bitmapY / planeHeight,
      Cue.ANCHOR_TYPE_START,
      (float) bitmapWidth / planeWidth,
      (float) bitmapHeight / planeHeight);
}