/** Parses a sidx atom (defined in 14496-12). */ private static ChunkIndex parseSidx(ParsableByteArray atom, long inputPosition) throws ParserException { atom.setPosition(Atom.HEADER_SIZE); int fullAtom = atom.readInt(); int version = Atom.parseFullAtomVersion(fullAtom); atom.skipBytes(4); long timescale = atom.readUnsignedInt(); long earliestPresentationTime; long offset = inputPosition; if (version == 0) { earliestPresentationTime = atom.readUnsignedInt(); offset += atom.readUnsignedInt(); } else { earliestPresentationTime = atom.readUnsignedLongToLong(); offset += atom.readUnsignedLongToLong(); } atom.skipBytes(2); int referenceCount = atom.readUnsignedShort(); int[] sizes = new int[referenceCount]; long[] offsets = new long[referenceCount]; long[] durationsUs = new long[referenceCount]; long[] timesUs = new long[referenceCount]; long time = earliestPresentationTime; long timeUs = Util.scaleLargeTimestamp(time, C.MICROS_PER_SECOND, timescale); for (int i = 0; i < referenceCount; i++) { int firstInt = atom.readInt(); int type = 0x80000000 & firstInt; if (type != 0) { throw new ParserException("Unhandled indirect reference"); } long referenceDuration = atom.readUnsignedInt(); sizes[i] = 0x7fffffff & firstInt; offsets[i] = offset; // Calculate time and duration values such that any rounding errors are consistent. i.e. That // timesUs[i] + durationsUs[i] == timesUs[i + 1]. timesUs[i] = timeUs; time += referenceDuration; timeUs = Util.scaleLargeTimestamp(time, C.MICROS_PER_SECOND, timescale); durationsUs[i] = timeUs - timesUs[i]; atom.skipBytes(4); offset += sizes[i]; } return new ChunkIndex(sizes, offsets, durationsUs, timesUs); }
private static void parseSaiz( TrackEncryptionBox encryptionBox, ParsableByteArray saiz, TrackFragment out) throws ParserException { int vectorSize = encryptionBox.initializationVectorSize; saiz.setPosition(Atom.HEADER_SIZE); int fullAtom = saiz.readInt(); int flags = Atom.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { saiz.skipBytes(8); } int defaultSampleInfoSize = saiz.readUnsignedByte(); int sampleCount = saiz.readUnsignedIntToInt(); if (sampleCount != out.length) { throw new ParserException("Length mismatch: " + sampleCount + ", " + out.length); } int totalSize = 0; if (defaultSampleInfoSize == 0) { boolean[] sampleHasSubsampleEncryptionTable = out.sampleHasSubsampleEncryptionTable; for (int i = 0; i < sampleCount; i++) { int sampleInfoSize = saiz.readUnsignedByte(); totalSize += sampleInfoSize; sampleHasSubsampleEncryptionTable[i] = sampleInfoSize > vectorSize; } } else { boolean subsampleEncryption = defaultSampleInfoSize > vectorSize; totalSize += defaultSampleInfoSize * sampleCount; Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption); } out.initEncryptionData(totalSize); }
/** * Parses a saio atom (defined in 14496-12). * * @param saio The saio atom to parse. * @param out The track fragment to populate with data from the saio atom. */ private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException { saio.setPosition(Atom.HEADER_SIZE); int fullAtom = saio.readInt(); int flags = Atom.parseFullAtomFlags(fullAtom); if ((flags & 0x01) == 1) { saio.skipBytes(8); } int entryCount = saio.readUnsignedIntToInt(); if (entryCount != 1) { // We only support one trun element currently, so always expect one entry. throw new ParserException("Unexpected saio entry count: " + entryCount); } int version = Atom.parseFullAtomVersion(fullAtom); out.auxiliaryDataPosition += version == 0 ? saio.readUnsignedInt() : saio.readUnsignedLongToLong(); }
private int appendSampleEncryptionData(ParsableByteArray sampleEncryptionData) { int sampleDescriptionIndex = fragmentRun.header.sampleDescriptionIndex; TrackEncryptionBox encryptionBox = track.sampleDescriptionEncryptionBoxes[sampleDescriptionIndex]; int vectorSize = encryptionBox.initializationVectorSize; boolean subsampleEncryption = fragmentRun.sampleHasSubsampleEncryptionTable[sampleIndex]; // Write the signal byte, containing the vector size and the subsample encryption flag. encryptionSignalByte.data[0] = (byte) (vectorSize | (subsampleEncryption ? 0x80 : 0)); encryptionSignalByte.setPosition(0); trackOutput.sampleData(encryptionSignalByte, 1); // Write the vector. trackOutput.sampleData(sampleEncryptionData, vectorSize); // If we don't have subsample encryption data, we're done. if (!subsampleEncryption) { return 1 + vectorSize; } // Write the subsample encryption data. int subsampleCount = sampleEncryptionData.readUnsignedShort(); sampleEncryptionData.skipBytes(-2); int subsampleDataLength = 2 + 6 * subsampleCount; trackOutput.sampleData(sampleEncryptionData, subsampleDataLength); return 1 + vectorSize + subsampleDataLength; }
/** * Parses a tfhd atom (defined in 14496-12). * * @param extendsDefaults Default sample values from the trex atom. * @param tfhd The tfhd atom to parse. * @param out The track fragment to populate with data from the tfhd atom. */ private static void parseTfhd( DefaultSampleValues extendsDefaults, ParsableByteArray tfhd, TrackFragment out) { tfhd.setPosition(Atom.HEADER_SIZE); int fullAtom = tfhd.readInt(); int flags = Atom.parseFullAtomFlags(fullAtom); tfhd.skipBytes(4); // trackId if ((flags & 0x01 /* base_data_offset_present */) != 0) { long baseDataPosition = tfhd.readUnsignedLongToLong(); out.dataPosition = baseDataPosition; out.auxiliaryDataPosition = baseDataPosition; } int defaultSampleDescriptionIndex = ((flags & 0x02 /* default_sample_description_index_present */) != 0) ? tfhd.readUnsignedIntToInt() - 1 : extendsDefaults.sampleDescriptionIndex; int defaultSampleDuration = ((flags & 0x08 /* default_sample_duration_present */) != 0) ? tfhd.readUnsignedIntToInt() : extendsDefaults.duration; int defaultSampleSize = ((flags & 0x10 /* default_sample_size_present */) != 0) ? tfhd.readUnsignedIntToInt() : extendsDefaults.size; int defaultSampleFlags = ((flags & 0x20 /* default_sample_flags_present */) != 0) ? tfhd.readUnsignedIntToInt() : extendsDefaults.flags; out.header = new DefaultSampleValues( defaultSampleDescriptionIndex, defaultSampleDuration, defaultSampleSize, defaultSampleFlags); }