com.google.android.exoplayer2.text.SubtitleInputBuffer Java Examples

The following examples show how to use com.google.android.exoplayer2.text.SubtitleInputBuffer. 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: CeaDecoder.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
@Override
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
  Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
  if (inputBuffer.isDecodeOnly()) {
    // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow
    // for decoding to begin mid-stream.
    releaseInputBuffer(dequeuedInputBuffer);
  } else {
    dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++;
    queuedInputBuffers.add(dequeuedInputBuffer);
  }
  dequeuedInputBuffer = null;
}
 
Example #2
Source File: CeaDecoder.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
@Override
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
  Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
  if (inputBuffer.isDecodeOnly()) {
    // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow
    // for decoding to begin mid-stream.
    releaseInputBuffer(dequeuedInputBuffer);
  } else {
    dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++;
    queuedInputBuffers.add(dequeuedInputBuffer);
  }
  dequeuedInputBuffer = null;
}
 
Example #3
Source File: CeaDecoder.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
@Override
public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException {
  Assertions.checkState(dequeuedInputBuffer == null);
  if (availableInputBuffers.isEmpty()) {
    return null;
  }
  dequeuedInputBuffer = availableInputBuffers.pollFirst();
  return dequeuedInputBuffer;
}
 
Example #4
Source File: CeaDecoder.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
@Override
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
  Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
  if (inputBuffer.isDecodeOnly()) {
    // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow
    // for decoding to begin mid-stream.
    releaseInputBuffer(dequeuedInputBuffer);
  } else {
    dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++;
    queuedInputBuffers.add(dequeuedInputBuffer);
  }
  dequeuedInputBuffer = null;
}
 
Example #5
Source File: CeaDecoder.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
@Override
public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException {
  Assertions.checkState(dequeuedInputBuffer == null);
  if (availableInputBuffers.isEmpty()) {
    return null;
  }
  dequeuedInputBuffer = availableInputBuffers.pollFirst();
  return dequeuedInputBuffer;
}
 
Example #6
Source File: CeaDecoder.java    From K-Sonic with MIT License 5 votes vote down vote up
@Override
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
  Assertions.checkArgument(inputBuffer != null);
  Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
  if (inputBuffer.isDecodeOnly()) {
    // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow
    // for decoding to begin mid-stream.
    releaseInputBuffer(inputBuffer);
  } else {
    queuedInputBuffers.add(inputBuffer);
  }
  dequeuedInputBuffer = null;
}
 
Example #7
Source File: CeaDecoder.java    From K-Sonic with MIT License 5 votes vote down vote up
@Override
public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException {
  Assertions.checkState(dequeuedInputBuffer == null);
  if (availableInputBuffers.isEmpty()) {
    return null;
  }
  dequeuedInputBuffer = availableInputBuffers.pollFirst();
  return dequeuedInputBuffer;
}
 
Example #8
Source File: CeaDecoder.java    From K-Sonic with MIT License 5 votes vote down vote up
public CeaDecoder() {
  availableInputBuffers = new LinkedList<>();
  for (int i = 0; i < NUM_INPUT_BUFFERS; i++) {
    availableInputBuffers.add(new SubtitleInputBuffer());
  }
  availableOutputBuffers = new LinkedList<>();
  for (int i = 0; i < NUM_OUTPUT_BUFFERS; i++) {
    availableOutputBuffers.add(new CeaOutputBuffer(this));
  }
  queuedInputBuffers = new TreeSet<>();
}
 
Example #9
Source File: CeaDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@Override
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
  Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
  if (inputBuffer.isDecodeOnly()) {
    // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow
    // for decoding to begin mid-stream.
    releaseInputBuffer(dequeuedInputBuffer);
  } else {
    dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++;
    queuedInputBuffers.add(dequeuedInputBuffer);
  }
  dequeuedInputBuffer = null;
}
 
Example #10
Source File: CeaDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@Override
public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException {
  Assertions.checkState(dequeuedInputBuffer == null);
  if (availableInputBuffers.isEmpty()) {
    return null;
  }
  dequeuedInputBuffer = availableInputBuffers.pollFirst();
  return dequeuedInputBuffer;
}
 
Example #11
Source File: CeaDecoder.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
@Override
public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException {
  Assertions.checkState(dequeuedInputBuffer == null);
  if (availableInputBuffers.isEmpty()) {
    return null;
  }
  dequeuedInputBuffer = availableInputBuffers.pollFirst();
  return dequeuedInputBuffer;
}
 
