Partial nullness annotations for AtomParsers
PiperOrigin-RevId: 284558886
This commit is contained in:
parent
4b281cec3b
commit
539a1ac2e2
@ -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];
|
||||
|
Loading…
x
Reference in New Issue
Block a user