/** * Returns a copy with the specified protection scheme type. * * @param schemeType A protection scheme type. May be null. * @return A copy with the specified protection scheme type. */ public DrmInitData copyWithSchemeType(@Nullable String schemeType) { if (Util.areEqual(this.schemeType, schemeType)) { return this; } return new DrmInitData(schemeType, false, schemeDatas); }
@Test @SuppressWarnings("deprecation") public void testSchemeDatasWithSameUuid() { DrmInitData testInitData = new DrmInitData(DATA_1, DATA_1B); assertThat(testInitData.schemeDataCount).isEqualTo(2); // Deprecated get method should return first entry. assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); // Test retrieval of first and second entry. assertThat(testInitData.get(0)).isEqualTo(DATA_1); assertThat(testInitData.get(1)).isEqualTo(DATA_1B); }
@Test public void testEquals() { DrmInitData drmInitData = new DrmInitData(DATA_1, DATA_2); // Basic non-referential equality test. DrmInitData testInitData = new DrmInitData(DATA_1, DATA_2); assertThat(testInitData).isEqualTo(drmInitData); assertThat(testInitData.hashCode()).isEqualTo(drmInitData.hashCode()); // Basic non-referential equality test with non-referential scheme data. testInitData = new DrmInitData(DATA_1B, DATA_2B); assertThat(testInitData).isEqualTo(drmInitData); assertThat(testInitData.hashCode()).isEqualTo(drmInitData.hashCode()); // Passing the scheme data in reverse order shouldn't affect equality. testInitData = new DrmInitData(DATA_2, DATA_1); assertThat(testInitData).isEqualTo(drmInitData); assertThat(testInitData.hashCode()).isEqualTo(drmInitData.hashCode()); // Ditto. testInitData = new DrmInitData(DATA_2B, DATA_1B); assertThat(testInitData).isEqualTo(drmInitData); assertThat(testInitData.hashCode()).isEqualTo(drmInitData.hashCode()); // Different number of tuples should affect equality. testInitData = new DrmInitData(DATA_1); assertThat(drmInitData).isNotEqualTo(testInitData); // Different data in one of the tuples should affect equality. testInitData = new DrmInitData(DATA_1, DATA_UNIVERSAL); assertThat(testInitData).isNotEqualTo(drmInitData); }
if (data.hasData() && !containsSchemeDataWithUuid(result, manifestDatasCount, data.uuid)) { result.add(data); return result.isEmpty() ? null : new DrmInitData(schemeType, result);
private List<SchemeData> getAllSchemeData(DrmInitData drmInitData) { ArrayList<SchemeData> schemeDatas = new ArrayList<>(); for (int i = 0; i < drmInitData.schemeDataCount; i++) { schemeDatas.add(drmInitData.get(i)); } return schemeDatas; }
@Test public void testParcelable() { DrmInitData drmInitDataToParcel = new DrmInitData(DATA_1, DATA_2); Parcel parcel = Parcel.obtain(); drmInitDataToParcel.writeToParcel(parcel, 0); parcel.setDataPosition(0); DrmInitData drmInitDataFromParcel = DrmInitData.CREATOR.createFromParcel(parcel); assertThat(drmInitDataFromParcel).isEqualTo(drmInitDataToParcel); parcel.recycle(); }
result = 31 * result + (language == null ? 0 : language.hashCode()); result = 31 * result + accessibilityChannel; result = 31 * result + (drmInitData == null ? 0 : drmInitData.hashCode()); result = 31 * result + (metadata == null ? 0 : metadata.hashCode()); result = 31 * result + (label != null ? label.hashCode() : 0);
public void updateDrmInitData(DrmInitData drmInitData) { TrackEncryptionBox encryptionBox = track.getSampleDescriptionEncryptionBox(fragment.header.sampleDescriptionIndex); String schemeType = encryptionBox != null ? encryptionBox.schemeType : null; output.format(track.format.copyWithDrmInitData(drmInitData.copyWithSchemeType(schemeType))); }
/** * Extracts {@link SchemeData} instances suitable for the given DRM scheme {@link UUID}. * * @param drmInitData The {@link DrmInitData} from which to extract the {@link SchemeData}. * @param uuid The UUID. * @param allowMissingData Whether a {@link SchemeData} with null {@link SchemeData#data} may be * returned. * @return The extracted {@link SchemeData} instances, or an empty list if no suitable data is * present. */ private static List<SchemeData> getSchemeDatas( DrmInitData drmInitData, UUID uuid, boolean allowMissingData) { // Look for matching scheme data (matching the Common PSSH box for ClearKey). List<SchemeData> matchingSchemeDatas = new ArrayList<>(drmInitData.schemeDataCount); for (int i = 0; i < drmInitData.schemeDataCount; i++) { SchemeData schemeData = drmInitData.get(i); boolean uuidMatches = schemeData.matches(uuid) || (C.CLEARKEY_UUID.equals(uuid) && schemeData.matches(C.COMMON_PSSH_UUID)); if (uuidMatches && (schemeData.data != null || allowMissingData)) { matchingSchemeDatas.add(schemeData); } } return matchingSchemeDatas; }
.add("selectionFlags", format.selectionFlags) .add("language", format.language) .add("drmInitData", format.drmInitData != null ? format.drmInitData.hashCode() : "-");
atomType = sampleEntryEncryptionData.first; drmInitData = drmInitData == null ? null : drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); out.trackEncryptionBoxes[entryIndex] = sampleEntryEncryptionData.second;
protected Representation buildRepresentation(RepresentationInfo representationInfo, String contentId, String extraDrmSchemeType, ArrayList<SchemeData> extraDrmSchemeDatas, ArrayList<Descriptor> extraInbandEventStreams) { Format format = representationInfo.format; String drmSchemeType = representationInfo.drmSchemeType != null ? representationInfo.drmSchemeType : extraDrmSchemeType; ArrayList<SchemeData> drmSchemeDatas = representationInfo.drmSchemeDatas; drmSchemeDatas.addAll(extraDrmSchemeDatas); if (!drmSchemeDatas.isEmpty()) { filterRedundantIncompleteSchemeDatas(drmSchemeDatas); DrmInitData drmInitData = new DrmInitData(drmSchemeType, drmSchemeDatas); format = format.copyWithDrmInitData(drmInitData); } ArrayList<Descriptor> inbandEventStreams = representationInfo.inbandEventStreams; inbandEventStreams.addAll(extraInbandEventStreams); return Representation.newInstance(contentId, representationInfo.revisionId, format, representationInfo.baseUrl, representationInfo.segmentBase, inbandEventStreams); }
@Test @SuppressWarnings("deprecation") public void testGetByUuid() { // Basic matching. DrmInitData testInitData = new DrmInitData(DATA_1, DATA_2); assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); assertThat(testInitData.get(PLAYREADY_UUID)).isEqualTo(DATA_2); assertThat(testInitData.get(UUID_NIL)).isNull(); // Basic matching including universal data. testInitData = new DrmInitData(DATA_1, DATA_2, DATA_UNIVERSAL); assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); assertThat(testInitData.get(PLAYREADY_UUID)).isEqualTo(DATA_2); assertThat(testInitData.get(UUID_NIL)).isEqualTo(DATA_UNIVERSAL); // Passing the scheme data in reverse order shouldn't affect equality. testInitData = new DrmInitData(DATA_UNIVERSAL, DATA_2, DATA_1); assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); assertThat(testInitData.get(PLAYREADY_UUID)).isEqualTo(DATA_2); assertThat(testInitData.get(UUID_NIL)).isEqualTo(DATA_UNIVERSAL); // Universal data should be returned in the absence of a specific match. testInitData = new DrmInitData(DATA_1, DATA_UNIVERSAL); assertThat(testInitData.get(WIDEVINE_UUID)).isEqualTo(DATA_1); assertThat(testInitData.get(PLAYREADY_UUID)).isEqualTo(DATA_UNIVERSAL); assertThat(testInitData.get(UUID_NIL)).isEqualTo(DATA_UNIVERSAL); }
@Override public boolean canAcquireSession(@NonNull DrmInitData drmInitData) { if (offlineLicenseKeySetId != null) { // An offline license can be restored so a session can always be acquired. return true; } List<SchemeData> schemeDatas = getSchemeDatas(drmInitData, uuid, true); if (schemeDatas.isEmpty()) { if (drmInitData.schemeDataCount == 1 && drmInitData.get(0).matches(C.COMMON_PSSH_UUID)) { // Assume scheme specific data will be added before the session is opened. Log.w( TAG, "DrmInitData only contains common PSSH SchemeData. Assuming support for: " + uuid); } else { // No data for this manager's scheme. return false; } } String schemeType = drmInitData.schemeType; if (schemeType == null || C.CENC_TYPE_cenc.equals(schemeType)) { // If there is no scheme information, assume patternless AES-CTR. return true; } else if (C.CENC_TYPE_cbc1.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType) || C.CENC_TYPE_cens.equals(schemeType)) { // API support for AES-CBC and pattern encryption was added in API 24. However, the // implementation was not stable until API 25. return Util.SDK_INT >= 25; } // Unknown schemes, assume one of them is supported. return true; }
.add("selectionFlags", format.selectionFlags) .add("language", format.language) .add("drmInitData", format.drmInitData != null ? format.drmInitData.hashCode() : "-");
atomType = sampleEntryEncryptionData.first; drmInitData = drmInitData == null ? null : drmInitData.copyWithSchemeType(sampleEntryEncryptionData.second.schemeType); out.trackEncryptionBoxes[entryIndex] = sampleEntryEncryptionData.second;
/** Returns DrmInitData from leaf atoms. */ private static DrmInitData getDrmInitDataFromAtoms(List<Atom.LeafAtom> leafChildren) { ArrayList<SchemeData> schemeDatas = null; int leafChildrenSize = leafChildren.size(); for (int i = 0; i < leafChildrenSize; i++) { LeafAtom child = leafChildren.get(i); if (child.type == Atom.TYPE_pssh) { if (schemeDatas == null) { schemeDatas = new ArrayList<>(); } byte[] psshData = child.data.data; UUID uuid = PsshAtomUtil.parseUuid(psshData); if (uuid == null) { Log.w(TAG, "Skipped pssh atom (failed to extract uuid)"); } else { schemeDatas.add(new SchemeData(uuid, MimeTypes.VIDEO_MP4, psshData)); } } } return schemeDatas == null ? null : new DrmInitData(schemeDatas); }
if (drmInitData != null) { for (int i = 0; i < drmInitData.schemeDataCount; i++) { requiresSecureDecryption |= drmInitData.get(i).requiresSecureDecryption;
@Override public Object build() { StreamElement[] streamElementArray = new StreamElement[streamElements.size()]; streamElements.toArray(streamElementArray); if (protectionElement != null) { DrmInitData drmInitData = new DrmInitData(new SchemeData(protectionElement.uuid, MimeTypes.VIDEO_MP4, protectionElement.data)); for (StreamElement streamElement : streamElementArray) { int type = streamElement.type; if (type == C.TRACK_TYPE_VIDEO || type == C.TRACK_TYPE_AUDIO) { Format[] formats = streamElement.formats; for (int i = 0; i < formats.length; i++) { formats[i] = formats[i].copyWithDrmInitData(drmInitData); } } } } return new SsManifest(majorVersion, minorVersion, timescale, duration, dvrWindowLength, lookAheadCount, isLive, protectionElement, streamElementArray); }
@Test public void testParseSampleAesMethod() throws Exception { Uri playlistUri = Uri.parse("https://example.com/test.m3u8"); String playlistString = "#EXTM3U\n" + "#EXT-X-MEDIA-SEQUENCE:0\n" + "#EXTINF:8,\n" + "https://priv.example.com/1.ts\n" + "\n" + "#EXT-X-KEY:METHOD=SAMPLE-AES,URI=" + "\"data:text/plain;base64,VGhpcyBpcyBhbiBlYXN0ZXIgZWdn\"," + "IV=0x9358382AEB449EE23C3D809DA0B9CCD3,KEYFORMATVERSIONS=\"1\"," + "KEYFORMAT=\"com.widevine\",IV=0x1566B\n" + "#EXTINF:8,\n" + "https://priv.example.com/2.ts\n" + "#EXT-X-ENDLIST\n"; InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString)); HlsMediaPlaylist playlist = (HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream); assertThat(playlist.protectionSchemes.schemeType).isEqualTo(C.CENC_TYPE_cbcs); assertThat(playlist.protectionSchemes.get(0).matches(C.WIDEVINE_UUID)).isTrue(); assertThat(playlist.protectionSchemes.get(0).hasData()).isFalse(); assertThat(playlist.segments.get(0).drmInitData).isNull(); assertThat(playlist.segments.get(1).drmInitData.get(0).matches(C.WIDEVINE_UUID)).isTrue(); assertThat(playlist.segments.get(1).drmInitData.get(0).hasData()).isTrue(); }