Example #12
Source File: CeaDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@Override
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
  Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
  if (inputBuffer.isDecodeOnly()) {
    // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow
    // for decoding to begin mid-stream.
    releaseInputBuffer(dequeuedInputBuffer);
  } else {
    dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++;
    queuedInputBuffers.add(dequeuedInputBuffer);
  }
  dequeuedInputBuffer = null;
}
 
Example #13
Source File: CeaDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@Override
public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException {
  Assertions.checkState(dequeuedInputBuffer == null);
  if (availableInputBuffers.isEmpty()) {
    return null;
  }
  dequeuedInputBuffer = availableInputBuffers.pollFirst();
  return dequeuedInputBuffer;
}
 
Example #14
Source File: Cea608Decoder.java    From K-Sonic with MIT License 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  boolean captionDataProcessed = false;
  boolean isRepeatableControl = false;
  while (ccData.bytesLeft() >= packetLength) {
    byte ccDataHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
        : (byte) ccData.readUnsignedByte();
    byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit
    byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit

    // Only examine valid CEA-608 packets
    // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
    // to the CEA-608 specification. We need to determine if the data should be handled
    // differently when that is not the case.
    if ((ccDataHeader & (CC_VALID_FLAG | CC_TYPE_FLAG)) != CC_VALID_608_ID) {
      continue;
    }

    // Only examine packets within the selected field
    if ((selectedField == 1 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_1)
        || (selectedField == 2 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_2)) {
      continue;
    }

    // Ignore empty captions.
    if (ccData1 == 0 && ccData2 == 0) {
      continue;
    }

    // If we've reached this point then there is data to process; flag that work has been done.
    captionDataProcessed = true;

    // Special North American character set.
    // ccData1 - 0|0|0|1|C|0|0|1
    // ccData2 - 0|0|1|1|X|X|X|X
    if (((ccData1 & 0xF7) == 0x11) && ((ccData2 & 0xF0) == 0x30)) {
      // TODO: Make use of the channel toggle
      currentCueBuilder.append(getSpecialChar(ccData2));
      continue;
    }

    // Extended Western European character set.
    // ccData1 - 0|0|0|1|C|0|1|S
    // ccData2 - 0|0|1|X|X|X|X|X
    if (((ccData1 & 0xF6) == 0x12) && (ccData2 & 0xE0) == 0x20) {
      // TODO: Make use of the channel toggle
      // Remove standard equivalent of the special extended char before appending new one
      currentCueBuilder.backspace();
      if ((ccData1 & 0x01) == 0x00) {
        // Extended Spanish/Miscellaneous and French character set (S = 0).
        currentCueBuilder.append(getExtendedEsFrChar(ccData2));
      } else {
        // Extended Portuguese and German/Danish character set (S = 1).
        currentCueBuilder.append(getExtendedPtDeChar(ccData2));
      }
      continue;
    }

    // Control character.
    // ccData1 - 0|0|0|X|X|X|X|X
    if ((ccData1 & 0xE0) == 0x00) {
      isRepeatableControl = handleCtrl(ccData1, ccData2);
      continue;
    }

    // Basic North American character set.
    currentCueBuilder.append(getChar(ccData1));
    if ((ccData2 & 0xE0) != 0x00) {
      currentCueBuilder.append(getChar(ccData2));
    }
  }

  if (captionDataProcessed) {
    if (!isRepeatableControl) {
      repeatableControlSet = false;
    }
    if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
      cues = getDisplayCues();
    }
  }
}
 
Example #15
Source File: Cea608Decoder.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
@SuppressWarnings("ByteBufferBackingArray")
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  boolean captionDataProcessed = false;
  while (ccData.bytesLeft() >= packetLength) {
    byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
        : (byte) ccData.readUnsignedByte();
    int ccByte1 = ccData.readUnsignedByte();
    int ccByte2 = ccData.readUnsignedByte();

    // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
    // to the CEA-608 specification. We need to determine if the data should be handled
    // differently when that is not the case.

    if ((ccHeader & CC_TYPE_FLAG) != 0) {
      // Do not process anything that is not part of the 608 byte stream.
      continue;
    }

    if ((ccHeader & CC_FIELD_FLAG) != selectedField) {
      // Do not process packets not within the selected field.
      continue;
    }

    // Strip the parity bit from each byte to get CC data.
    byte ccData1 = (byte) (ccByte1 & 0x7F);
    byte ccData2 = (byte) (ccByte2 & 0x7F);

    if (ccData1 == 0 && ccData2 == 0) {
      // Ignore empty captions.
      continue;
    }

    boolean previousIsCaptionValid = isCaptionValid;
    isCaptionValid =
        (ccHeader & CC_VALID_FLAG) == CC_VALID_FLAG
            && ODD_PARITY_BYTE_TABLE[ccByte1]
            && ODD_PARITY_BYTE_TABLE[ccByte2];

    if (isRepeatedCommand(isCaptionValid, ccData1, ccData2)) {
      // Ignore repeated valid commands.
      continue;
    }

    if (!isCaptionValid) {
      if (previousIsCaptionValid) {
        // The encoder has flipped the validity bit to indicate captions are being turned off.
        resetCueBuilders();
        captionDataProcessed = true;
      }
      continue;
    }

    maybeUpdateIsInCaptionService(ccData1, ccData2);
    if (!isInCaptionService) {
      // Only the Captioning service is supported. Drop all other bytes.
      continue;
    }

    if (!updateAndVerifyCurrentChannel(ccData1)) {
      // Wrong channel.
      continue;
    }

    if (isCtrlCode(ccData1)) {
      if (isSpecialNorthAmericanChar(ccData1, ccData2)) {
        currentCueBuilder.append(getSpecialNorthAmericanChar(ccData2));
      } else if (isExtendedWestEuropeanChar(ccData1, ccData2)) {
        // Remove standard equivalent of the special extended char before appending new one.
        currentCueBuilder.backspace();
        currentCueBuilder.append(getExtendedWestEuropeanChar(ccData1, ccData2));
      } else if (isMidrowCtrlCode(ccData1, ccData2)) {
        handleMidrowCtrl(ccData2);
      } else if (isPreambleAddressCode(ccData1, ccData2)) {
        handlePreambleAddressCode(ccData1, ccData2);
      } else if (isTabCtrlCode(ccData1, ccData2)) {
        currentCueBuilder.tabOffset = ccData2 - 0x20;
      } else if (isMiscCode(ccData1, ccData2)) {
        handleMiscCode(ccData2);
      }
    } else {
      // Basic North American character set.
      currentCueBuilder.append(getBasicChar(ccData1));
      if ((ccData2 & 0xE0) != 0x00) {
        currentCueBuilder.append(getBasicChar(ccData2));
      }
    }
    captionDataProcessed = true;
  }

  if (captionDataProcessed) {
    if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
      cues = getDisplayCues();
    }
  }
}
 
Example #16
Source File: Cea708Decoder.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe.
  @SuppressWarnings("ByteBufferBackingArray")
  byte[] inputBufferData = inputBuffer.data.array();
  ccData.reset(inputBufferData, inputBuffer.data.limit());
  while (ccData.bytesLeft() >= 3) {
    int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);

    int ccType = ccTypeAndValid & (DTVCC_PACKET_DATA | DTVCC_PACKET_START);
    boolean ccValid = (ccTypeAndValid & CC_VALID_FLAG) == CC_VALID_FLAG;
    byte ccData1 = (byte) ccData.readUnsignedByte();
    byte ccData2 = (byte) ccData.readUnsignedByte();

    // Ignore any non-CEA-708 data
    if (ccType != DTVCC_PACKET_DATA && ccType != DTVCC_PACKET_START) {
      continue;
    }

    if (!ccValid) {
      // This byte-pair isn't valid, ignore it and continue.
      continue;
    }

    if (ccType == DTVCC_PACKET_START) {
      finalizeCurrentPacket();

      int sequenceNumber = (ccData1 & 0xC0) >> 6; // first 2 bits
      int packetSize = ccData1 & 0x3F; // last 6 bits
      if (packetSize == 0) {
        packetSize = 64;
      }

      currentDtvCcPacket = new DtvCcPacket(sequenceNumber, packetSize);
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    } else {
      // The only remaining valid packet type is DTVCC_PACKET_DATA
      Assertions.checkArgument(ccType == DTVCC_PACKET_DATA);

      if (currentDtvCcPacket == null) {
        Log.e(TAG, "Encountered DTVCC_PACKET_DATA before DTVCC_PACKET_START");
        continue;
      }

      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData1;
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    }

    if (currentDtvCcPacket.currentIndex == (currentDtvCcPacket.packetSize * 2 - 1)) {
      finalizeCurrentPacket();
    }
  }
}
 
