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<>(); }
@Override public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException { Assertions.checkState(dequeuedInputBuffer == null); if (availableInputBuffers.isEmpty()) { return null; } dequeuedInputBuffer = availableInputBuffers.pollFirst(); return dequeuedInputBuffer; }
@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; }
@Override public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException { Assertions.checkArgument(inputBuffer != null); Assertions.checkArgument(inputBuffer == dequeuedInputBuffer); queuedInputBuffers.add(inputBuffer); dequeuedInputBuffer = null; }
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 PriorityQueue<>(); }
@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(inputBuffer); } else { queuedInputBuffers.add(inputBuffer); } dequeuedInputBuffer = null; }
private void releaseInputBuffer(SubtitleInputBuffer inputBuffer) { inputBuffer.clear(); availableInputBuffers.add(inputBuffer); }
@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(); } } }
@Override protected void decode(SubtitleInputBuffer inputBuffer) { ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit()); boolean captionDataProcessed = false; boolean isRepeatableControl = false; while (ccData.bytesLeft() > 0) { byte ccTypeAndValid = (byte) (ccData.readUnsignedByte() & 0x07); byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F); byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F); // Only examine valid NTSC_CC_FIELD_1 packets if (ccTypeAndValid != (CC_VALID_FLAG | NTSC_CC_FIELD_1)) { // TODO: Add support for NTSC_CC_FIELD_2 packets 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 - P|0|0|1|C|0|0|1 // ccData2 - P|0|1|1|X|X|X|X if ((ccData1 == 0x11 || ccData1 == 0x19) && ((ccData2 & 0x70) == 0x30)) { // TODO: Make use of the channel bit captionStringBuilder.append(getSpecialChar(ccData2)); continue; } // Extended Western European character set. // ccData1 - P|0|0|1|C|0|1|S // ccData2 - P|0|1|X|X|X|X|X if ((ccData2 & 0x60) == 0x20) { // Extended Spanish/Miscellaneous and French character set (S = 0). if (ccData1 == 0x12 || ccData1 == 0x1A) { // TODO: Make use of the channel bit backspace(); // Remove standard equivalent of the special extended char. captionStringBuilder.append(getExtendedEsFrChar(ccData2)); continue; } // Extended Portuguese and German/Danish character set (S = 1). if (ccData1 == 0x13 || ccData1 == 0x1B) { // TODO: Make use of the channel bit backspace(); // Remove standard equivalent of the special extended char. captionStringBuilder.append(getExtendedPtDeChar(ccData2)); continue; } } // Control character. if (ccData1 < 0x20) { isRepeatableControl = handleCtrl(ccData1, ccData2); continue; } // Basic North American character set. captionStringBuilder.append(getChar(ccData1)); if (ccData2 >= 0x20) { captionStringBuilder.append(getChar(ccData2)); } } if (captionDataProcessed) { if (!isRepeatableControl) { repeatableControlSet = false; } if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) { captionString = getDisplayCaption(); } } }
/** * 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);