Handle non-AAC/AVC encrypted audio/video sample entries.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=123847497
This commit is contained in:
parent
ecad3bb396
commit
0565d8e100
@ -632,8 +632,13 @@ import java.util.List;
|
|||||||
float pixelWidthHeightRatio = 1;
|
float pixelWidthHeightRatio = 1;
|
||||||
parent.skipBytes(50);
|
parent.skipBytes(50);
|
||||||
|
|
||||||
List<byte[]> initializationData = null;
|
|
||||||
int childPosition = parent.getPosition();
|
int childPosition = parent.getPosition();
|
||||||
|
if (atomType == Atom.TYPE_encv) {
|
||||||
|
atomType = parseSampleEntryEncryptionData(parent, position, size, out, entryIndex);
|
||||||
|
parent.setPosition(childPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<byte[]> initializationData = null;
|
||||||
String mimeType = null;
|
String mimeType = null;
|
||||||
while (childPosition - position < size) {
|
while (childPosition - position < size) {
|
||||||
parent.setPosition(childPosition);
|
parent.setPosition(childPosition);
|
||||||
@ -660,6 +665,9 @@ import java.util.List;
|
|||||||
Pair<List<byte[]>, Integer> hvcCData = parseHvcCFromParent(parent, childStartPosition);
|
Pair<List<byte[]>, Integer> hvcCData = parseHvcCFromParent(parent, childStartPosition);
|
||||||
initializationData = hvcCData.first;
|
initializationData = hvcCData.first;
|
||||||
out.nalUnitLengthFieldLength = hvcCData.second;
|
out.nalUnitLengthFieldLength = hvcCData.second;
|
||||||
|
} else if (childAtomType == Atom.TYPE_vpcC) {
|
||||||
|
Assertions.checkState(mimeType == null);
|
||||||
|
mimeType = (atomType == Atom.TYPE_vp08) ? MimeTypes.VIDEO_VP8 : MimeTypes.VIDEO_VP9;
|
||||||
} else if (childAtomType == Atom.TYPE_d263) {
|
} else if (childAtomType == Atom.TYPE_d263) {
|
||||||
Assertions.checkState(mimeType == null);
|
Assertions.checkState(mimeType == null);
|
||||||
mimeType = MimeTypes.VIDEO_H263;
|
mimeType = MimeTypes.VIDEO_H263;
|
||||||
@ -669,15 +677,9 @@ import java.util.List;
|
|||||||
parseEsdsFromParent(parent, childStartPosition);
|
parseEsdsFromParent(parent, childStartPosition);
|
||||||
mimeType = mimeTypeAndInitializationData.first;
|
mimeType = mimeTypeAndInitializationData.first;
|
||||||
initializationData = Collections.singletonList(mimeTypeAndInitializationData.second);
|
initializationData = Collections.singletonList(mimeTypeAndInitializationData.second);
|
||||||
} else if (childAtomType == Atom.TYPE_sinf) {
|
|
||||||
out.trackEncryptionBoxes[entryIndex] =
|
|
||||||
parseSinfFromParent(parent, childStartPosition, childAtomSize);
|
|
||||||
} else if (childAtomType == Atom.TYPE_pasp) {
|
} else if (childAtomType == Atom.TYPE_pasp) {
|
||||||
pixelWidthHeightRatio = parsePaspFromParent(parent, childStartPosition);
|
pixelWidthHeightRatio = parsePaspFromParent(parent, childStartPosition);
|
||||||
pixelWidthHeightRatioFromPasp = true;
|
pixelWidthHeightRatioFromPasp = true;
|
||||||
} else if (childAtomType == Atom.TYPE_vpcC) {
|
|
||||||
Assertions.checkState(mimeType == null);
|
|
||||||
mimeType = (atomType == Atom.TYPE_vp08) ? MimeTypes.VIDEO_VP8 : MimeTypes.VIDEO_VP9;
|
|
||||||
}
|
}
|
||||||
childPosition += childAtomSize;
|
childPosition += childAtomSize;
|
||||||
}
|
}
|
||||||
@ -795,30 +797,6 @@ import java.util.List;
|
|||||||
return Pair.create(editListDurations, editListMediaTimes);
|
return Pair.create(editListDurations, editListMediaTimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TrackEncryptionBox parseSinfFromParent(ParsableByteArray parent, int position,
|
|
||||||
int size) {
|
|
||||||
int childPosition = position + Atom.HEADER_SIZE;
|
|
||||||
|
|
||||||
TrackEncryptionBox trackEncryptionBox = null;
|
|
||||||
while (childPosition - position < size) {
|
|
||||||
parent.setPosition(childPosition);
|
|
||||||
int childAtomSize = parent.readInt();
|
|
||||||
int childAtomType = parent.readInt();
|
|
||||||
if (childAtomType == Atom.TYPE_frma) {
|
|
||||||
parent.readInt(); // dataFormat.
|
|
||||||
} else if (childAtomType == Atom.TYPE_schm) {
|
|
||||||
parent.skipBytes(4);
|
|
||||||
parent.readInt(); // schemeType. Expect cenc
|
|
||||||
parent.readInt(); // schemeVersion. Expect 0x00010000
|
|
||||||
} else if (childAtomType == Atom.TYPE_schi) {
|
|
||||||
trackEncryptionBox = parseSchiFromParent(parent, childPosition, childAtomSize);
|
|
||||||
}
|
|
||||||
childPosition += childAtomSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackEncryptionBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float parsePaspFromParent(ParsableByteArray parent, int position) {
|
private static float parsePaspFromParent(ParsableByteArray parent, int position) {
|
||||||
parent.setPosition(position + Atom.HEADER_SIZE);
|
parent.setPosition(position + Atom.HEADER_SIZE);
|
||||||
int hSpacing = parent.readUnsignedIntToInt();
|
int hSpacing = parent.readUnsignedIntToInt();
|
||||||
@ -826,27 +804,6 @@ import java.util.List;
|
|||||||
return (float) hSpacing / vSpacing;
|
return (float) hSpacing / vSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TrackEncryptionBox parseSchiFromParent(ParsableByteArray parent, int position,
|
|
||||||
int size) {
|
|
||||||
int childPosition = position + Atom.HEADER_SIZE;
|
|
||||||
while (childPosition - position < size) {
|
|
||||||
parent.setPosition(childPosition);
|
|
||||||
int childAtomSize = parent.readInt();
|
|
||||||
int childAtomType = parent.readInt();
|
|
||||||
if (childAtomType == Atom.TYPE_tenc) {
|
|
||||||
parent.skipBytes(4);
|
|
||||||
int firstInt = parent.readInt();
|
|
||||||
boolean defaultIsEncrypted = (firstInt >> 8) == 1;
|
|
||||||
int defaultInitVectorSize = firstInt & 0xFF;
|
|
||||||
byte[] defaultKeyId = new byte[16];
|
|
||||||
parent.readBytes(defaultKeyId, 0, defaultKeyId.length);
|
|
||||||
return new TrackEncryptionBox(defaultIsEncrypted, defaultInitVectorSize, defaultKeyId);
|
|
||||||
}
|
|
||||||
childPosition += childAtomSize;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
|
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
|
||||||
int size, int trackId, String language, boolean isQuickTime, DrmInitData drmInitData,
|
int size, int trackId, String language, boolean isQuickTime, DrmInitData drmInitData,
|
||||||
StsdData out, int entryIndex) {
|
StsdData out, int entryIndex) {
|
||||||
@ -886,6 +843,12 @@ import java.util.List;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int childPosition = parent.getPosition();
|
||||||
|
if (atomType == Atom.TYPE_enca) {
|
||||||
|
atomType = parseSampleEntryEncryptionData(parent, position, size, out, entryIndex);
|
||||||
|
parent.setPosition(childPosition);
|
||||||
|
}
|
||||||
|
|
||||||
// If the atom type determines a MIME type, set it immediately.
|
// If the atom type determines a MIME type, set it immediately.
|
||||||
String mimeType = null;
|
String mimeType = null;
|
||||||
if (atomType == Atom.TYPE_ac_3) {
|
if (atomType == Atom.TYPE_ac_3) {
|
||||||
@ -907,19 +870,14 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
|
|
||||||
byte[] initializationData = null;
|
byte[] initializationData = null;
|
||||||
int childAtomPosition = parent.getPosition();
|
while (childPosition - position < size) {
|
||||||
while (childAtomPosition - position < size) {
|
parent.setPosition(childPosition);
|
||||||
parent.setPosition(childAtomPosition);
|
|
||||||
int childAtomSize = parent.readInt();
|
int childAtomSize = parent.readInt();
|
||||||
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
|
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
|
||||||
int childAtomType = parent.readInt();
|
int childAtomType = parent.readInt();
|
||||||
if (atomType == Atom.TYPE_mp4a || atomType == Atom.TYPE_enca) {
|
if (childAtomType == Atom.TYPE_esds || (isQuickTime && childAtomType == Atom.TYPE_wave)) {
|
||||||
int esdsAtomPosition = -1;
|
int esdsAtomPosition = childAtomType == Atom.TYPE_esds ? childPosition
|
||||||
if (childAtomType == Atom.TYPE_esds) {
|
: findEsdsPosition(parent, childPosition, childAtomSize);
|
||||||
esdsAtomPosition = childAtomPosition;
|
|
||||||
} else if (isQuickTime && childAtomType == Atom.TYPE_wave) {
|
|
||||||
esdsAtomPosition = findEsdsPosition(parent, childAtomPosition, childAtomSize);
|
|
||||||
}
|
|
||||||
if (esdsAtomPosition != -1) {
|
if (esdsAtomPosition != -1) {
|
||||||
Pair<String, byte[]> mimeTypeAndInitializationData =
|
Pair<String, byte[]> mimeTypeAndInitializationData =
|
||||||
parseEsdsFromParent(parent, esdsAtomPosition);
|
parseEsdsFromParent(parent, esdsAtomPosition);
|
||||||
@ -933,45 +891,32 @@ import java.util.List;
|
|||||||
sampleRate = audioSpecificConfig.first;
|
sampleRate = audioSpecificConfig.first;
|
||||||
channelCount = audioSpecificConfig.second;
|
channelCount = audioSpecificConfig.second;
|
||||||
}
|
}
|
||||||
} else if (childAtomType == Atom.TYPE_sinf) {
|
|
||||||
out.trackEncryptionBoxes[entryIndex] = parseSinfFromParent(parent, childAtomPosition,
|
|
||||||
childAtomSize);
|
|
||||||
}
|
}
|
||||||
} else if (atomType == Atom.TYPE_ac_3 && childAtomType == Atom.TYPE_dac3) {
|
} else if (childAtomType == Atom.TYPE_dac3) {
|
||||||
// TODO: Choose the right AC-3 track based on the contents of dac3/dec3.
|
parent.setPosition(Atom.HEADER_SIZE + childPosition);
|
||||||
// TODO: Add support for encryption (by setting out.trackEncryptionBoxes).
|
|
||||||
parent.setPosition(Atom.HEADER_SIZE + childAtomPosition);
|
|
||||||
out.format = Ac3Util.parseAc3AnnexFFormat(parent, Integer.toString(trackId), language,
|
out.format = Ac3Util.parseAc3AnnexFFormat(parent, Integer.toString(trackId), language,
|
||||||
drmInitData);
|
drmInitData);
|
||||||
return;
|
} else if (childAtomType == Atom.TYPE_dec3) {
|
||||||
} else if (atomType == Atom.TYPE_ec_3 && childAtomType == Atom.TYPE_dec3) {
|
parent.setPosition(Atom.HEADER_SIZE + childPosition);
|
||||||
parent.setPosition(Atom.HEADER_SIZE + childAtomPosition);
|
|
||||||
out.format = Ac3Util.parseEAc3AnnexFFormat(parent, Integer.toString(trackId), language,
|
out.format = Ac3Util.parseEAc3AnnexFFormat(parent, Integer.toString(trackId), language,
|
||||||
drmInitData);
|
drmInitData);
|
||||||
return;
|
} else if (childAtomType == Atom.TYPE_ddts) {
|
||||||
} else if ((atomType == Atom.TYPE_dtsc || atomType == Atom.TYPE_dtse
|
|
||||||
|| atomType == Atom.TYPE_dtsh || atomType == Atom.TYPE_dtsl)
|
|
||||||
&& childAtomType == Atom.TYPE_ddts) {
|
|
||||||
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
||||||
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0,
|
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, null, drmInitData, 0,
|
||||||
language);
|
language);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
childAtomPosition += childAtomSize;
|
childPosition += childAtomSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the media type was not recognized, ignore the track.
|
if (out.format == null && mimeType != null) {
|
||||||
if (mimeType == null) {
|
// TODO: Determine the correct PCM encoding.
|
||||||
return;
|
int pcmEncoding =
|
||||||
|
MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT : Format.NO_VALUE;
|
||||||
|
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
||||||
|
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, pcmEncoding,
|
||||||
|
initializationData == null ? null : Collections.singletonList(initializationData),
|
||||||
|
drmInitData, 0, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Determine the correct PCM encoding.
|
|
||||||
int pcmEncoding = MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT : Format.NO_VALUE;
|
|
||||||
|
|
||||||
out.format = Format.createAudioSampleFormat(Integer.toString(trackId), mimeType,
|
|
||||||
Format.NO_VALUE, Format.NO_VALUE, channelCount, sampleRate, pcmEncoding,
|
|
||||||
initializationData == null ? null : Collections.singletonList(initializationData),
|
|
||||||
drmInitData, 0, language);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the position of the esds box within a parent, or -1 if no esds box is found */
|
/** Returns the position of the esds box within a parent, or -1 if no esds box is found */
|
||||||
@ -1064,6 +1009,78 @@ import java.util.List;
|
|||||||
return Pair.create(mimeType, initializationData);
|
return Pair.create(mimeType, initializationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses encryption data from an audio/video sample entry, populating {@code out} and returning
|
||||||
|
* the unencrypted atom type, or 0 if no sinf atom was present.
|
||||||
|
*/
|
||||||
|
private static int parseSampleEntryEncryptionData(ParsableByteArray parent, int position,
|
||||||
|
int size, StsdData out, int entryIndex) {
|
||||||
|
int childPosition = parent.getPosition();
|
||||||
|
while (childPosition - position < size) {
|
||||||
|
parent.setPosition(childPosition);
|
||||||
|
int childAtomSize = parent.readInt();
|
||||||
|
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
|
||||||
|
int childAtomType = parent.readInt();
|
||||||
|
if (childAtomType == Atom.TYPE_sinf) {
|
||||||
|
Pair<Integer, TrackEncryptionBox> result = parseSinfFromParent(parent, childPosition,
|
||||||
|
childAtomSize);
|
||||||
|
Integer dataFormat = result.first;
|
||||||
|
Assertions.checkArgument(dataFormat != null, "frma atom is mandatory");
|
||||||
|
out.trackEncryptionBoxes[entryIndex] = result.second;
|
||||||
|
return dataFormat;
|
||||||
|
}
|
||||||
|
childPosition += childAtomSize;
|
||||||
|
}
|
||||||
|
// This enca/encv box does not have a data format so return an invalid atom type.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Pair<Integer, TrackEncryptionBox> parseSinfFromParent(ParsableByteArray parent,
|
||||||
|
int position, int size) {
|
||||||
|
int childPosition = position + Atom.HEADER_SIZE;
|
||||||
|
|
||||||
|
TrackEncryptionBox trackEncryptionBox = null;
|
||||||
|
Integer dataFormat = null;
|
||||||
|
while (childPosition - position < size) {
|
||||||
|
parent.setPosition(childPosition);
|
||||||
|
int childAtomSize = parent.readInt();
|
||||||
|
int childAtomType = parent.readInt();
|
||||||
|
if (childAtomType == Atom.TYPE_frma) {
|
||||||
|
dataFormat = parent.readInt();
|
||||||
|
} else if (childAtomType == Atom.TYPE_schm) {
|
||||||
|
parent.skipBytes(4);
|
||||||
|
parent.readInt(); // schemeType. Expect cenc
|
||||||
|
parent.readInt(); // schemeVersion. Expect 0x00010000
|
||||||
|
} else if (childAtomType == Atom.TYPE_schi) {
|
||||||
|
trackEncryptionBox = parseSchiFromParent(parent, childPosition, childAtomSize);
|
||||||
|
}
|
||||||
|
childPosition += childAtomSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair.create(dataFormat, trackEncryptionBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TrackEncryptionBox parseSchiFromParent(ParsableByteArray parent, int position,
|
||||||
|
int size) {
|
||||||
|
int childPosition = position + Atom.HEADER_SIZE;
|
||||||
|
while (childPosition - position < size) {
|
||||||
|
parent.setPosition(childPosition);
|
||||||
|
int childAtomSize = parent.readInt();
|
||||||
|
int childAtomType = parent.readInt();
|
||||||
|
if (childAtomType == Atom.TYPE_tenc) {
|
||||||
|
parent.skipBytes(4);
|
||||||
|
int firstInt = parent.readInt();
|
||||||
|
boolean defaultIsEncrypted = (firstInt >> 8) == 1;
|
||||||
|
int defaultInitVectorSize = firstInt & 0xFF;
|
||||||
|
byte[] defaultKeyId = new byte[16];
|
||||||
|
parent.readBytes(defaultKeyId, 0, defaultKeyId.length);
|
||||||
|
return new TrackEncryptionBox(defaultIsEncrypted, defaultInitVectorSize, defaultKeyId);
|
||||||
|
}
|
||||||
|
childPosition += childAtomSize;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/** Parses the size of an expandable class, as specified by ISO 14496-1 subsection 8.3.3. */
|
/** Parses the size of an expandable class, as specified by ISO 14496-1 subsection 8.3.3. */
|
||||||
private static int parseExpandableClassSize(ParsableByteArray data) {
|
private static int parseExpandableClassSize(ParsableByteArray data) {
|
||||||
int currentByte = data.readUnsignedByte();
|
int currentByte = data.readUnsignedByte();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user