Example #17
Source File: Cea608Decoder.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
@SuppressWarnings("ByteBufferBackingArray")
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  boolean captionDataProcessed = false;
  while (ccData.bytesLeft() >= packetLength) {
    byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
        : (byte) ccData.readUnsignedByte();
    int ccByte1 = ccData.readUnsignedByte();
    int ccByte2 = ccData.readUnsignedByte();

    // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
    // to the CEA-608 specification. We need to determine if the data should be handled
    // differently when that is not the case.

    if ((ccHeader & CC_TYPE_FLAG) != 0) {
      // Do not process anything that is not part of the 608 byte stream.
      continue;
    }

    if ((ccHeader & CC_FIELD_FLAG) != selectedField) {
      // Do not process packets not within the selected field.
      continue;
    }

    // Strip the parity bit from each byte to get CC data.
    byte ccData1 = (byte) (ccByte1 & 0x7F);
    byte ccData2 = (byte) (ccByte2 & 0x7F);

    if (ccData1 == 0 && ccData2 == 0) {
      // Ignore empty captions.
      continue;
    }

    boolean previousIsCaptionValid = isCaptionValid;
    isCaptionValid =
        (ccHeader & CC_VALID_FLAG) == CC_VALID_FLAG
            && ODD_PARITY_BYTE_TABLE[ccByte1]
            && ODD_PARITY_BYTE_TABLE[ccByte2];

    if (isRepeatedCommand(isCaptionValid, ccData1, ccData2)) {
      // Ignore repeated valid commands.
      continue;
    }

    if (!isCaptionValid) {
      if (previousIsCaptionValid) {
        // The encoder has flipped the validity bit to indicate captions are being turned off.
        resetCueBuilders();
        captionDataProcessed = true;
      }
      continue;
    }

    maybeUpdateIsInCaptionService(ccData1, ccData2);
    if (!isInCaptionService) {
      // Only the Captioning service is supported. Drop all other bytes.
      continue;
    }

    if (!updateAndVerifyCurrentChannel(ccData1)) {
      // Wrong channel.
      continue;
    }

    if (isCtrlCode(ccData1)) {
      if (isSpecialNorthAmericanChar(ccData1, ccData2)) {
        currentCueBuilder.append(getSpecialNorthAmericanChar(ccData2));
      } else if (isExtendedWestEuropeanChar(ccData1, ccData2)) {
        // Remove standard equivalent of the special extended char before appending new one.
        currentCueBuilder.backspace();
        currentCueBuilder.append(getExtendedWestEuropeanChar(ccData1, ccData2));
      } else if (isMidrowCtrlCode(ccData1, ccData2)) {
        handleMidrowCtrl(ccData2);
      } else if (isPreambleAddressCode(ccData1, ccData2)) {
        handlePreambleAddressCode(ccData1, ccData2);
      } else if (isTabCtrlCode(ccData1, ccData2)) {
        currentCueBuilder.tabOffset = ccData2 - 0x20;
      } else if (isMiscCode(ccData1, ccData2)) {
        handleMiscCode(ccData2);
      }
    } else {
      // Basic North American character set.
      currentCueBuilder.append(getBasicChar(ccData1));
      if ((ccData2 & 0xE0) != 0x00) {
        currentCueBuilder.append(getBasicChar(ccData2));
      }
    }
    captionDataProcessed = true;
  }

  if (captionDataProcessed) {
    if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
      cues = getDisplayCues();
    }
  }
}
 
Example #18
Source File: Cea708Decoder.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe.
  @SuppressWarnings("ByteBufferBackingArray")
  byte[] inputBufferData = inputBuffer.data.array();
  ccData.reset(inputBufferData, inputBuffer.data.limit());
  while (ccData.bytesLeft() >= 3) {
    int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);

    int ccType = ccTypeAndValid & (DTVCC_PACKET_DATA | DTVCC_PACKET_START);
    boolean ccValid = (ccTypeAndValid & CC_VALID_FLAG) == CC_VALID_FLAG;
    byte ccData1 = (byte) ccData.readUnsignedByte();
    byte ccData2 = (byte) ccData.readUnsignedByte();

    // Ignore any non-CEA-708 data
    if (ccType != DTVCC_PACKET_DATA && ccType != DTVCC_PACKET_START) {
      continue;
    }

    if (!ccValid) {
      // This byte-pair isn't valid, ignore it and continue.
      continue;
    }

    if (ccType == DTVCC_PACKET_START) {
      finalizeCurrentPacket();

      int sequenceNumber = (ccData1 & 0xC0) >> 6; // first 2 bits
      int packetSize = ccData1 & 0x3F; // last 6 bits
      if (packetSize == 0) {
        packetSize = 64;
      }

      currentDtvCcPacket = new DtvCcPacket(sequenceNumber, packetSize);
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    } else {
      // The only remaining valid packet type is DTVCC_PACKET_DATA
      Assertions.checkArgument(ccType == DTVCC_PACKET_DATA);

      if (currentDtvCcPacket == null) {
        Log.e(TAG, "Encountered DTVCC_PACKET_DATA before DTVCC_PACKET_START");
        continue;
      }

      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData1;
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    }

    if (currentDtvCcPacket.currentIndex == (currentDtvCcPacket.packetSize * 2 - 1)) {
      finalizeCurrentPacket();
    }
  }
}
 
