Partial nullness annotations for AtomParsers

PiperOrigin-RevId: 284558886
This commit is contained in:
olly 2019-12-09 16:32:22 +00:00 committed by Oliver Woodman
parent 4b281cec3b
commit 539a1ac2e2

View File

@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/** Utility methods for parsing MP4 format atom payloads according to ISO 14496-12. */
@SuppressWarnings({"ConstantField"})
@ -85,15 +86,21 @@ import java.util.List;
*
* @param trak Atom to decode.
* @param mvhd Movie header atom, used to get the timescale.
* @param duration The duration in units of the timescale declared in the mvhd atom, or
* {@link C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param duration The duration in units of the timescale declared in the mvhd atom, or {@link
* C#TIME_UNSET} if the duration should be parsed from the tkhd atom.
* @param drmInitData {@link DrmInitData} to be included in the format, or {@code null}.
* @param ignoreEditLists Whether to ignore any edit lists in the trak box.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return A {@link Track} instance, or {@code null} if the track's type isn't supported.
*/
public static Track parseTrak(Atom.ContainerAtom trak, Atom.LeafAtom mvhd, long duration,
DrmInitData drmInitData, boolean ignoreEditLists, boolean isQuickTime)
@Nullable
public static Track parseTrak(
Atom.ContainerAtom trak,
Atom.LeafAtom mvhd,
long duration,
@Nullable DrmInitData drmInitData,
boolean ignoreEditLists,
boolean isQuickTime)
throws ParserException {
Atom.ContainerAtom mdia = trak.getContainerAtomOfType(Atom.TYPE_mdia);
int trackType = getTrackTypeForHdlr(parseHdlr(mdia.getLeafAtomOfType(Atom.TYPE_hdlr).data));
@ -121,9 +128,12 @@ import java.util.List;
long[] editListDurations = null;
long[] editListMediaTimes = null;
if (!ignoreEditLists) {
@Nullable
Pair<long[], long[]> edtsData = parseEdts(trak.getContainerAtomOfType(Atom.TYPE_edts));
editListDurations = edtsData.first;
editListMediaTimes = edtsData.second;
if (edtsData != null) {
editListDurations = edtsData.first;
editListMediaTimes = edtsData.second;
}
}
return stsdData.format == null ? null
: new Track(tkhdData.id, trackType, mdhdData.first, movieTimescale, durationUs,
@ -736,19 +746,25 @@ import java.util.List;
* @param trackId The track's identifier in its container.
* @param rotationDegrees The rotation of the track in degrees.
* @param language The language of the track.
* @param drmInitData {@link DrmInitData} to be included in the format.
* @param drmInitData {@link DrmInitData} to be included in the format, or {@code null}.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return An object containing the parsed data.
*/
private static StsdData parseStsd(ParsableByteArray stsd, int trackId, int rotationDegrees,
String language, DrmInitData drmInitData, boolean isQuickTime) throws ParserException {
private static StsdData parseStsd(
ParsableByteArray stsd,
int trackId,
int rotationDegrees,
String language,
@Nullable DrmInitData drmInitData,
boolean isQuickTime)
throws ParserException {
stsd.setPosition(Atom.FULL_HEADER_SIZE);
int numberOfEntries = stsd.readInt();
StsdData out = new StsdData(numberOfEntries);
for (int i = 0; i < numberOfEntries; i++) {
int childStartPosition = stsd.getPosition();
int childAtomSize = stsd.readInt();
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
Assertions.checkState(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = stsd.readInt();
if (childAtomType == Atom.TYPE_avc1
|| childAtomType == Atom.TYPE_avc3
@ -846,9 +862,17 @@ import java.util.List;
initializationData);
}
private static void parseVideoSampleEntry(ParsableByteArray parent, int atomType, int position,
int size, int trackId, int rotationDegrees, DrmInitData drmInitData, StsdData out,
int entryIndex) throws ParserException {
private static void parseVideoSampleEntry(
ParsableByteArray parent,
int atomType,
int position,
int size,
int trackId,
int rotationDegrees,
@Nullable DrmInitData drmInitData,
StsdData out,
int entryIndex)
throws ParserException {
parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
parent.skipBytes(16);
@ -860,8 +884,9 @@ import java.util.List;
int childPosition = parent.getPosition();
if (atomType == Atom.TYPE_encv) {
Pair<Integer, TrackEncryptionBox> sampleEntryEncryptionData = parseSampleEntryEncryptionData(
parent, position, size);
@Nullable
Pair<Integer, TrackEncryptionBox> sampleEntryEncryptionData =
parseSampleEntryEncryptionData(parent, position, size);
if (sampleEntryEncryptionData != null) {
atomType = sampleEntryEncryptionData.first;
drmInitData = drmInitData == null ? null
@ -875,10 +900,10 @@ import java.util.List;
// drmInitData = null;
// }
List<byte[]> initializationData = null;
String mimeType = null;
String codecs = null;
byte[] projectionData = null;
@Nullable List<byte[]> initializationData = null;
@Nullable String mimeType = null;
@Nullable String codecs = null;
@Nullable byte[] projectionData = null;
@C.StereoMode
int stereoMode = Format.NO_VALUE;
while (childPosition - position < size) {
@ -889,7 +914,7 @@ import java.util.List;
// Handle optional terminating four zero bytes in MOV files.
break;
}
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
Assertions.checkState(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = parent.readInt();
if (childAtomType == Atom.TYPE_avcC) {
Assertions.checkState(mimeType == null);
@ -925,10 +950,13 @@ import java.util.List;
mimeType = MimeTypes.VIDEO_H263;
} else if (childAtomType == Atom.TYPE_esds) {
Assertions.checkState(mimeType == null);
Pair<String, byte[]> mimeTypeAndInitializationData =
Pair<@NullableType String, byte @NullableType []> mimeTypeAndInitializationDataBytes =
parseEsdsFromParent(parent, childStartPosition);
mimeType = mimeTypeAndInitializationData.first;
initializationData = Collections.singletonList(mimeTypeAndInitializationData.second);
mimeType = mimeTypeAndInitializationDataBytes.first;
@Nullable byte[] initializationDataBytes = mimeTypeAndInitializationDataBytes.second;
if (initializationDataBytes != null) {
initializationData = Collections.singletonList(initializationDataBytes);
}
} else if (childAtomType == Atom.TYPE_pasp) {
pixelWidthHeightRatio = parsePaspFromParent(parent, childStartPosition);
pixelWidthHeightRatioFromPasp = true;
@ -988,13 +1016,14 @@ import java.util.List;
* Parses the edts atom (defined in 14496-12 subsection 8.6.5).
*
* @param edtsAtom edts (edit box) atom to decode.
* @return Pair of edit list durations and edit list media times, or a pair of nulls if they are
* not present.
* @return Pair of edit list durations and edit list media times, or {@code null} if they are not
* present.
*/
@Nullable
private static Pair<long[], long[]> parseEdts(Atom.ContainerAtom edtsAtom) {
Atom.LeafAtom elst;
if (edtsAtom == null || (elst = edtsAtom.getLeafAtomOfType(Atom.TYPE_elst)) == null) {
return Pair.create(null, null);
return null;
}
ParsableByteArray elstData = elst.data;
elstData.setPosition(Atom.HEADER_SIZE);
@ -1024,9 +1053,18 @@ import java.util.List;
return (float) hSpacing / vSpacing;
}
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
int size, int trackId, String language, boolean isQuickTime, DrmInitData drmInitData,
StsdData out, int entryIndex) throws ParserException {
private static void parseAudioSampleEntry(
ParsableByteArray parent,
int atomType,
int position,
int size,
int trackId,
String language,
boolean isQuickTime,
@Nullable DrmInitData drmInitData,
StsdData out,
int entryIndex)
throws ParserException {
parent.setPosition(position + Atom.HEADER_SIZE + StsdData.STSD_HEADER_SIZE);
int quickTimeSoundDescriptionVersion = 0;
@ -1064,8 +1102,9 @@ import java.util.List;
int childPosition = parent.getPosition();
if (atomType == Atom.TYPE_enca) {
Pair<Integer, TrackEncryptionBox> sampleEntryEncryptionData = parseSampleEntryEncryptionData(
parent, position, size);
@Nullable
Pair<Integer, TrackEncryptionBox> sampleEntryEncryptionData =
parseSampleEntryEncryptionData(parent, position, size);
if (sampleEntryEncryptionData != null) {
atomType = sampleEntryEncryptionData.first;
drmInitData = drmInitData == null ? null
@ -1080,7 +1119,7 @@ import java.util.List;
// }
// If the atom type determines a MIME type, set it immediately.
String mimeType = null;
@Nullable String mimeType = null;
if (atomType == Atom.TYPE_ac_3) {
mimeType = MimeTypes.AUDIO_AC3;
} else if (atomType == Atom.TYPE_ec_3) {
@ -1113,21 +1152,21 @@ import java.util.List;
mimeType = MimeTypes.AUDIO_FLAC;
}
byte[] initializationData = null;
@Nullable byte[] initializationData = null;
while (childPosition - position < size) {
parent.setPosition(childPosition);
int childAtomSize = parent.readInt();
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
Assertions.checkState(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = parent.readInt();
if (childAtomType == Atom.TYPE_esds || (isQuickTime && childAtomType == Atom.TYPE_wave)) {
int esdsAtomPosition = childAtomType == Atom.TYPE_esds ? childPosition
: findEsdsPosition(parent, childPosition, childAtomSize);
if (esdsAtomPosition != C.POSITION_UNSET) {
Pair<String, byte[]> mimeTypeAndInitializationData =
Pair<@NullableType String, byte @NullableType []> mimeTypeAndInitializationData =
parseEsdsFromParent(parent, esdsAtomPosition);
mimeType = mimeTypeAndInitializationData.first;
initializationData = mimeTypeAndInitializationData.second;
if (MimeTypes.AUDIO_AAC.equals(mimeType)) {
if (MimeTypes.AUDIO_AAC.equals(mimeType) && initializationData != null) {
// Update sampleRate and channelCount from the AudioSpecificConfig initialization data,
// which is more reliable. See [Internal: b/10903778].
Pair<Integer, Integer> audioSpecificConfig =
@ -1204,7 +1243,7 @@ import java.util.List;
while (childAtomPosition - position < size) {
parent.setPosition(childAtomPosition);
int childAtomSize = parent.readInt();
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
Assertions.checkState(childAtomSize > 0, "childAtomSize should be positive");
int childType = parent.readInt();
if (childType == Atom.TYPE_esds) {
return childAtomPosition;
@ -1214,10 +1253,9 @@ import java.util.List;
return C.POSITION_UNSET;
}
/**
* Returns codec-specific initialization data contained in an esds box.
*/
private static Pair<String, byte[]> parseEsdsFromParent(ParsableByteArray parent, int position) {
/** Returns codec-specific initialization data contained in an esds box. */
private static Pair<@NullableType String, byte @NullableType []> parseEsdsFromParent(
ParsableByteArray parent, int position) {
parent.setPosition(position + Atom.HEADER_SIZE + 4);
// Start of the ES_Descriptor (defined in 14496-1)
parent.skipBytes(1); // ES_Descriptor tag
@ -1263,13 +1301,14 @@ import java.util.List;
* unencrypted atom type and a {@link TrackEncryptionBox}. Null is returned if no common
* encryption sinf atom was present.
*/
@Nullable
private static Pair<Integer, TrackEncryptionBox> parseSampleEntryEncryptionData(
ParsableByteArray parent, int position, int size) {
int childPosition = parent.getPosition();
while (childPosition - position < size) {
parent.setPosition(childPosition);
int childAtomSize = parent.readInt();
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
Assertions.checkState(childAtomSize > 0, "childAtomSize should be positive");
int childAtomType = parent.readInt();
if (childAtomType == Atom.TYPE_sinf) {
Pair<Integer, TrackEncryptionBox> result = parseCommonEncryptionSinfFromParent(parent,
@ -1283,6 +1322,7 @@ import java.util.List;
return null;
}
@Nullable
/* package */ static Pair<Integer, TrackEncryptionBox> parseCommonEncryptionSinfFromParent(
ParsableByteArray parent, int position, int size) {
int childPosition = position + Atom.HEADER_SIZE;
@ -1309,20 +1349,21 @@ import java.util.List;
if (C.CENC_TYPE_cenc.equals(schemeType) || C.CENC_TYPE_cbc1.equals(schemeType)
|| C.CENC_TYPE_cens.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType)) {
Assertions.checkArgument(dataFormat != null, "frma atom is mandatory");
Assertions.checkArgument(schemeInformationBoxPosition != C.POSITION_UNSET,
"schi atom is mandatory");
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.checkArgument(encryptionBox != null, "tenc atom is mandatory");
Assertions.checkStateNotNull(encryptionBox, "tenc atom is mandatory");
return Pair.create(dataFormat, encryptionBox);
} else {
return null;
}
}
private static TrackEncryptionBox parseSchiFromParent(ParsableByteArray parent, int position,
int size, String schemeType) {
@Nullable
private static TrackEncryptionBox parseSchiFromParent(
ParsableByteArray parent, int position, int size, String schemeType) {
int childPosition = position + Atom.HEADER_SIZE;
while (childPosition - position < size) {
parent.setPosition(childPosition);
@ -1359,9 +1400,8 @@ import java.util.List;
return null;
}
/**
* Parses the proj box from sv3d box, as specified by https://github.com/google/spatial-media.
*/
/** Parses the proj box from sv3d box, as specified by https://github.com/google/spatial-media. */
@Nullable
private static byte[] parseProjFromParent(ParsableByteArray parent, int position, int size) {
int childPosition = position + Atom.HEADER_SIZE;
while (childPosition - position < size) {
@ -1477,10 +1517,9 @@ import java.util.List;
public final TrackEncryptionBox[] trackEncryptionBoxes;
public Format format;
@Nullable public Format format;
public int nalUnitLengthFieldLength;
@Track.Transformation
public int requiredSampleTransformation;
@Track.Transformation public int requiredSampleTransformation;
public StsdData(int numberOfEntries) {
trackEncryptionBoxes = new TrackEncryptionBox[numberOfEntries];