/** * Parses a ContentProtection element. * * @throws XmlPullParserException If an error occurs parsing the element. * @throws IOException If an error occurs reading the element. **/ protected ContentProtection parseContentProtection(XmlPullParser xpp) throws XmlPullParserException, IOException { String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri"); UUID uuid = null; byte[] psshAtom = null; do { xpp.next(); // The cenc:pssh element is defined in 23001-7:2015 if (isStartTag(xpp, "cenc:pssh") && xpp.next() == XmlPullParser.TEXT) { psshAtom = Base64.decode(xpp.getText(), Base64.DEFAULT); uuid = PsshAtomUtil.parseUuid(psshAtom); if (uuid == null) { throw new ParserException("Invalid pssh atom in cenc:pssh element"); } } } while (!isEndTag(xpp, "ContentProtection")); return buildContentProtection(schemeIdUri, uuid, psshAtom); }
/** * Parses a {@link ContentProtection} element. * * @throws XmlPullParserException If an error occurs parsing the element. * @throws IOException If an error occurs reading the element. * @return The parsed {@link ContentProtection} element, or null if the element is unsupported. **/ protected ContentProtection parseContentProtection(XmlPullParser xpp) throws XmlPullParserException, IOException { String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri"); UUID uuid = null; SchemeInitData data = null; boolean seenPsshElement = false; do { xpp.next(); // The cenc:pssh element is defined in 23001-7:2015. if (ParserUtil.isStartTag(xpp, "cenc:pssh") && xpp.next() == XmlPullParser.TEXT) { seenPsshElement = true; data = new SchemeInitData(MimeTypes.VIDEO_MP4, Base64.decode(xpp.getText(), Base64.DEFAULT)); uuid = PsshAtomUtil.parseUuid(data.data); } } while (!ParserUtil.isEndTag(xpp, "ContentProtection")); if (seenPsshElement && uuid == null) { Log.w(TAG, "Skipped unsupported ContentProtection element"); return null; } return buildContentProtection(schemeIdUri, uuid, data); }
@Nullable static DrmInitData.SchemeInitData getWidevineInitData(@Nullable DrmInitData drmInitData) { if (drmInitData == null) { Log.e(TAG, "No PSSH in media"); return null; } DrmInitData.SchemeInitData schemeInitData = drmInitData.get(WIDEVINE_UUID); if (schemeInitData == null) { Log.e(TAG, "No Widevine PSSH in media"); return null; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // Prior to L the Widevine CDM required data to be extracted from the PSSH atom. byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeInitData.data, WIDEVINE_UUID); if (psshData == null) { // Extraction failed. schemeData isn't a Widevine PSSH atom, so leave it unchanged. } else { schemeInitData = new DrmInitData.SchemeInitData(schemeInitData.mimeType, psshData); } } return schemeInitData; }
@TargetApi(18) private DrmInitData getDrmInitDataV18() { // MediaExtractor only supports psshInfo for MP4, so it's ok to hard code the mimeType here. Map<UUID, byte[]> psshInfo = extractor.getPsshInfo(); if (psshInfo == null || psshInfo.isEmpty()) { return null; } DrmInitData.Mapped drmInitData = new DrmInitData.Mapped(MimeTypes.VIDEO_MP4); for (UUID uuid : psshInfo.keySet()) { byte[] psshAtom = PsshAtomUtil.buildPsshAtom(uuid, psshInfo.get(uuid)); drmInitData.put(uuid, psshAtom); } return drmInitData; }
@Override public final void open(DrmInitData drmInitData) { if (++openCount != 1) { return; } if (postRequestHandler == null) { requestHandlerThread = new HandlerThread("DrmRequestHandler"); requestHandlerThread.start(); postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper()); } if (schemeData == null) { mimeType = drmInitData.mimeType; schemeData = drmInitData.get(uuid); if (schemeData == null) { onError(new IllegalStateException("Media does not support uuid: " + uuid)); return; } if (Util.SDK_INT < 21) { // Prior to L the Widevine CDM required data to be extracted from the PSSH atom. byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeData, WIDEVINE_UUID); if (psshData == null) { // Extraction failed. schemeData isn't a Widevine PSSH atom, so leave it unchanged. } else { schemeData = psshData; } } } state = STATE_OPENING; openInternal(true); }
@TargetApi(18) private DrmInitData getDrmInitDataV18() { // MediaExtractor only supports psshInfo for MP4, so it's ok to hard code the mimeType here. Map<UUID, byte[]> psshInfo = extractor.getPsshInfo(); if (psshInfo == null || psshInfo.isEmpty()) { return null; } DrmInitData.Mapped drmInitData = new DrmInitData.Mapped(); for (UUID uuid : psshInfo.keySet()) { byte[] psshAtom = PsshAtomUtil.buildPsshAtom(uuid, psshInfo.get(uuid)); drmInitData.put(uuid, new SchemeInitData(MimeTypes.VIDEO_MP4, psshAtom)); } return drmInitData; }
@Override public void open(DrmInitData drmInitData) { if (++openCount != 1) { return; } if (postRequestHandler == null) { requestHandlerThread = new HandlerThread("DrmRequestHandler"); requestHandlerThread.start(); postRequestHandler = new PostRequestHandler(requestHandlerThread.getLooper()); } if (schemeInitData == null) { schemeInitData = drmInitData.get(uuid); if (schemeInitData == null) { onError(new IllegalStateException("Media does not support uuid: " + uuid)); return; } if (Util.SDK_INT < 21) { // Prior to L the Widevine CDM required data to be extracted from the PSSH atom. byte[] psshData = PsshAtomUtil.parseSchemeSpecificData(schemeInitData.data, WIDEVINE_UUID); if (psshData == null) { // Extraction failed. schemeData isn't a Widevine PSSH atom, so leave it unchanged. } else { schemeInitData = new SchemeInitData(schemeInitData.mimeType, psshData); } } } state = STATE_OPENING; openInternal(true); }
@Override public Object build() { return new ProtectionElement(uuid, PsshAtomUtil.buildPsshAtom(uuid, initData)); }