Example #19
Source File: Cea708Decoder.java    From MediaSDK with Apache License 2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe.
  @SuppressWarnings("ByteBufferBackingArray")
  byte[] inputBufferData = inputBuffer.data.array();
  ccData.reset(inputBufferData, inputBuffer.data.limit());
  while (ccData.bytesLeft() >= 3) {
    int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);

    int ccType = ccTypeAndValid & (DTVCC_PACKET_DATA | DTVCC_PACKET_START);
    boolean ccValid = (ccTypeAndValid & CC_VALID_FLAG) == CC_VALID_FLAG;
    byte ccData1 = (byte) ccData.readUnsignedByte();
    byte ccData2 = (byte) ccData.readUnsignedByte();

    // Ignore any non-CEA-708 data
    if (ccType != DTVCC_PACKET_DATA && ccType != DTVCC_PACKET_START) {
      continue;
    }

    if (!ccValid) {
      // This byte-pair isn't valid, ignore it and continue.
      continue;
    }

    if (ccType == DTVCC_PACKET_START) {
      finalizeCurrentPacket();

      int sequenceNumber = (ccData1 & 0xC0) >> 6; // first 2 bits
      int packetSize = ccData1 & 0x3F; // last 6 bits
      if (packetSize == 0) {
        packetSize = 64;
      }

      currentDtvCcPacket = new DtvCcPacket(sequenceNumber, packetSize);
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    } else {
      // The only remaining valid packet type is DTVCC_PACKET_DATA
      Assertions.checkArgument(ccType == DTVCC_PACKET_DATA);

      if (currentDtvCcPacket == null) {
        Log.e(TAG, "Encountered DTVCC_PACKET_DATA before DTVCC_PACKET_START");
        continue;
      }

      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData1;
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    }

    if (currentDtvCcPacket.currentIndex == (currentDtvCcPacket.packetSize * 2 - 1)) {
      finalizeCurrentPacket();
    }
  }
}
 
Example #20
Source File: Cea608Decoder.java    From MediaSDK with Apache License 2.0 4 votes vote down vote up
@SuppressWarnings("ByteBufferBackingArray")
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  boolean captionDataProcessed = false;
  while (ccData.bytesLeft() >= packetLength) {
    byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
        : (byte) ccData.readUnsignedByte();
    int ccByte1 = ccData.readUnsignedByte();
    int ccByte2 = ccData.readUnsignedByte();

    // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
    // to the CEA-608 specification. We need to determine if the data should be handled
    // differently when that is not the case.

    if ((ccHeader & CC_TYPE_FLAG) != 0) {
      // Do not process anything that is not part of the 608 byte stream.
      continue;
    }

    if ((ccHeader & CC_FIELD_FLAG) != selectedField) {
      // Do not process packets not within the selected field.
      continue;
    }

    // Strip the parity bit from each byte to get CC data.
    byte ccData1 = (byte) (ccByte1 & 0x7F);
    byte ccData2 = (byte) (ccByte2 & 0x7F);

    if (ccData1 == 0 && ccData2 == 0) {
      // Ignore empty captions.
      continue;
    }

    boolean previousIsCaptionValid = isCaptionValid;
    isCaptionValid =
        (ccHeader & CC_VALID_FLAG) == CC_VALID_FLAG
            && ODD_PARITY_BYTE_TABLE[ccByte1]
            && ODD_PARITY_BYTE_TABLE[ccByte2];

    if (isRepeatedCommand(isCaptionValid, ccData1, ccData2)) {
      // Ignore repeated valid commands.
      continue;
    }

    if (!isCaptionValid) {
      if (previousIsCaptionValid) {
        // The encoder has flipped the validity bit to indicate captions are being turned off.
        resetCueBuilders();
        captionDataProcessed = true;
      }
      continue;
    }

    maybeUpdateIsInCaptionService(ccData1, ccData2);
    if (!isInCaptionService) {
      // Only the Captioning service is supported. Drop all other bytes.
      continue;
    }

    if (!updateAndVerifyCurrentChannel(ccData1)) {
      // Wrong channel.
      continue;
    }

    if (isCtrlCode(ccData1)) {
      if (isSpecialNorthAmericanChar(ccData1, ccData2)) {
        currentCueBuilder.append(getSpecialNorthAmericanChar(ccData2));
      } else if (isExtendedWestEuropeanChar(ccData1, ccData2)) {
        // Remove standard equivalent of the special extended char before appending new one.
        currentCueBuilder.backspace();
        currentCueBuilder.append(getExtendedWestEuropeanChar(ccData1, ccData2));
      } else if (isMidrowCtrlCode(ccData1, ccData2)) {
        handleMidrowCtrl(ccData2);
      } else if (isPreambleAddressCode(ccData1, ccData2)) {
        handlePreambleAddressCode(ccData1, ccData2);
      } else if (isTabCtrlCode(ccData1, ccData2)) {
        currentCueBuilder.tabOffset = ccData2 - 0x20;
      } else if (isMiscCode(ccData1, ccData2)) {
        handleMiscCode(ccData2);
      }
    } else {
      // Basic North American character set.
      currentCueBuilder.append(getBasicChar(ccData1));
      if ((ccData2 & 0xE0) != 0x00) {
        currentCueBuilder.append(getBasicChar(ccData2));
      }
    }
    captionDataProcessed = true;
  }

  if (captionDataProcessed) {
    if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
      cues = getDisplayCues();
    }
  }
}
 
