use of com.google.android.exoplayer2.util.ParsableBitArray in project ExoPlayer by google.
the class DvbParser method paintPixelDataSubBlock.
/**
* Draws a pixel data sub-block, as defined by ETSI EN 300 743 7.2.5.1, into a canvas.
*/
private static void paintPixelDataSubBlock(byte[] pixelData, int[] clutEntries, int regionDepth, int horizontalAddress, int verticalAddress, @Nullable Paint paint, Canvas canvas) {
ParsableBitArray data = new ParsableBitArray(pixelData);
int column = horizontalAddress;
int line = verticalAddress;
@Nullable byte[] clutMapTable2To4 = null;
@Nullable byte[] clutMapTable2To8 = null;
@Nullable byte[] clutMapTable4To8 = null;
while (data.bitsLeft() != 0) {
int dataType = data.readBits(8);
switch(dataType) {
case DATA_TYPE_2BP_CODE_STRING:
@Nullable byte[] clutMapTable2ToX;
if (regionDepth == REGION_DEPTH_8_BIT) {
clutMapTable2ToX = clutMapTable2To8 == null ? defaultMap2To8 : clutMapTable2To8;
} else if (regionDepth == REGION_DEPTH_4_BIT) {
clutMapTable2ToX = clutMapTable2To4 == null ? defaultMap2To4 : clutMapTable2To4;
} else {
clutMapTable2ToX = null;
}
column = paint2BitPixelCodeString(data, clutEntries, clutMapTable2ToX, column, line, paint, canvas);
data.byteAlign();
break;
case DATA_TYPE_4BP_CODE_STRING:
@Nullable byte[] clutMapTable4ToX;
if (regionDepth == REGION_DEPTH_8_BIT) {
clutMapTable4ToX = clutMapTable4To8 == null ? defaultMap4To8 : clutMapTable4To8;
} else {
clutMapTable4ToX = null;
}
column = paint4BitPixelCodeString(data, clutEntries, clutMapTable4ToX, column, line, paint, canvas);
data.byteAlign();
break;
case DATA_TYPE_8BP_CODE_STRING:
column = paint8BitPixelCodeString(data, clutEntries, /* clutMapTable= */
null, column, line, paint, canvas);
break;
case DATA_TYPE_24_TABLE_DATA:
clutMapTable2To4 = buildClutMapTable(4, 4, data);
break;
case DATA_TYPE_28_TABLE_DATA:
clutMapTable2To8 = buildClutMapTable(4, 8, data);
break;
case DATA_TYPE_48_TABLE_DATA:
clutMapTable4To8 = buildClutMapTable(16, 8, data);
break;
case DATA_TYPE_END_LINE:
column = horizontalAddress;
line += 2;
break;
default:
// Do nothing.
break;
}
}
}
use of com.google.android.exoplayer2.util.ParsableBitArray in project ExoPlayer by google.
the class AdtsExtractor method sniff.
@Override
public boolean sniff(ExtractorInput input) throws IOException, InterruptedException {
// Skip any ID3 headers.
ParsableByteArray scratch = new ParsableByteArray(10);
ParsableBitArray scratchBits = new ParsableBitArray(scratch.data);
int startPosition = 0;
while (true) {
input.peekFully(scratch.data, 0, 10);
scratch.setPosition(0);
if (scratch.readUnsignedInt24() != ID3_TAG) {
break;
}
scratch.skipBytes(3);
int length = scratch.readSynchSafeInt();
startPosition += 10 + length;
input.advancePeekPosition(length);
}
input.resetPeekPosition();
input.advancePeekPosition(startPosition);
// Try to find four or more consecutive AAC audio frames, exceeding the MPEG TS packet size.
int headerPosition = startPosition;
int validFramesSize = 0;
int validFramesCount = 0;
while (true) {
input.peekFully(scratch.data, 0, 2);
scratch.setPosition(0);
int syncBytes = scratch.readUnsignedShort();
if ((syncBytes & 0xFFF6) != 0xFFF0) {
validFramesCount = 0;
validFramesSize = 0;
input.resetPeekPosition();
if (++headerPosition - startPosition >= MAX_SNIFF_BYTES) {
return false;
}
input.advancePeekPosition(headerPosition);
} else {
if (++validFramesCount >= 4 && validFramesSize > 188) {
return true;
}
// Skip the frame.
input.peekFully(scratch.data, 0, 4);
scratchBits.setPosition(14);
int frameSize = scratchBits.readBits(13);
// Either the stream is malformed OR we're not parsing an ADTS stream.
if (frameSize <= 6) {
return false;
}
input.advancePeekPosition(frameSize - 6);
validFramesSize += frameSize;
}
}
}
use of com.google.android.exoplayer2.util.ParsableBitArray in project ExoPlayer by google.
the class FlacMetadataReader method readMetadataBlock.
/**
* Reads one FLAC metadata block.
*
* <p>If no exception is thrown, the peek position of {@code input} is aligned with the read
* position.
*
* @param input Input stream to read the metadata block from (header included).
* @param metadataHolder A holder for the metadata read. If the stream info block (which must be
* the first metadata block) is read, the holder contains a new instance representing the
* stream info data. If the block read is a Vorbis comment block or a picture block, the
* holder contains a copy of the existing stream metadata with the corresponding metadata
* added. Otherwise, the metadata in the holder is unchanged.
* @return Whether the block read is the last metadata block.
* @throws IllegalArgumentException If the block read is not a stream info block and the metadata
* in {@code metadataHolder} is {@code null}. In this case, the read position will be at the
* start of a metadata block and there is no guarantee on the peek position.
* @throws IOException If reading from the input fails. In this case, the read position will be at
* the start of a metadata block and there is no guarantee on the peek position.
*/
public static boolean readMetadataBlock(ExtractorInput input, FlacStreamMetadataHolder metadataHolder) throws IOException {
input.resetPeekPosition();
ParsableBitArray scratch = new ParsableBitArray(new byte[4]);
input.peekFully(scratch.data, 0, FlacConstants.METADATA_BLOCK_HEADER_SIZE);
boolean isLastMetadataBlock = scratch.readBit();
int type = scratch.readBits(7);
int length = FlacConstants.METADATA_BLOCK_HEADER_SIZE + scratch.readBits(24);
if (type == FlacConstants.METADATA_TYPE_STREAM_INFO) {
metadataHolder.flacStreamMetadata = readStreamInfoBlock(input);
} else {
@Nullable FlacStreamMetadata flacStreamMetadata = metadataHolder.flacStreamMetadata;
if (flacStreamMetadata == null) {
throw new IllegalArgumentException();
}
if (type == FlacConstants.METADATA_TYPE_SEEK_TABLE) {
FlacStreamMetadata.SeekTable seekTable = readSeekTableMetadataBlock(input, length);
metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithSeekTable(seekTable);
} else if (type == FlacConstants.METADATA_TYPE_VORBIS_COMMENT) {
List<String> vorbisComments = readVorbisCommentMetadataBlock(input, length);
metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithVorbisComments(vorbisComments);
} else if (type == FlacConstants.METADATA_TYPE_PICTURE) {
ParsableByteArray pictureBlock = new ParsableByteArray(length);
input.readFully(pictureBlock.getData(), 0, length);
pictureBlock.skipBytes(FlacConstants.METADATA_BLOCK_HEADER_SIZE);
PictureFrame pictureFrame = PictureFrame.fromPictureBlock(pictureBlock);
metadataHolder.flacStreamMetadata = flacStreamMetadata.copyWithPictureFrames(ImmutableList.of(pictureFrame));
} else {
input.skipFully(length);
}
}
return isLastMetadataBlock;
}
use of com.google.android.exoplayer2.util.ParsableBitArray in project ExoPlayer by google.
the class DtsUtil method getNormalizedFrameHeader.
private static ParsableBitArray getNormalizedFrameHeader(byte[] frameHeader) {
if (frameHeader[0] == FIRST_BYTE_BE) {
// The frame is already 16-bit mode, big endian.
return new ParsableBitArray(frameHeader);
}
// Data is not normalized, but we don't want to modify frameHeader.
frameHeader = Arrays.copyOf(frameHeader, frameHeader.length);
if (isLittleEndianFrameHeader(frameHeader)) {
// Change endianness.
for (int i = 0; i < frameHeader.length - 1; i += 2) {
byte temp = frameHeader[i];
frameHeader[i] = frameHeader[i + 1];
frameHeader[i + 1] = temp;
}
}
ParsableBitArray frameBits = new ParsableBitArray(frameHeader);
if (frameHeader[0] == (byte) (SYNC_VALUE_14B_BE >> 24)) {
// Discard the 2 most significant bits of each 16 bit word.
ParsableBitArray scratchBits = new ParsableBitArray(frameHeader);
while (scratchBits.bitsLeft() >= 16) {
scratchBits.skipBits(2);
frameBits.putInt(scratchBits.readBits(14), 14);
}
}
frameBits.reset(frameHeader);
return frameBits;
}
use of com.google.android.exoplayer2.util.ParsableBitArray in project ExoPlayer by google.
the class AppInfoTableDecoder method parseAit.
@Nullable
private static Metadata parseAit(ParsableBitArray sectionData) {
// tableId, section_syntax_indication, reserved_future_use, reserved
sectionData.skipBits(12);
int sectionLength = sectionData.readBits(12);
int endOfSection = sectionData.getBytePosition() + sectionLength - 4;
// test_application_flag, application_type, reserved, version_number, current_next_indicator,
// section_number, last_section_number, reserved_future_use
sectionData.skipBits(44);
int commonDescriptorsLength = sectionData.readBits(12);
// Since we currently only keep URL and control code, which are unique per application,
// there is no useful information in common descriptor.
sectionData.skipBytes(commonDescriptorsLength);
// reserved_future_use, application_loop_length
sectionData.skipBits(16);
ArrayList<AppInfoTable> appInfoTables = new ArrayList<>();
while (sectionData.getBytePosition() < endOfSection) {
@Nullable String urlBase = null;
@Nullable String urlExtension = null;
// application_identifier
sectionData.skipBits(48);
int controlCode = sectionData.readBits(8);
// reserved_future_use
sectionData.skipBits(4);
int applicationDescriptorsLoopLength = sectionData.readBits(12);
int positionOfNextApplication = sectionData.getBytePosition() + applicationDescriptorsLoopLength;
while (sectionData.getBytePosition() < positionOfNextApplication) {
int descriptorTag = sectionData.readBits(8);
int descriptorLength = sectionData.readBits(8);
int positionOfNextDescriptor = sectionData.getBytePosition() + descriptorLength;
if (descriptorTag == DESCRIPTOR_TRANSPORT_PROTOCOL) {
// See section 5.3.6.
int protocolId = sectionData.readBits(16);
// label
sectionData.skipBits(8);
if (protocolId == TRANSPORT_PROTOCOL_HTTP) {
// See section 5.3.6.2.
while (sectionData.getBytePosition() < positionOfNextDescriptor) {
int urlBaseLength = sectionData.readBits(8);
urlBase = sectionData.readBytesAsString(urlBaseLength, Charsets.US_ASCII);
int extensionCount = sectionData.readBits(8);
for (int urlExtensionIndex = 0; urlExtensionIndex < extensionCount; urlExtensionIndex++) {
int urlExtensionLength = sectionData.readBits(8);
sectionData.skipBytes(urlExtensionLength);
}
}
}
} else if (descriptorTag == DESCRIPTOR_SIMPLE_APPLICATION_LOCATION) {
// See section 5.3.7.
urlExtension = sectionData.readBytesAsString(descriptorLength, Charsets.US_ASCII);
}
sectionData.setPosition(positionOfNextDescriptor * 8);
}
sectionData.setPosition(positionOfNextApplication * 8);
if (urlBase != null && urlExtension != null) {
appInfoTables.add(new AppInfoTable(controlCode, urlBase + urlExtension));
}
}
return appInfoTables.isEmpty() ? null : new Metadata(appInfoTables);
}
Aggregations