Add NonNull at package level for extractor.mp4

PiperOrigin-RevId: 286191078
This commit is contained in:
olly 2019-12-18 15:53:31 +00:00 committed by Oliver Woodman
parent 7a03e8edc0
commit 821d4fb13a
8 changed files with 150 additions and 100 deletions

View File

@ -125,14 +125,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, tkhdData.id,
tkhdData.rotationDegrees, mdhdData.second, drmInitData, isQuickTime);
long[] editListDurations = null;
long[] editListMediaTimes = null;
@Nullable long[] editListDurations = null;
@Nullable long[] editListMediaTimes = null;
if (!ignoreEditLists) {
@Nullable
Pair<long[], long[]> edtsData = parseEdts(trak.getContainerAtomOfType(Atom.TYPE_edts));
if (edtsData != null) {
editListDurations = edtsData.first;
editListMediaTimes = edtsData.second;
@Nullable Atom.ContainerAtom edtsAtom = trak.getContainerAtomOfType(Atom.TYPE_edts);
if (edtsAtom != null) {
@Nullable Pair<long[], long[]> edtsData = parseEdts(edtsAtom);
if (edtsData != null) {
editListDurations = edtsData.first;
editListMediaTimes = edtsData.second;
}
}
}
return stsdData.format == null ? null
@ -154,11 +156,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
Track track, Atom.ContainerAtom stblAtom, GaplessInfoHolder gaplessInfoHolder)
throws ParserException {
SampleSizeBox sampleSizeBox;
Atom.LeafAtom stszAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stsz);
@Nullable Atom.LeafAtom stszAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stsz);
if (stszAtom != null) {
sampleSizeBox = new StszSampleSizeBox(stszAtom);
} else {
Atom.LeafAtom stz2Atom = stblAtom.getLeafAtomOfType(Atom.TYPE_stz2);
@Nullable Atom.LeafAtom stz2Atom = stblAtom.getLeafAtomOfType(Atom.TYPE_stz2);
if (stz2Atom == null) {
throw new ParserException("Track has no sample table size information");
}
@ -179,7 +181,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
// Entries are byte offsets of chunks.
boolean chunkOffsetsAreLongs = false;
Atom.LeafAtom chunkOffsetsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stco);
@Nullable Atom.LeafAtom chunkOffsetsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stco);
if (chunkOffsetsAtom == null) {
chunkOffsetsAreLongs = true;
chunkOffsetsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_co64);
@ -190,11 +192,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
// Entries are (number of samples, timestamp delta between those samples).
ParsableByteArray stts = stblAtom.getLeafAtomOfType(Atom.TYPE_stts).data;
// Entries are the indices of samples that are synchronization samples.
Atom.LeafAtom stssAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stss);
ParsableByteArray stss = stssAtom != null ? stssAtom.data : null;
@Nullable Atom.LeafAtom stssAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stss);
@Nullable ParsableByteArray stss = stssAtom != null ? stssAtom.data : null;
// Entries are (number of samples, timestamp offset).
Atom.LeafAtom cttsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_ctts);
ParsableByteArray ctts = cttsAtom != null ? cttsAtom.data : null;
@Nullable Atom.LeafAtom cttsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_ctts);
@Nullable ParsableByteArray ctts = cttsAtom != null ? cttsAtom.data : null;
// Prepare to read chunk information.
ChunkIterator chunkIterator = new ChunkIterator(stsc, chunkOffsets, chunkOffsetsAreLongs);
@ -542,9 +544,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
*/
@Nullable
public static Metadata parseMdtaFromMeta(Atom.ContainerAtom meta) {
Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr);
Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys);
Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst);
@Nullable Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr);
@Nullable Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys);
@Nullable Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst);
if (hdlrAtom == null
|| keysAtom == null
|| ilstAtom == null
@ -575,6 +577,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
int keyIndex = ilst.readInt() - 1;
if (keyIndex >= 0 && keyIndex < keyNames.length) {
String key = keyNames[keyIndex];
@Nullable
Metadata.Entry entry =
MetadataUtil.parseMdtaMetadataEntryFromIlst(ilst, atomPosition + atomSize, key);
if (entry != null) {
@ -609,7 +612,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
ilst.skipBytes(Atom.HEADER_SIZE);
ArrayList<Metadata.Entry> entries = new ArrayList<>();
while (ilst.getPosition() < limit) {
Metadata.Entry entry = MetadataUtil.parseIlstElement(ilst);
@Nullable Metadata.Entry entry = MetadataUtil.parseIlstElement(ilst);
if (entry != null) {
entries.add(entry);
}
@ -817,12 +820,18 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
return out;
}
private static void parseTextSampleEntry(ParsableByteArray parent, int atomType, int position,
int atomSize, int trackId, String language, StsdData out) throws ParserException {
private static void parseTextSampleEntry(
ParsableByteArray parent,
int atomType,
int position,
int atomSize,
int trackId,
String language,
StsdData out) {
parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
// Default values.
List<byte[]> initializationData = null;
@Nullable List<byte[]> initializationData = null;
long subsampleOffsetUs = Format.OFFSET_SAMPLE_RELATIVE;
String mimeType;
@ -934,7 +943,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
initializationData = hevcConfig.initializationData;
out.nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength;
} else if (childAtomType == Atom.TYPE_dvcC || childAtomType == Atom.TYPE_dvvC) {
DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig.parse(parent);
@Nullable DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig.parse(parent);
if (dolbyVisionConfig != null) {
codecs = dolbyVisionConfig.codecs;
mimeType = MimeTypes.VIDEO_DOLBY_VISION;
@ -1021,11 +1030,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
*/
@Nullable
private static Pair<long[], long[]> parseEdts(Atom.ContainerAtom edtsAtom) {
Atom.LeafAtom elst;
if (edtsAtom == null || (elst = edtsAtom.getLeafAtomOfType(Atom.TYPE_elst)) == null) {
@Nullable Atom.LeafAtom elstAtom = edtsAtom.getLeafAtomOfType(Atom.TYPE_elst);
if (elstAtom == null) {
return null;
}
ParsableByteArray elstData = elst.data;
ParsableByteArray elstData = elstAtom.data;
elstData.setPosition(Atom.HEADER_SIZE);
int fullAtom = elstData.readInt();
int version = Atom.parseFullAtomVersion(fullAtom);
@ -1328,8 +1337,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
int childPosition = position + Atom.HEADER_SIZE;
int schemeInformationBoxPosition = C.POSITION_UNSET;
int schemeInformationBoxSize = 0;
String schemeType = null;
Integer dataFormat = null;
@Nullable String schemeType = null;
@Nullable Integer dataFormat = null;
while (childPosition - position < size) {
parent.setPosition(childPosition);
int childAtomSize = parent.readInt();
@ -1352,9 +1361,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
Assertions.checkStateNotNull(dataFormat, "frma atom is mandatory");
Assertions.checkState(
schemeInformationBoxPosition != C.POSITION_UNSET, "schi atom is mandatory");
TrackEncryptionBox encryptionBox = parseSchiFromParent(parent, schemeInformationBoxPosition,
schemeInformationBoxSize, schemeType);
Assertions.checkStateNotNull(encryptionBox, "tenc atom is mandatory");
TrackEncryptionBox encryptionBox =
Assertions.checkStateNotNull(
parseSchiFromParent(
parent, schemeInformationBoxPosition, schemeInformationBoxSize, schemeType),
"tenc atom is mandatory");
return Pair.create(dataFormat, encryptionBox);
} else {
return null;

View File

@ -55,6 +55,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Extracts data from the FMP4 container format. */
@SuppressWarnings("ConstantField")
@ -155,14 +156,14 @@ public class FragmentedMp4Extractor implements Extractor {
private int atomType;
private long atomSize;
private int atomHeaderBytesRead;
private ParsableByteArray atomData;
@Nullable private ParsableByteArray atomData;
private long endOfMdatPosition;
private int pendingMetadataSampleBytes;
private long pendingSeekTimeUs;
private long durationUs;
private long segmentIndexEarliestPresentationTimeUs;
private TrackBundle currentTrackBundle;
@Nullable private TrackBundle currentTrackBundle;
private int sampleSize;
private int sampleBytesWritten;
private int sampleCurrentNalBytesRemaining;
@ -170,7 +171,7 @@ public class FragmentedMp4Extractor implements Extractor {
private boolean isAc4HeaderRequired;
// Extractor output.
private ExtractorOutput extractorOutput;
@MonotonicNonNull private ExtractorOutput extractorOutput;
private TrackOutput[] emsgTrackOutputs;
private TrackOutput[] cea608TrackOutputs;
@ -495,6 +496,7 @@ public class FragmentedMp4Extractor implements Extractor {
for (int i = 0; i < moovContainerChildrenSize; i++) {
Atom.ContainerAtom atom = moov.containerChildren.get(i);
if (atom.type == Atom.TYPE_trak) {
@Nullable
Track track =
modifyTrack(
AtomParsers.parseTrak(
@ -712,7 +714,7 @@ public class FragmentedMp4Extractor implements Extractor {
private static void parseTraf(ContainerAtom traf, SparseArray<TrackBundle> trackBundleArray,
@Flags int flags, byte[] extendedTypeScratch) throws ParserException {
LeafAtom tfhd = traf.getLeafAtomOfType(Atom.TYPE_tfhd);
TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundleArray);
@Nullable TrackBundle trackBundle = parseTfhd(tfhd.data, trackBundleArray);
if (trackBundle == null) {
return;
}
@ -721,33 +723,34 @@ public class FragmentedMp4Extractor implements Extractor {
long decodeTime = fragment.nextFragmentDecodeTime;
trackBundle.reset();
LeafAtom tfdtAtom = traf.getLeafAtomOfType(Atom.TYPE_tfdt);
@Nullable LeafAtom tfdtAtom = traf.getLeafAtomOfType(Atom.TYPE_tfdt);
if (tfdtAtom != null && (flags & FLAG_WORKAROUND_IGNORE_TFDT_BOX) == 0) {
decodeTime = parseTfdt(traf.getLeafAtomOfType(Atom.TYPE_tfdt).data);
}
parseTruns(traf, trackBundle, decodeTime, flags);
TrackEncryptionBox encryptionBox = trackBundle.track
.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex);
@Nullable
TrackEncryptionBox encryptionBox =
trackBundle.track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex);
LeafAtom saiz = traf.getLeafAtomOfType(Atom.TYPE_saiz);
@Nullable LeafAtom saiz = traf.getLeafAtomOfType(Atom.TYPE_saiz);
if (saiz != null) {
parseSaiz(encryptionBox, saiz.data, fragment);
}
LeafAtom saio = traf.getLeafAtomOfType(Atom.TYPE_saio);
@Nullable LeafAtom saio = traf.getLeafAtomOfType(Atom.TYPE_saio);
if (saio != null) {
parseSaio(saio.data, fragment);
}
LeafAtom senc = traf.getLeafAtomOfType(Atom.TYPE_senc);
@Nullable LeafAtom senc = traf.getLeafAtomOfType(Atom.TYPE_senc);
if (senc != null) {
parseSenc(senc.data, fragment);
}
LeafAtom sbgp = traf.getLeafAtomOfType(Atom.TYPE_sbgp);
LeafAtom sgpd = traf.getLeafAtomOfType(Atom.TYPE_sgpd);
@Nullable LeafAtom sbgp = traf.getLeafAtomOfType(Atom.TYPE_sbgp);
@Nullable LeafAtom sgpd = traf.getLeafAtomOfType(Atom.TYPE_sgpd);
if (sbgp != null && sgpd != null) {
parseSgpd(sbgp.data, sgpd.data, encryptionBox != null ? encryptionBox.schemeType : null,
fragment);
@ -863,13 +866,14 @@ public class FragmentedMp4Extractor implements Extractor {
* @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd
* does not refer to any {@link TrackBundle}.
*/
@Nullable
private static TrackBundle parseTfhd(
ParsableByteArray tfhd, SparseArray<TrackBundle> trackBundles) {
tfhd.setPosition(Atom.HEADER_SIZE);
int fullAtom = tfhd.readInt();
int atomFlags = Atom.parseFullAtomFlags(fullAtom);
int trackId = tfhd.readInt();
TrackBundle trackBundle = getTrackBundle(trackBundles, trackId);
@Nullable TrackBundle trackBundle = getTrackBundle(trackBundles, trackId);
if (trackBundle == null) {
return null;
}
@ -1053,8 +1057,12 @@ public class FragmentedMp4Extractor implements Extractor {
out.fillEncryptionData(senc);
}
private static void parseSgpd(ParsableByteArray sbgp, ParsableByteArray sgpd, String schemeType,
TrackFragment out) throws ParserException {
private static void parseSgpd(
ParsableByteArray sbgp,
ParsableByteArray sgpd,
@Nullable String schemeType,
TrackFragment out)
throws ParserException {
sbgp.setPosition(Atom.HEADER_SIZE);
int sbgpFullAtom = sbgp.readInt();
if (sbgp.readInt() != SAMPLE_GROUP_TYPE_seig) {
@ -1216,7 +1224,7 @@ public class FragmentedMp4Extractor implements Extractor {
private boolean readSample(ExtractorInput input) throws IOException, InterruptedException {
if (parserState == STATE_READING_SAMPLE_START) {
if (currentTrackBundle == null) {
TrackBundle currentTrackBundle = getNextFragmentRun(trackBundles);
@Nullable TrackBundle currentTrackBundle = getNextFragmentRun(trackBundles);
if (currentTrackBundle == null) {
// We've run out of samples in the current mdat. Discard any trailing data and prepare to
// read the header of the next atom.
@ -1388,6 +1396,7 @@ public class FragmentedMp4Extractor implements Extractor {
* Returns the {@link TrackBundle} whose fragment run has the earliest file position out of those
* yet to be consumed, or null if all have been consumed.
*/
@Nullable
private static TrackBundle getNextFragmentRun(SparseArray<TrackBundle> trackBundles) {
TrackBundle nextTrackBundle = null;
long nextTrackRunOffset = Long.MAX_VALUE;
@ -1410,7 +1419,7 @@ public class FragmentedMp4Extractor implements Extractor {
/** Returns DrmInitData from leaf atoms. */
private static DrmInitData getDrmInitDataFromAtoms(List<Atom.LeafAtom> leafChildren) {
ArrayList<SchemeData> schemeDatas = null;
@Nullable ArrayList<SchemeData> schemeDatas = null;
int leafChildrenSize = leafChildren.size();
for (int i = 0; i < leafChildrenSize; i++) {
LeafAtom child = leafChildren.get(i);
@ -1419,7 +1428,7 @@ public class FragmentedMp4Extractor implements Extractor {
schemeDatas = new ArrayList<>();
}
byte[] psshData = child.data.data;
UUID uuid = PsshAtomUtil.parseUuid(psshData);
@Nullable UUID uuid = PsshAtomUtil.parseUuid(psshData);
if (uuid == null) {
Log.w(TAG, "Skipped pssh atom (failed to extract uuid)");
} else {
@ -1496,9 +1505,10 @@ public class FragmentedMp4Extractor implements Extractor {
}
public void updateDrmInitData(DrmInitData drmInitData) {
@Nullable
TrackEncryptionBox encryptionBox =
track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex);
String schemeType = encryptionBox != null ? encryptionBox.schemeType : null;
@Nullable String schemeType = encryptionBox != null ? encryptionBox.schemeType : null;
output.format(track.format.copyWithDrmInitData(drmInitData.copyWithSchemeType(schemeType)));
}
@ -1595,7 +1605,7 @@ public class FragmentedMp4Extractor implements Extractor {
/** Skips the encryption data for the current sample. */
private void skipSampleEncryptionData() {
TrackEncryptionBox encryptionBox = getEncryptionBoxIfEncrypted();
@Nullable TrackEncryptionBox encryptionBox = getEncryptionBoxIfEncrypted();
if (encryptionBox == null) {
return;
}
@ -1609,8 +1619,10 @@ public class FragmentedMp4Extractor implements Extractor {
}
}
@Nullable
private TrackEncryptionBox getEncryptionBoxIfEncrypted() {
int sampleDescriptionIndex = fragment.header.sampleDescriptionIndex;
@Nullable
TrackEncryptionBox encryptionBox =
fragment.trackEncryptionBox != null
? fragment.trackEncryptionBox

View File

@ -47,8 +47,7 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
private MdtaMetadataEntry(Parcel in) {
key = Util.castNonNull(in.readString());
value = new byte[in.readInt()];
in.readByteArray(value);
value = Util.castNonNull(in.createByteArray());
localeIndicator = in.readInt();
typeIndicator = in.readInt();
}
@ -88,7 +87,6 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(key);
dest.writeInt(value.length);
dest.writeByteArray(value);
dest.writeInt(localeIndicator);
dest.writeInt(typeIndicator);

View File

@ -325,8 +325,11 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
@Nullable
private static TextInformationFrame parseStandardGenreAttribute(ParsableByteArray data) {
int genreCode = parseUint8AttributeValue(data);
String genreString = (0 < genreCode && genreCode <= STANDARD_GENRES.length)
? STANDARD_GENRES[genreCode - 1] : null;
@Nullable
String genreString =
(0 < genreCode && genreCode <= STANDARD_GENRES.length)
? STANDARD_GENRES[genreCode - 1]
: null;
if (genreString != null) {
return new TextInformationFrame("TCON", /* description= */ null, genreString);
}
@ -341,7 +344,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
if (atomType == Atom.TYPE_data) {
int fullVersionInt = data.readInt();
int flags = Atom.parseFullAtomFlags(fullVersionInt);
String mimeType = flags == 13 ? "image/jpeg" : flags == 14 ? "image/png" : null;
@Nullable String mimeType = flags == 13 ? "image/jpeg" : flags == 14 ? "image/png" : null;
if (mimeType == null) {
Log.w(TAG, "Unrecognized cover art flags: " + flags);
return null;
@ -361,8 +364,8 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
@Nullable
private static Id3Frame parseInternalAttribute(ParsableByteArray data, int endPosition) {
String domain = null;
String name = null;
@Nullable String domain = null;
@Nullable String name = null;
int dataAtomPosition = -1;
int dataAtomSize = -1;
while (data.getPosition() < endPosition) {

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.extractor.mp4;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
@ -42,6 +43,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* Extracts data from the MP4 container format.
@ -105,7 +107,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
private int atomType;
private long atomSize;
private int atomHeaderBytesRead;
private ParsableByteArray atomData;
@Nullable private ParsableByteArray atomData;
private int sampleTrackIndex;
private int sampleBytesWritten;
@ -113,7 +115,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
private boolean isAc4HeaderRequired;
// Extractor outputs.
private ExtractorOutput extractorOutput;
@MonotonicNonNull private ExtractorOutput extractorOutput;
private Mp4Track[] tracks;
private long[][] accumulatedSampleSizes;
private int firstVideoTrackIndex;
@ -290,8 +292,11 @@ public final class Mp4Extractor implements Extractor, SeekMap {
// The atom extends to the end of the file. Note that if the atom is within a container we can
// work out its size even if the input length is unknown.
long endPosition = input.getLength();
if (endPosition == C.LENGTH_UNSET && !containerAtoms.isEmpty()) {
endPosition = containerAtoms.peek().endPosition;
if (endPosition == C.LENGTH_UNSET) {
@Nullable ContainerAtom containerAtom = containerAtoms.peek();
if (containerAtom != null) {
endPosition = containerAtom.endPosition;
}
}
if (endPosition != C.LENGTH_UNSET) {
atomSize = endPosition - input.getPosition() + atomHeaderBytesRead;
@ -386,17 +391,17 @@ public final class Mp4Extractor implements Extractor, SeekMap {
List<Mp4Track> tracks = new ArrayList<>();
// Process metadata.
Metadata udtaMetadata = null;
@Nullable Metadata udtaMetadata = null;
GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
@Nullable Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
if (udta != null) {
udtaMetadata = AtomParsers.parseUdta(udta, isQuickTime);
if (udtaMetadata != null) {
gaplessInfoHolder.setFromMetadata(udtaMetadata);
}
}
Metadata mdtaMetadata = null;
Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
@Nullable Metadata mdtaMetadata = null;
@Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
if (meta != null) {
mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
}
@ -453,6 +458,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
if (atom.type != Atom.TYPE_trak) {
continue;
}
@Nullable
Track track =
AtomParsers.parseTrak(
atom,

View File

@ -49,8 +49,6 @@ public final class PsshAtomUtil {
* @param data The scheme specific data.
* @return The PSSH atom.
*/
// dereference of possibly-null reference keyId
@SuppressWarnings({"ParameterNotNullable", "nullness:dereference.of.nullable"})
public static byte[] buildPsshAtom(
UUID systemId, @Nullable UUID[] keyIds, @Nullable byte[] data) {
int dataLength = data != null ? data.length : 0;
@ -97,8 +95,9 @@ public final class PsshAtomUtil {
* @return The parsed UUID. Null if the input is not a valid PSSH atom, or if the PSSH atom has an
* unsupported version.
*/
public static @Nullable UUID parseUuid(byte[] atom) {
PsshAtom parsedAtom = parsePsshAtom(atom);
@Nullable
public static UUID parseUuid(byte[] atom) {
@Nullable PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) {
return null;
}
@ -115,7 +114,7 @@ public final class PsshAtomUtil {
* an unsupported version.
*/
public static int parseVersion(byte[] atom) {
PsshAtom parsedAtom = parsePsshAtom(atom);
@Nullable PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) {
return -1;
}
@ -133,8 +132,9 @@ public final class PsshAtomUtil {
* @return The parsed scheme specific data. Null if the input is not a valid PSSH atom, or if the
* PSSH atom has an unsupported version, or if the PSSH atom does not match the passed UUID.
*/
public static @Nullable byte[] parseSchemeSpecificData(byte[] atom, UUID uuid) {
PsshAtom parsedAtom = parsePsshAtom(atom);
@Nullable
public static byte[] parseSchemeSpecificData(byte[] atom, UUID uuid) {
@Nullable PsshAtom parsedAtom = parsePsshAtom(atom);
if (parsedAtom == null) {
return null;
}
@ -153,7 +153,8 @@ public final class PsshAtomUtil {
* has an unsupported version.
*/
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
private static @Nullable PsshAtom parsePsshAtom(byte[] atom) {
@Nullable
private static PsshAtom parsePsshAtom(byte[] atom) {
ParsableByteArray atomData = new ParsableByteArray(atom);
if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) {
// Data too short.

View File

@ -15,19 +15,19 @@
*/
package com.google.android.exoplayer2.extractor.mp4;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* A holder for information corresponding to a single fragment of an mp4 file.
*/
/* package */ final class TrackFragment {
/**
* The default values for samples from the track fragment header.
*/
public DefaultSampleValues header;
/** The default values for samples from the track fragment header. */
@MonotonicNonNull public DefaultSampleValues header;
/**
* The position (byte offset) of the start of fragment.
*/
@ -81,20 +81,13 @@ import java.io.IOException;
* Undefined otherwise.
*/
public boolean[] sampleHasSubsampleEncryptionTable;
/**
* Fragment specific track encryption. May be null.
*/
public TrackEncryptionBox trackEncryptionBox;
/**
* If {@link #definesEncryptionData} is true, indicates the length of the sample encryption data.
* Undefined otherwise.
*/
public int sampleEncryptionDataLength;
/** Fragment specific track encryption. May be null. */
@Nullable public TrackEncryptionBox trackEncryptionBox;
/**
* If {@link #definesEncryptionData} is true, contains binary sample encryption data. Undefined
* otherwise.
*/
public ParsableByteArray sampleEncryptionData;
public final ParsableByteArray sampleEncryptionData;
/**
* Whether {@link #sampleEncryptionData} needs populating with the actual encryption data.
*/
@ -104,6 +97,17 @@ import java.io.IOException;
*/
public long nextFragmentDecodeTime;
public TrackFragment() {
trunDataPosition = new long[0];
trunLength = new int[0];
sampleSizeTable = new int[0];
sampleCompositionTimeOffsetTable = new int[0];
sampleDecodingTimeTable = new long[0];
sampleIsSyncFrameTable = new boolean[0];
sampleHasSubsampleEncryptionTable = new boolean[0];
sampleEncryptionData = new ParsableByteArray();
}
/**
* Resets the fragment.
* <p>
@ -130,11 +134,11 @@ import java.io.IOException;
public void initTables(int trunCount, int sampleCount) {
this.trunCount = trunCount;
this.sampleCount = sampleCount;
if (trunLength == null || trunLength.length < trunCount) {
if (trunLength.length < trunCount) {
trunDataPosition = new long[trunCount];
trunLength = new int[trunCount];
}
if (sampleSizeTable == null || sampleSizeTable.length < sampleCount) {
if (sampleSizeTable.length < sampleCount) {
// Size the tables 25% larger than needed, so as to make future resize operations less
// likely. The choice of 25% is relatively arbitrary.
int tableSize = (sampleCount * 125) / 100;
@ -148,18 +152,14 @@ import java.io.IOException;
/**
* Configures the fragment to be one that defines encryption data of the specified length.
* <p>
* {@link #definesEncryptionData} is set to true, {@link #sampleEncryptionDataLength} is set to
* the specified length, and {@link #sampleEncryptionData} is resized if necessary such that it
* is at least this length.
*
* <p>{@link #definesEncryptionData} is set to true, and the {@link ParsableByteArray#limit()
* limit} of {@link #sampleEncryptionData} is set to the specified length.
*
* @param length The length in bytes of the encryption data.
*/
public void initEncryptionData(int length) {
if (sampleEncryptionData == null || sampleEncryptionData.limit() < length) {
sampleEncryptionData = new ParsableByteArray(length);
}
sampleEncryptionDataLength = length;
sampleEncryptionData.reset(length);
definesEncryptionData = true;
sampleEncryptionDataNeedsFill = true;
}
@ -170,7 +170,7 @@ import java.io.IOException;
* @param input An {@link ExtractorInput} from which to read the encryption data.
*/
public void fillEncryptionData(ExtractorInput input) throws IOException, InterruptedException {
input.readFully(sampleEncryptionData.data, 0, sampleEncryptionDataLength);
input.readFully(sampleEncryptionData.data, 0, sampleEncryptionData.limit());
sampleEncryptionData.setPosition(0);
sampleEncryptionDataNeedsFill = false;
}
@ -181,7 +181,7 @@ import java.io.IOException;
* @param source A source from which to read the encryption data.
*/
public void fillEncryptionData(ParsableByteArray source) {
source.readBytes(sampleEncryptionData.data, 0, sampleEncryptionDataLength);
source.readBytes(sampleEncryptionData.data, 0, sampleEncryptionData.limit());
sampleEncryptionData.setPosition(0);
sampleEncryptionDataNeedsFill = false;
}

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.mp4;
import com.google.android.exoplayer2.util.NonNullApi;