Example #21
Source File: Cea608Decoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  boolean captionDataProcessed = false;
  boolean isRepeatableControl = false;
  while (ccData.bytesLeft() >= packetLength) {
    byte ccDataHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
        : (byte) ccData.readUnsignedByte();
    byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit
    byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit

    // Only examine valid CEA-608 packets
    // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
    // to the CEA-608 specification. We need to determine if the data should be handled
    // differently when that is not the case.
    if ((ccDataHeader & (CC_VALID_FLAG | CC_TYPE_FLAG)) != CC_VALID_608_ID) {
      continue;
    }

    // Only examine packets within the selected field
    if ((selectedField == 1 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_1)
        || (selectedField == 2 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_2)) {
      continue;
    }

    // Ignore empty captions.
    if (ccData1 == 0 && ccData2 == 0) {
      continue;
    }

    // If we've reached this point then there is data to process; flag that work has been done.
    captionDataProcessed = true;

    // Special North American character set.
    // ccData1 - 0|0|0|1|C|0|0|1
    // ccData2 - 0|0|1|1|X|X|X|X
    if (((ccData1 & 0xF7) == 0x11) && ((ccData2 & 0xF0) == 0x30)) {
      // TODO: Make use of the channel toggle
      currentCueBuilder.append(getSpecialChar(ccData2));
      continue;
    }

    // Extended Western European character set.
    // ccData1 - 0|0|0|1|C|0|1|S
    // ccData2 - 0|0|1|X|X|X|X|X
    if (((ccData1 & 0xF6) == 0x12) && (ccData2 & 0xE0) == 0x20) {
      // TODO: Make use of the channel toggle
      // Remove standard equivalent of the special extended char before appending new one
      currentCueBuilder.backspace();
      if ((ccData1 & 0x01) == 0x00) {
        // Extended Spanish/Miscellaneous and French character set (S = 0).
        currentCueBuilder.append(getExtendedEsFrChar(ccData2));
      } else {
        // Extended Portuguese and German/Danish character set (S = 1).
        currentCueBuilder.append(getExtendedPtDeChar(ccData2));
      }
      continue;
    }

    // Control character.
    // ccData1 - 0|0|0|X|X|X|X|X
    if ((ccData1 & 0xE0) == 0x00) {
      isRepeatableControl = handleCtrl(ccData1, ccData2);
      continue;
    }

    // Basic North American character set.
    currentCueBuilder.append(getChar(ccData1));
    if ((ccData2 & 0xE0) != 0x00) {
      currentCueBuilder.append(getChar(ccData2));
    }
  }

  if (captionDataProcessed) {
    if (!isRepeatableControl) {
      repeatableControlSet = false;
    }
    if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
      cues = getDisplayCues();
    }
  }
}
 
