Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
c81c14ae
authored
Mar 18, 2019
by
aquilescanta
Committed by
Oliver Woodman
Mar 20, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Work around lack of LA_URL attributes in PlayReady key requests init data
PiperOrigin-RevId: 239066912
parent
b5e4523b
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
71 additions
and
0 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/C.java
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
RELEASENOTES.md
View file @
c81c14ae
...
...
@@ -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
...
...
library/core/src/main/java/com/google/android/exoplayer2/C.java
View file @
c81c14ae
...
...
@@ -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.
*/
...
...
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
View file @
c81c14ae
...
...
@@ -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
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment