mirror of
https://github.com/androidx/media.git
synced 2025-05-06 23:20:42 +08:00
Work around lack of LA_URL attributes in PlayReady key requests init data
PiperOrigin-RevId: 239066912
This commit is contained in:
parent
b5e4523b58
commit
c81c14ae86
@ -6,6 +6,7 @@
|
||||
* Add new `ExoPlaybackException` types for remote exceptions and out-of-memory
|
||||
errors.
|
||||
* HLS:
|
||||
* Work around lack of LA_URL attribute in PlayReady key request init data.
|
||||
* Prevent unnecessary reloads of initialization segments.
|
||||
* Form an adaptive track group out of audio renditions with matching name.
|
||||
* Support encrypted initialization segments
|
||||
|
@ -101,6 +101,9 @@ public final class C {
|
||||
*/
|
||||
public static final String UTF16_NAME = "UTF-16";
|
||||
|
||||
/** The name of the UTF-16 little-endian charset. */
|
||||
public static final String UTF16LE_NAME = "UTF-16LE";
|
||||
|
||||
/**
|
||||
* The name of the serif font family.
|
||||
*/
|
||||
|
@ -29,8 +29,13 @@ import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -44,6 +49,10 @@ import java.util.UUID;
|
||||
public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto> {
|
||||
|
||||
private static final String CENC_SCHEME_MIME_TYPE = "cenc";
|
||||
private static final String MOCK_LA_URL_VALUE = "https://x";
|
||||
private static final String MOCK_LA_URL = "<LA_URL>" + MOCK_LA_URL_VALUE + "</LA_URL>";
|
||||
private static final int UTF_16_BYTES_PER_CHARACTER = 2;
|
||||
private static final String TAG = "FrameworkMediaDrm";
|
||||
|
||||
private final UUID uuid;
|
||||
private final MediaDrm mediaDrm;
|
||||
@ -139,6 +148,9 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
||||
byte[] requestData = adjustRequestData(uuid, request.getData());
|
||||
|
||||
String licenseServerUrl = request.getDefaultUrl();
|
||||
if (MOCK_LA_URL_VALUE.equals(licenseServerUrl)) {
|
||||
licenseServerUrl = "";
|
||||
}
|
||||
if (TextUtils.isEmpty(licenseServerUrl)
|
||||
&& schemeData != null
|
||||
&& !TextUtils.isEmpty(schemeData.licenseServerUrl)) {
|
||||
@ -277,6 +289,18 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
||||
}
|
||||
|
||||
private static byte[] adjustRequestInitData(UUID uuid, byte[] initData) {
|
||||
// TODO: Add API level check once [Internal ref: b/112142048] is fixed.
|
||||
if (C.PLAYREADY_UUID.equals(uuid)) {
|
||||
byte[] schemeSpecificData = PsshAtomUtil.parseSchemeSpecificData(initData, uuid);
|
||||
if (schemeSpecificData == null) {
|
||||
// The init data is not contained in a pssh box.
|
||||
schemeSpecificData = initData;
|
||||
}
|
||||
initData =
|
||||
PsshAtomUtil.buildPsshAtom(
|
||||
C.PLAYREADY_UUID, addLaUrlAttributeIfMissing(schemeSpecificData));
|
||||
}
|
||||
|
||||
// Prior to L the Widevine CDM required data to be extracted from the PSSH atom. Some Amazon
|
||||
// devices also required data to be extracted from the PSSH atom for PlayReady.
|
||||
if ((Util.SDK_INT < 21 && C.WIDEVINE_UUID.equals(uuid))
|
||||
@ -324,4 +348,47 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
|
||||
private static boolean needsForceWidevineL3Workaround() {
|
||||
return "ASUS_Z00AD".equals(Util.MODEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the LA_URL tag is missing, injects a mock LA_URL value to avoid causing the CDM to throw
|
||||
* when creating the key request. The LA_URL attribute is optional but some Android PlayReady
|
||||
* implementations are known to require it. Does nothing it the provided {@code data} already
|
||||
* contains an LA_URL value.
|
||||
*/
|
||||
private static byte[] addLaUrlAttributeIfMissing(byte[] data) {
|
||||
ParsableByteArray byteArray = new ParsableByteArray(data);
|
||||
// See https://docs.microsoft.com/en-us/playready/specifications/specifications for more
|
||||
// information about the init data format.
|
||||
int length = byteArray.readLittleEndianInt();
|
||||
int objectRecordCount = byteArray.readLittleEndianShort();
|
||||
int recordType = byteArray.readLittleEndianShort();
|
||||
if (objectRecordCount != 1 || recordType != 1) {
|
||||
Log.i(TAG, "Unexpected record count or type. Skipping LA_URL workaround.");
|
||||
return data;
|
||||
}
|
||||
int recordLength = byteArray.readLittleEndianShort();
|
||||
String xml = byteArray.readString(recordLength, Charset.forName(C.UTF16LE_NAME));
|
||||
if (xml.contains("<LA_URL>")) {
|
||||
// LA_URL already present. Do nothing.
|
||||
return data;
|
||||
}
|
||||
// This PlayReady object record does not include an LA_URL. We add a mock value for it.
|
||||
int endOfDataTagIndex = xml.indexOf("</DATA>");
|
||||
if (endOfDataTagIndex == -1) {
|
||||
Log.w(TAG, "Could not find the </DATA> tag. Skipping LA_URL workaround.");
|
||||
}
|
||||
String xmlWithMockLaUrl =
|
||||
xml.substring(/* beginIndex= */ 0, /* endIndex= */ endOfDataTagIndex)
|
||||
+ MOCK_LA_URL
|
||||
+ xml.substring(/* beginIndex= */ endOfDataTagIndex);
|
||||
int extraBytes = MOCK_LA_URL.length() * UTF_16_BYTES_PER_CHARACTER;
|
||||
ByteBuffer newData = ByteBuffer.allocate(length + extraBytes);
|
||||
newData.order(ByteOrder.LITTLE_ENDIAN);
|
||||
newData.putInt(length + extraBytes);
|
||||
newData.putShort((short) objectRecordCount);
|
||||
newData.putShort((short) recordType);
|
||||
newData.putShort((short) (xmlWithMockLaUrl.length() * UTF_16_BYTES_PER_CHARACTER));
|
||||
newData.put(xmlWithMockLaUrl.getBytes(Charset.forName(C.UTF16LE_NAME)));
|
||||
return newData.array();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user