use of androidx.media3.common.util.ParsableByteArray in project media by androidx.
the class StreamReader method readPayload.
@RequiresNonNull({ "trackOutput", "oggSeeker", "extractorOutput" })
private int readPayload(ExtractorInput input, PositionHolder seekPosition) throws IOException {
long position = oggSeeker.read(input);
if (position >= 0) {
seekPosition.position = position;
return Extractor.RESULT_SEEK;
} else if (position < -1) {
onSeekEnd(-(position + 2));
}
if (!seekMapSet) {
SeekMap seekMap = checkStateNotNull(oggSeeker.createSeekMap());
extractorOutput.seekMap(seekMap);
seekMapSet = true;
}
if (lengthOfReadPacket > 0 || oggPacket.populate(input)) {
lengthOfReadPacket = 0;
ParsableByteArray payload = oggPacket.getPayload();
long granulesInPacket = preparePayload(payload);
if (granulesInPacket >= 0 && currentGranule + granulesInPacket >= targetGranule) {
// calculate time and send payload data to codec
long timeUs = convertGranuleToTime(currentGranule);
trackOutput.sampleData(payload, payload.limit());
trackOutput.sampleMetadata(timeUs, C.BUFFER_FLAG_KEY_FRAME, payload.limit(), 0, null);
targetGranule = -1;
}
currentGranule += granulesInPacket;
} else {
state = STATE_END_OF_INPUT;
return Extractor.RESULT_END_OF_INPUT;
}
return Extractor.RESULT_CONTINUE;
}
use of androidx.media3.common.util.ParsableByteArray in project media by androidx.
the class SefReader method readSdrs.
private void readSdrs(ExtractorInput input, PositionHolder seekPosition) throws IOException {
long streamLength = input.getLength();
int sdrsLength = tailLength - TAIL_HEADER_LENGTH - TAIL_FOOTER_LENGTH;
ParsableByteArray scratch = new ParsableByteArray(/* limit= */
sdrsLength);
input.readFully(scratch.getData(), /* offset= */
0, /* length= */
sdrsLength);
for (int i = 0; i < sdrsLength / LENGTH_OF_ONE_SDR; i++) {
// SDR data sub info flag and reserved bits (2).
scratch.skipBytes(2);
@DataType int dataType = scratch.readLittleEndianShort();
switch(dataType) {
case TYPE_SLOW_MOTION_DATA:
case TYPE_SUPER_SLOW_MOTION_DATA:
case TYPE_SUPER_SLOW_MOTION_BGM:
case TYPE_SUPER_SLOW_MOTION_EDIT_DATA:
case TYPE_SUPER_SLOW_DEFLICKERING_ON:
// The read int is the distance from the tail info to the start of the metadata.
// Calculated as an offset from the start by working backwards.
long startOffset = streamLength - tailLength - scratch.readLittleEndianInt();
int size = scratch.readLittleEndianInt();
dataReferences.add(new DataReference(dataType, startOffset, size));
break;
default:
// startPosition (4), size (4).
scratch.skipBytes(8);
}
}
if (dataReferences.isEmpty()) {
seekPosition.position = 0;
return;
}
readerState = STATE_READING_SEF_DATA;
seekPosition.position = dataReferences.get(0).startOffset;
}
use of androidx.media3.common.util.ParsableByteArray in project media by androidx.
the class VorbisReader method readHeaders.
@Override
@EnsuresNonNullIf(expression = "#3.format", result = false)
protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData) throws IOException {
if (vorbisSetup != null) {
checkNotNull(setupData.format);
return false;
}
vorbisSetup = readSetupHeaders(packet);
if (vorbisSetup == null) {
return true;
}
VorbisSetup vorbisSetup = this.vorbisSetup;
VorbisUtil.VorbisIdHeader idHeader = vorbisSetup.idHeader;
ArrayList<byte[]> codecInitializationData = new ArrayList<>();
codecInitializationData.add(idHeader.data);
codecInitializationData.add(vorbisSetup.setupHeaderData);
@Nullable Metadata metadata = VorbisUtil.parseVorbisComments(ImmutableList.copyOf(vorbisSetup.commentHeader.comments));
setupData.format = new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_VORBIS).setAverageBitrate(idHeader.bitrateNominal).setPeakBitrate(idHeader.bitrateMaximum).setChannelCount(idHeader.channels).setSampleRate(idHeader.sampleRate).setInitializationData(codecInitializationData).setMetadata(metadata).build();
return true;
}
use of androidx.media3.common.util.ParsableByteArray in project media by androidx.
the class Id3Decoder method decode.
/**
* Decodes ID3 tags.
*
* @param data The bytes to decode ID3 tags from.
* @param size Amount of bytes in {@code data} to read.
* @return A {@link Metadata} object containing the decoded ID3 tags, or null if the data could
* not be decoded.
*/
@Nullable
public Metadata decode(byte[] data, int size) {
List<Id3Frame> id3Frames = new ArrayList<>();
ParsableByteArray id3Data = new ParsableByteArray(data, size);
@Nullable Id3Header id3Header = decodeHeader(id3Data);
if (id3Header == null) {
return null;
}
int startPosition = id3Data.getPosition();
int frameHeaderSize = id3Header.majorVersion == 2 ? 6 : 10;
int framesSize = id3Header.framesSize;
if (id3Header.isUnsynchronized) {
framesSize = removeUnsynchronization(id3Data, id3Header.framesSize);
}
id3Data.setLimit(startPosition + framesSize);
boolean unsignedIntFrameSizeHack = false;
if (!validateFrames(id3Data, id3Header.majorVersion, frameHeaderSize, false)) {
if (id3Header.majorVersion == 4 && validateFrames(id3Data, 4, frameHeaderSize, true)) {
unsignedIntFrameSizeHack = true;
} else {
Log.w(TAG, "Failed to validate ID3 tag with majorVersion=" + id3Header.majorVersion);
return null;
}
}
while (id3Data.bytesLeft() >= frameHeaderSize) {
@Nullable Id3Frame frame = decodeFrame(id3Header.majorVersion, id3Data, unsignedIntFrameSizeHack, frameHeaderSize, framePredicate);
if (frame != null) {
id3Frames.add(frame);
}
}
return new Metadata(id3Frames);
}
use of androidx.media3.common.util.ParsableByteArray in project media by androidx.
the class DefaultTsPayloadReaderFactory method getClosedCaptionFormats.
/**
* If {@link #FLAG_OVERRIDE_CAPTION_DESCRIPTORS} is set, returns a {@link List<Format>} of {@link
* #closedCaptionFormats}. If unset, parses the PMT descriptor information and returns a {@link
* List<Format>} for the declared formats, or {@link #closedCaptionFormats} if the descriptor is
* not present.
*
* @param esInfo The {@link EsInfo} passed to {@link #createPayloadReader(int, EsInfo)}.
* @return A {@link List<Format>} containing list of closed caption formats.
*/
private List<Format> getClosedCaptionFormats(EsInfo esInfo) {
if (isSet(FLAG_OVERRIDE_CAPTION_DESCRIPTORS)) {
return closedCaptionFormats;
}
ParsableByteArray scratchDescriptorData = new ParsableByteArray(esInfo.descriptorBytes);
List<Format> closedCaptionFormats = this.closedCaptionFormats;
while (scratchDescriptorData.bytesLeft() > 0) {
int descriptorTag = scratchDescriptorData.readUnsignedByte();
int descriptorLength = scratchDescriptorData.readUnsignedByte();
int nextDescriptorPosition = scratchDescriptorData.getPosition() + descriptorLength;
if (descriptorTag == DESCRIPTOR_TAG_CAPTION_SERVICE) {
// Note: see ATSC A/65 for detailed information about the caption service descriptor.
closedCaptionFormats = new ArrayList<>();
int numberOfServices = scratchDescriptorData.readUnsignedByte() & 0x1F;
for (int i = 0; i < numberOfServices; i++) {
String language = scratchDescriptorData.readString(3);
int captionTypeByte = scratchDescriptorData.readUnsignedByte();
boolean isDigital = (captionTypeByte & 0x80) != 0;
String mimeType;
int accessibilityChannel;
if (isDigital) {
mimeType = MimeTypes.APPLICATION_CEA708;
accessibilityChannel = captionTypeByte & 0x3F;
} else {
mimeType = MimeTypes.APPLICATION_CEA608;
accessibilityChannel = 1;
}
// easy_reader(1), wide_aspect_ratio(1), reserved(6).
byte flags = (byte) scratchDescriptorData.readUnsignedByte();
// Skip reserved (8).
scratchDescriptorData.skipBytes(1);
@Nullable List<byte[]> initializationData = null;
// The wide_aspect_ratio flag only has meaning for CEA-708.
if (isDigital) {
boolean isWideAspectRatio = (flags & 0x40) != 0;
initializationData = CodecSpecificDataUtil.buildCea708InitializationData(isWideAspectRatio);
}
closedCaptionFormats.add(new Format.Builder().setSampleMimeType(mimeType).setLanguage(language).setAccessibilityChannel(accessibilityChannel).setInitializationData(initializationData).build());
}
} else {
// Unknown descriptor. Ignore.
}
scratchDescriptorData.setPosition(nextDescriptorPosition);
}
return closedCaptionFormats;
}
Aggregations