Example #22
Source File: Cea708Decoder.java    From K-Sonic with MIT License 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  while (ccData.bytesLeft() >= 3) {
    int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);

    int ccType = ccTypeAndValid & (DTVCC_PACKET_DATA | DTVCC_PACKET_START);
    boolean ccValid = (ccTypeAndValid & CC_VALID_FLAG) == CC_VALID_FLAG;
    byte ccData1 = (byte) ccData.readUnsignedByte();
    byte ccData2 = (byte) ccData.readUnsignedByte();

    // Ignore any non-CEA-708 data
    if (ccType != DTVCC_PACKET_DATA && ccType != DTVCC_PACKET_START) {
      continue;
    }

    if (!ccValid) {
      // This byte-pair isn't valid, ignore it and continue.
      continue;
    }

    if (ccType == DTVCC_PACKET_START) {
      finalizeCurrentPacket();

      int sequenceNumber = (ccData1 & 0xC0) >> 6; // first 2 bits
      int packetSize = ccData1 & 0x3F; // last 6 bits
      if (packetSize == 0) {
        packetSize = 64;
      }

      currentDtvCcPacket = new DtvCcPacket(sequenceNumber, packetSize);
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    } else {
      // The only remaining valid packet type is DTVCC_PACKET_DATA
      Assertions.checkArgument(ccType == DTVCC_PACKET_DATA);

      if (currentDtvCcPacket == null) {
        Log.e(TAG, "Encountered DTVCC_PACKET_DATA before DTVCC_PACKET_START");
        continue;
      }

      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData1;
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    }

    if (currentDtvCcPacket.currentIndex == (currentDtvCcPacket.packetSize * 2 - 1)) {
      finalizeCurrentPacket();
    }
  }
}
 
Example #23
Source File: CeaDecoder.java    From K-Sonic with MIT License 4 votes vote down vote up
private void releaseInputBuffer(SubtitleInputBuffer inputBuffer) {
  inputBuffer.clear();
  availableInputBuffers.add(inputBuffer);
}
 
Example #24
Source File: Cea608Decoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
  boolean captionDataProcessed = false;
  boolean isRepeatableControl = false;
  while (ccData.bytesLeft() >= packetLength) {
    byte ccDataHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
        : (byte) ccData.readUnsignedByte();
    byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit
    byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit

    // Only examine valid CEA-608 packets
    // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
    // to the CEA-608 specification. We need to determine if the data should be handled
    // differently when that is not the case.
    if ((ccDataHeader & (CC_VALID_FLAG | CC_TYPE_FLAG)) != CC_VALID_608_ID) {
      continue;
    }

    // Only examine packets within the selected field
    if ((selectedField == 1 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_1)
        || (selectedField == 2 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_2)) {
      continue;
    }

    // Ignore empty captions.
    if (ccData1 == 0 && ccData2 == 0) {
      continue;
    }

    // If we've reached this point then there is data to process; flag that work has been done.
    captionDataProcessed = true;

    // Special North American character set.
    // ccData1 - 0|0|0|1|C|0|0|1
    // ccData2 - 0|0|1|1|X|X|X|X
    if (((ccData1 & 0xF7) == 0x11) && ((ccData2 & 0xF0) == 0x30)) {
      // TODO: Make use of the channel toggle
      currentCueBuilder.append(getSpecialChar(ccData2));
      continue;
    }

    // Extended Western European character set.
    // ccData1 - 0|0|0|1|C|0|1|S
    // ccData2 - 0|0|1|X|X|X|X|X
    if (((ccData1 & 0xF6) == 0x12) && (ccData2 & 0xE0) == 0x20) {
      // TODO: Make use of the channel toggle
      // Remove standard equivalent of the special extended char before appending new one
      currentCueBuilder.backspace();
      if ((ccData1 & 0x01) == 0x00) {
        // Extended Spanish/Miscellaneous and French character set (S = 0).
        currentCueBuilder.append(getExtendedEsFrChar(ccData2));
      } else {
        // Extended Portuguese and German/Danish character set (S = 1).
        currentCueBuilder.append(getExtendedPtDeChar(ccData2));
      }
      continue;
    }

    // Control character.
    // ccData1 - 0|0|0|X|X|X|X|X
    if ((ccData1 & 0xE0) == 0x00) {
      isRepeatableControl = handleCtrl(ccData1, ccData2);
      continue;
    }

    // Basic North American character set.
    currentCueBuilder.append(getChar(ccData1));
    if ((ccData2 & 0xE0) != 0x00) {
      currentCueBuilder.append(getChar(ccData2));
    }
  }

  if (captionDataProcessed) {
    if (!isRepeatableControl) {
      repeatableControlSet = false;
    }
    if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
      cues = getDisplayCues();
    }
  }
}
 
Example #25
Source File: Cea708Decoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe.
  @SuppressWarnings("ByteBufferBackingArray")
  byte[] inputBufferData = inputBuffer.data.array();
  ccData.reset(inputBufferData, inputBuffer.data.limit());
  while (ccData.bytesLeft() >= 3) {
    int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);

    int ccType = ccTypeAndValid & (DTVCC_PACKET_DATA | DTVCC_PACKET_START);
    boolean ccValid = (ccTypeAndValid & CC_VALID_FLAG) == CC_VALID_FLAG;
    byte ccData1 = (byte) ccData.readUnsignedByte();
    byte ccData2 = (byte) ccData.readUnsignedByte();

    // Ignore any non-CEA-708 data
    if (ccType != DTVCC_PACKET_DATA && ccType != DTVCC_PACKET_START) {
      continue;
    }

    if (!ccValid) {
      // This byte-pair isn't valid, ignore it and continue.
      continue;
    }

    if (ccType == DTVCC_PACKET_START) {
      finalizeCurrentPacket();

      int sequenceNumber = (ccData1 & 0xC0) >> 6; // first 2 bits
      int packetSize = ccData1 & 0x3F; // last 6 bits
      if (packetSize == 0) {
        packetSize = 64;
      }

      currentDtvCcPacket = new DtvCcPacket(sequenceNumber, packetSize);
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    } else {
      // The only remaining valid packet type is DTVCC_PACKET_DATA
      Assertions.checkArgument(ccType == DTVCC_PACKET_DATA);

      if (currentDtvCcPacket == null) {
        Log.e(TAG, "Encountered DTVCC_PACKET_DATA before DTVCC_PACKET_START");
        continue;
      }

      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData1;
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    }

    if (currentDtvCcPacket.currentIndex == (currentDtvCcPacket.packetSize * 2 - 1)) {
      finalizeCurrentPacket();
    }
  }
}
 
Example #26
Source File: Cea708Decoder.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
  // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe.
  @SuppressWarnings("ByteBufferBackingArray")
  byte[] inputBufferData = inputBuffer.data.array();
  ccData.reset(inputBufferData, inputBuffer.data.limit());
  while (ccData.bytesLeft() >= 3) {
    int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);

    int ccType = ccTypeAndValid & (DTVCC_PACKET_DATA | DTVCC_PACKET_START);
    boolean ccValid = (ccTypeAndValid & CC_VALID_FLAG) == CC_VALID_FLAG;
    byte ccData1 = (byte) ccData.readUnsignedByte();
    byte ccData2 = (byte) ccData.readUnsignedByte();

    // Ignore any non-CEA-708 data
    if (ccType != DTVCC_PACKET_DATA && ccType != DTVCC_PACKET_START) {
      continue;
    }

    if (!ccValid) {
      // This byte-pair isn't valid, ignore it and continue.
      continue;
    }

    if (ccType == DTVCC_PACKET_START) {
      finalizeCurrentPacket();

      int sequenceNumber = (ccData1 & 0xC0) >> 6; // first 2 bits
      int packetSize = ccData1 & 0x3F; // last 6 bits
      if (packetSize == 0) {
        packetSize = 64;
      }

      currentDtvCcPacket = new DtvCcPacket(sequenceNumber, packetSize);
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    } else {
      // The only remaining valid packet type is DTVCC_PACKET_DATA
      Assertions.checkArgument(ccType == DTVCC_PACKET_DATA);

      if (currentDtvCcPacket == null) {
        Log.e(TAG, "Encountered DTVCC_PACKET_DATA before DTVCC_PACKET_START");
        continue;
      }

      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData1;
      currentDtvCcPacket.packetData[currentDtvCcPacket.currentIndex++] = ccData2;
    }

    if (currentDtvCcPacket.currentIndex == (currentDtvCcPacket.packetSize * 2 - 1)) {
      finalizeCurrentPacket();
    }
  }
}
 
Example #27
Source File: CeaDecoder.java    From K-Sonic with MIT License 2 votes vote down vote up
/**
 * Filters and processes the raw data, providing {@link Subtitle}s via {@link #createSubtitle()}
 * when sufficient data has been processed.
 */
protected abstract void decode(SubtitleInputBuffer inputBuffer);
 
Example #28
Source File: CeaDecoder.java    From Telegram-FOSS with GNU General Public License v2.0 2 votes vote down vote up
/**
 * Filters and processes the raw data, providing {@link Subtitle}s via {@link #createSubtitle()}
 * when sufficient data has been processed.
 */
protected abstract void decode(SubtitleInputBuffer inputBuffer);
 
Example #29
Source File: CeaDecoder.java    From TelePlus-Android with GNU General Public License v2.0 2 votes vote down vote up
/**
 * Filters and processes the raw data, providing {@link Subtitle}s via {@link #createSubtitle()}
 * when sufficient data has been processed.
 */
protected abstract void decode(SubtitleInputBuffer inputBuffer);
 
Example #30
Source File: CeaDecoder.java    From MediaSDK with Apache License 2.0 2 votes vote down vote up
/**
 * Filters and processes the raw data, providing {@link Subtitle}s via {@link #createSubtitle()}
 * when sufficient data has been processed.
 */
protected abstract void decode(SubtitleInputBuffer inputBuffer);