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
e8221963
authored
Aug 24, 2020
by
Oliver Woodman
Committed by
GitHub
Aug 24, 2020
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #7784 from google/dev-v2-r2.11.8
r2.11.8
parents
5bfad37c
1475f78d
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
233 additions
and
89 deletions
RELEASENOTES.md
constants.gradle
demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
extensions/ima/build.gradle
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java
library/core/src/main/java/com/google/android/exoplayer2/util/ConditionVariable.java
library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
library/core/src/test/java/com/google/android/exoplayer2/util/UtilTest.java
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsUtil.java
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java
RELEASENOTES.md
View file @
e8221963
# Release notes #
### 2.11.8 (2020-08-25) ###
*
Fix distorted playback of floating point audio when samples exceed the
`[-1, 1]`
nominal range.
*
MP4:
*
Add support for
`piff`
and
`isml`
brands
(
[
#7584
](
https://github.com/google/ExoPlayer/issues/7584
)
).
*
Fix playback of very short MP4 files.
*
FMP4:
*
Fix
`saiz`
and
`senc`
sample count checks, resolving a "length
mismatch"
`ParserException`
when playing certain protected FMP4 streams
(
[
#7592
](
https://github.com/google/ExoPlayer/issues/7592
)
).
*
Fix handling of
`traf`
boxes containing multiple
`sbgp`
or
`sgpd`
boxes.
*
FLV: Ignore
`SCRIPTDATA`
segments with invalid name types, rather than
failing playback (
[
#7675
](
https://github.com/google/ExoPlayer/issues/7675
)
).
*
Better infer the content type of
`.ism`
and
`.isml`
streaming URLs.
*
Workaround an issue on Broadcom based devices where playbacks would not
transition to
`STATE_ENDED`
when using video tunneling mode
(
[
#7647
](
https://github.com/google/ExoPlayer/issues/7647
)
).
*
IMA extension: Upgrade to IMA SDK 3.19.4, bringing in a fix for setting the
media load timeout
(
[
#7170
](
https://github.com/google/ExoPlayer/issues/7170
)
).
*
Demo app: Fix playback of ClearKey protected content on API level 26 and
earlier (
[
#7735
](
https://github.com/google/ExoPlayer/issues/7735
)
).
### 2.11.7 (2020-06-29) ###
*
IMA extension: Fix the way postroll "content complete" notifications are
...
...
constants.gradle
View file @
e8221963
...
...
@@ -13,8 +13,8 @@
// limitations under the License.
project
.
ext
{
// ExoPlayer version and version code.
releaseVersion
=
'2.11.
7
'
releaseVersionCode
=
201100
7
releaseVersion
=
'2.11.
8
'
releaseVersionCode
=
201100
8
minSdkVersion
=
16
appTargetSdkVersion
=
29
targetSdkVersion
=
28
// TODO: Bump once b/143232359 is resolved
...
...
demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
View file @
e8221963
...
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.demo;
import
android.content.Intent
;
import
android.content.pm.PackageManager
;
import
android.media.MediaDrm
;
import
android.net.Uri
;
import
android.os.Bundle
;
import
android.util.Pair
;
...
...
@@ -47,6 +46,7 @@ import com.google.android.exoplayer2.drm.ExoMediaCrypto;
import
com.google.android.exoplayer2.drm.FrameworkMediaDrm
;
import
com.google.android.exoplayer2.drm.HttpMediaDrmCallback
;
import
com.google.android.exoplayer2.drm.MediaDrmCallback
;
import
com.google.android.exoplayer2.drm.FrameworkMediaDrm
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException
;
import
com.google.android.exoplayer2.offline.DownloadHelper
;
...
...
@@ -485,7 +485,7 @@ public class PlayerActivity extends AppCompatActivity
drmSessionManager
=
DrmSessionManager
.
getDummyDrmSessionManager
();
}
else
if
(
Util
.
SDK_INT
<
18
)
{
errorStringId
=
R
.
string
.
error_drm_unsupported_before_api_18
;
}
else
if
(!
MediaDrm
.
isCryptoSchemeSupported
(
drmInfo
.
drmScheme
))
{
}
else
if
(!
Framework
MediaDrm
.
isCryptoSchemeSupported
(
drmInfo
.
drmScheme
))
{
errorStringId
=
R
.
string
.
error_drm_unsupported_scheme
;
}
else
{
MediaDrmCallback
mediaDrmCallback
=
...
...
extensions/ima/build.gradle
View file @
e8221963
...
...
@@ -32,7 +32,7 @@ android {
}
dependencies
{
api
'com.google.ads.interactivemedia.v3:interactivemedia:3.19.
0
'
api
'com.google.ads.interactivemedia.v3:interactivemedia:3.19.
4
'
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
'androidx.annotation:annotation:'
+
androidxAnnotationVersion
implementation
'com.google.android.gms:play-services-ads-identifier:17.0.0'
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
e8221963
...
...
@@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public
static
final
String
VERSION
=
"2.11.
7
"
;
public
static
final
String
VERSION
=
"2.11.
8
"
;
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.11.
7
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.11.
8
"
;
/**
* The version of the library expressed as an integer, for example 1002003.
...
...
@@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
int
VERSION_INT
=
201100
7
;
public
static
final
int
VERSION_INT
=
201100
8
;
/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java
View file @
e8221963
...
...
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.audio;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Util
;
import
java.nio.ByteBuffer
;
/**
...
...
@@ -115,9 +116,13 @@ import java.nio.ByteBuffer;
// 32 bit floating point -> 16 bit resampling. Floating point values are in the range
// [-1.0, 1.0], so need to be scaled by Short.MAX_VALUE.
for
(
int
i
=
position
;
i
<
limit
;
i
+=
4
)
{
short
value
=
(
short
)
(
inputBuffer
.
getFloat
(
i
)
*
Short
.
MAX_VALUE
);
buffer
.
put
((
byte
)
(
value
&
0xFF
));
buffer
.
put
((
byte
)
((
value
>>
8
)
&
0xFF
));
// Clamp to avoid integer overflow if the floating point values exceed their nominal range
// [Internal ref: b/161204847].
float
floatValue
=
Util
.
constrainValue
(
inputBuffer
.
getFloat
(
i
),
/* min= */
-
1
,
/* max= */
1
);
short
shortValue
=
(
short
)
(
floatValue
*
Short
.
MAX_VALUE
);
buffer
.
put
((
byte
)
(
shortValue
&
0xFF
));
buffer
.
put
((
byte
)
((
shortValue
>>
8
)
&
0xFF
));
}
break
;
case
C
.
ENCODING_PCM_16BIT
:
...
...
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
View file @
e8221963
...
...
@@ -76,6 +76,15 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
private
int
referenceCount
;
/**
* Returns whether the DRM scheme with the given UUID is supported on this device.
*
* @see MediaDrm#isCryptoSchemeSupported(UUID)
*/
public
static
boolean
isCryptoSchemeSupported
(
UUID
uuid
)
{
return
MediaDrm
.
isCryptoSchemeSupported
(
adjustUuid
(
uuid
));
}
/**
* Creates an instance with an initial reference count of 1. {@link #release()} must be called on
* the instance when it's no longer required.
*
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/flv/ScriptTagPayloadReader.java
View file @
e8221963
...
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.extractor.flv;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.extractor.DummyTrackOutput
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.util.ArrayList
;
...
...
@@ -65,11 +64,11 @@ import java.util.Map;
}
@Override
protected
boolean
parsePayload
(
ParsableByteArray
data
,
long
timeUs
)
throws
ParserException
{
protected
boolean
parsePayload
(
ParsableByteArray
data
,
long
timeUs
)
{
int
nameType
=
readAmfType
(
data
);
if
(
nameType
!=
AMF_TYPE_STRING
)
{
//
Should never happen
.
throw
new
ParserException
()
;
//
Ignore segments with unexpected name type
.
return
false
;
}
String
name
=
readAmfString
(
data
);
if
(!
NAME_METADATA
.
equals
(
name
))
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
View file @
e8221963
...
...
@@ -735,12 +735,7 @@ public class FragmentedMp4Extractor implements Extractor {
parseSenc
(
senc
.
data
,
fragment
);
}
LeafAtom
sbgp
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_sbgp
);
LeafAtom
sgpd
=
traf
.
getLeafAtomOfType
(
Atom
.
TYPE_sgpd
);
if
(
sbgp
!=
null
&&
sgpd
!=
null
)
{
parseSgpd
(
sbgp
.
data
,
sgpd
.
data
,
encryptionBox
!=
null
?
encryptionBox
.
schemeType
:
null
,
fragment
);
}
parseSampleGroups
(
traf
,
encryptionBox
!=
null
?
encryptionBox
.
schemeType
:
null
,
fragment
);
int
leafChildrenSize
=
traf
.
leafChildren
.
size
();
for
(
int
i
=
0
;
i
<
leafChildrenSize
;
i
++)
{
...
...
@@ -798,8 +793,12 @@ public class FragmentedMp4Extractor implements Extractor {
int
defaultSampleInfoSize
=
saiz
.
readUnsignedByte
();
int
sampleCount
=
saiz
.
readUnsignedIntToInt
();
if
(
sampleCount
!=
out
.
sampleCount
)
{
throw
new
ParserException
(
"Length mismatch: "
+
sampleCount
+
", "
+
out
.
sampleCount
);
if
(
sampleCount
>
out
.
sampleCount
)
{
throw
new
ParserException
(
"Saiz sample count "
+
sampleCount
+
" is greater than fragment sample count"
+
out
.
sampleCount
);
}
int
totalSize
=
0
;
...
...
@@ -815,7 +814,10 @@ public class FragmentedMp4Extractor implements Extractor {
totalSize
+=
defaultSampleInfoSize
*
sampleCount
;
Arrays
.
fill
(
out
.
sampleHasSubsampleEncryptionTable
,
0
,
sampleCount
,
subsampleEncryption
);
}
out
.
initEncryptionData
(
totalSize
);
Arrays
.
fill
(
out
.
sampleHasSubsampleEncryptionTable
,
sampleCount
,
out
.
sampleCount
,
false
);
if
(
totalSize
>
0
)
{
out
.
initEncryptionData
(
totalSize
);
}
}
/**
...
...
@@ -990,8 +992,10 @@ public class FragmentedMp4Extractor implements Extractor {
checkNonNegative
(
sampleDurationsPresent
?
trun
.
readInt
()
:
defaultSampleValues
.
duration
);
int
sampleSize
=
checkNonNegative
(
sampleSizesPresent
?
trun
.
readInt
()
:
defaultSampleValues
.
size
);
int
sampleFlags
=
(
i
==
0
&&
firstSampleFlagsPresent
)
?
firstSampleFlags
:
sampleFlagsPresent
?
trun
.
readInt
()
:
defaultSampleValues
.
flags
;
int
sampleFlags
=
sampleFlagsPresent
?
trun
.
readInt
()
:
(
i
==
0
&&
firstSampleFlagsPresent
)
?
firstSampleFlags
:
defaultSampleValues
.
flags
;
if
(
sampleCompositionTimeOffsetsPresent
)
{
// The BMFF spec (ISO 14496-12) states that sample offsets should be unsigned integers in
// version 0 trun boxes, however a significant number of streams violate the spec and use
...
...
@@ -1055,8 +1059,16 @@ public class FragmentedMp4Extractor implements Extractor {
boolean
subsampleEncryption
=
(
flags
&
0x02
/* use_subsample_encryption */
)
!=
0
;
int
sampleCount
=
senc
.
readUnsignedIntToInt
();
if
(
sampleCount
!=
out
.
sampleCount
)
{
throw
new
ParserException
(
"Length mismatch: "
+
sampleCount
+
", "
+
out
.
sampleCount
);
if
(
sampleCount
==
0
)
{
// Samples are unencrypted.
Arrays
.
fill
(
out
.
sampleHasSubsampleEncryptionTable
,
0
,
out
.
sampleCount
,
false
);
return
;
}
else
if
(
sampleCount
!=
out
.
sampleCount
)
{
throw
new
ParserException
(
"Senc sample count "
+
sampleCount
+
" is different from fragment sample count"
+
out
.
sampleCount
);
}
Arrays
.
fill
(
out
.
sampleHasSubsampleEncryptionTable
,
0
,
sampleCount
,
subsampleEncryption
);
...
...
@@ -1064,28 +1076,43 @@ public class FragmentedMp4Extractor implements Extractor {
out
.
fillEncryptionData
(
senc
);
}
private
static
void
parseSgpd
(
ParsableByteArray
sbgp
,
ParsableByteArray
sgpd
,
String
schemeType
,
TrackFragment
out
)
throws
ParserException
{
sbgp
.
setPosition
(
Atom
.
HEADER_SIZE
);
int
sbgpFullAtom
=
sbgp
.
readInt
();
if
(
sbgp
.
readInt
()
!=
SAMPLE_GROUP_TYPE_seig
)
{
// Only seig grouping type is supported.
private
static
void
parseSampleGroups
(
ContainerAtom
traf
,
@Nullable
String
schemeType
,
TrackFragment
out
)
throws
ParserException
{
// Find sbgp and sgpd boxes with grouping_type == seig.
@Nullable
ParsableByteArray
sbgp
=
null
;
@Nullable
ParsableByteArray
sgpd
=
null
;
for
(
int
i
=
0
;
i
<
traf
.
leafChildren
.
size
();
i
++)
{
LeafAtom
leafAtom
=
traf
.
leafChildren
.
get
(
i
);
ParsableByteArray
leafAtomData
=
leafAtom
.
data
;
if
(
leafAtom
.
type
==
Atom
.
TYPE_sbgp
)
{
leafAtomData
.
setPosition
(
Atom
.
FULL_HEADER_SIZE
);
if
(
leafAtomData
.
readInt
()
==
SAMPLE_GROUP_TYPE_seig
)
{
sbgp
=
leafAtomData
;
}
}
else
if
(
leafAtom
.
type
==
Atom
.
TYPE_sgpd
)
{
leafAtomData
.
setPosition
(
Atom
.
FULL_HEADER_SIZE
);
if
(
leafAtomData
.
readInt
()
==
SAMPLE_GROUP_TYPE_seig
)
{
sgpd
=
leafAtomData
;
}
}
}
if
(
sbgp
==
null
||
sgpd
==
null
)
{
return
;
}
if
(
Atom
.
parseFullAtomVersion
(
sbgpFullAtom
)
==
1
)
{
sbgp
.
skipBytes
(
4
);
// default_length.
sbgp
.
setPosition
(
Atom
.
HEADER_SIZE
);
int
sbgpVersion
=
Atom
.
parseFullAtomVersion
(
sbgp
.
readInt
());
sbgp
.
skipBytes
(
4
);
// grouping_type == seig.
if
(
sbgpVersion
==
1
)
{
sbgp
.
skipBytes
(
4
);
// grouping_type_parameter.
}
if
(
sbgp
.
readInt
()
!=
1
)
{
// entry_count.
throw
new
ParserException
(
"Entry count in sbgp != 1 (unsupported)."
);
}
sgpd
.
setPosition
(
Atom
.
HEADER_SIZE
);
int
sgpdFullAtom
=
sgpd
.
readInt
();
if
(
sgpd
.
readInt
()
!=
SAMPLE_GROUP_TYPE_seig
)
{
// Only seig grouping type is supported.
return
;
}
int
sgpdVersion
=
Atom
.
parseFullAtomVersion
(
sgpdFullAtom
);
int
sgpdVersion
=
Atom
.
parseFullAtomVersion
(
sgpd
.
readInt
());
sgpd
.
skipBytes
(
4
);
// grouping_type == seig.
if
(
sgpdVersion
==
1
)
{
if
(
sgpd
.
readUnsignedInt
()
==
0
)
{
throw
new
ParserException
(
"Variable length description in sgpd found (unsupported)"
);
...
...
@@ -1096,6 +1123,7 @@ public class FragmentedMp4Extractor implements Extractor {
if
(
sgpd
.
readUnsignedInt
()
!=
1
)
{
// entry_count.
throw
new
ParserException
(
"Entry count in sgpd != 1 (unsupported)."
);
}
// CencSampleEncryptionInformationGroupEntry
sgpd
.
skipBytes
(
1
);
// reserved = 0.
int
patternByte
=
sgpd
.
readUnsignedByte
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java
View file @
e8221963
...
...
@@ -57,6 +57,8 @@ import java.io.IOException;
0x71742020
,
// qt[space][space], Apple QuickTime
0x4d534e56
,
// MSNV, Sony PSP
0x64627931
,
// dby1, Dolby Vision
0x69736d6c
,
// isml
0x70696666
,
// piff
};
/**
...
...
@@ -101,7 +103,12 @@ import java.io.IOException;
// Read an atom header.
int
headerSize
=
Atom
.
HEADER_SIZE
;
buffer
.
reset
(
headerSize
);
input
.
peekFully
(
buffer
.
data
,
0
,
headerSize
);
boolean
success
=
input
.
peekFully
(
buffer
.
data
,
0
,
headerSize
,
/* allowEndOfInput= */
true
);
if
(!
success
)
{
// We've reached the end of the file.
break
;
}
long
atomSize
=
buffer
.
readUnsignedInt
();
int
atomType
=
buffer
.
readInt
();
if
(
atomSize
==
Atom
.
DEFINES_LARGE_SIZE
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
View file @
e8221963
...
...
@@ -657,6 +657,10 @@ public final class TsExtractor implements Extractor {
int
descriptorTag
=
data
.
readUnsignedByte
();
int
descriptorLength
=
data
.
readUnsignedByte
();
int
positionOfNextDescriptor
=
data
.
getPosition
()
+
descriptorLength
;
if
(
positionOfNextDescriptor
>
descriptorsEndPosition
)
{
// Descriptor claims to extend past the end position. Skip it.
break
;
}
if
(
descriptorTag
==
TS_PMT_DESC_REGISTRATION
)
{
// registration_descriptor
long
formatIdentifier
=
data
.
readUnsignedInt
();
if
(
formatIdentifier
==
AC3_FORMAT_IDENTIFIER
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
View file @
e8221963
...
...
@@ -1937,6 +1937,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
String
name
=
codecInfo
.
name
;
return
(
Util
.
SDK_INT
<=
25
&&
"OMX.rk.video_decoder.avc"
.
equals
(
name
))
||
(
Util
.
SDK_INT
<=
17
&&
"OMX.allwinner.video.decoder.avc"
.
equals
(
name
))
||
(
Util
.
SDK_INT
<=
29
&&
(
"OMX.broadcom.video_decoder.tunnel"
.
equals
(
name
)
||
"OMX.broadcom.video_decoder.tunnel.secure"
.
equals
(
name
)))
||
(
"Amazon"
.
equals
(
Util
.
MANUFACTURER
)
&&
"AFTS"
.
equals
(
Util
.
MODEL
)
&&
codecInfo
.
secure
);
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaFormatUtil.java
View file @
e8221963
...
...
@@ -83,7 +83,7 @@ public final class MediaFormatUtil {
*
* @param format The {@link MediaFormat} being configured.
* @param key The key to set.
* @param value The
{@link byte[]}
that will be wrapped to obtain the value.
* @param value The
byte array
that will be wrapped to obtain the value.
*/
public
static
void
maybeSetByteBuffer
(
MediaFormat
format
,
String
key
,
@Nullable
byte
[]
value
)
{
if
(
value
!=
null
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/ConditionVariable.java
View file @
e8221963
...
...
@@ -40,7 +40,7 @@ public final class ConditionVariable {
}
/**
* Creates an instance.
* Creates an instance
, which starts closed
.
*
* @param clock The {@link Clock} whose {@link Clock#elapsedRealtime()} method is used to
* determine when {@link #block(long)} should time out.
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/Util.java
View file @
e8221963
...
...
@@ -135,6 +135,11 @@ public final class Util {
+
"(T(([0-9]*)H)?(([0-9]*)M)?(([0-9.]*)S)?)?$"
);
private
static
final
Pattern
ESCAPED_CHARACTER_PATTERN
=
Pattern
.
compile
(
"%([A-Fa-f0-9]{2})"
);
// https://docs.microsoft.com/en-us/azure/media-services/previous/media-services-deliver-content-overview#URLs.
private
static
final
Pattern
ISM_URL_PATTERN
=
Pattern
.
compile
(
".*\\.isml?(?:/(manifest(.*))?)?"
);
private
static
final
String
ISM_HLS_FORMAT_EXTENSION
=
"format=m3u8-aapl"
;
private
static
final
String
ISM_DASH_FORMAT_EXTENSION
=
"format=mpd-time-csf"
;
// Replacement map of ISO language codes used for normalization.
@Nullable
private
static
HashMap
<
String
,
String
>
languageTagReplacementMap
;
...
...
@@ -1599,11 +1604,41 @@ public final class Util {
return
C
.
TYPE_DASH
;
}
else
if
(
fileName
.
endsWith
(
".m3u8"
))
{
return
C
.
TYPE_HLS
;
}
else
if
(
fileName
.
matches
(
".*\\.ism(l)?(/manifest(\\(.+\\))?)?"
))
{
}
Matcher
ismMatcher
=
ISM_URL_PATTERN
.
matcher
(
fileName
);
if
(
ismMatcher
.
matches
())
{
@Nullable
String
extensions
=
ismMatcher
.
group
(
2
);
if
(
extensions
!=
null
)
{
if
(
extensions
.
contains
(
ISM_DASH_FORMAT_EXTENSION
))
{
return
C
.
TYPE_DASH
;
}
else
if
(
extensions
.
contains
(
ISM_HLS_FORMAT_EXTENSION
))
{
return
C
.
TYPE_HLS
;
}
}
return
C
.
TYPE_SS
;
}
else
{
return
C
.
TYPE_OTHER
;
}
return
C
.
TYPE_OTHER
;
}
/**
* If the provided URI is an ISM Presentation URI, returns the URI with "Manifest" appended to its
* path (i.e., the corresponding default manifest URI). Else returns the provided URI without
* modification. See [MS-SSTR] v20180912, section 2.2.1.
*
* @param uri The original URI.
* @return The fixed URI.
*/
public
static
Uri
fixSmoothStreamingIsmManifestUri
(
Uri
uri
)
{
@Nullable
String
path
=
toLowerInvariant
(
uri
.
getPath
());
if
(
path
==
null
)
{
return
uri
;
}
Matcher
ismMatcher
=
ISM_URL_PATTERN
.
matcher
(
path
);
if
(
ismMatcher
.
matches
()
&&
ismMatcher
.
group
(
1
)
==
null
)
{
// Add missing "Manifest" suffix.
return
Uri
.
withAppendedPath
(
uri
,
"Manifest"
);
}
return
uri
;
}
/**
...
...
library/core/src/test/java/com/google/android/exoplayer2/util/UtilTest.java
View file @
e8221963
...
...
@@ -24,6 +24,7 @@ import static com.google.android.exoplayer2.util.Util.parseXsDuration;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Util
.
unescapeFileName
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.net.Uri
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
...
...
@@ -77,15 +78,77 @@ public class UtilTest {
}
@Test
public
void
testInferContentType
()
{
public
void
inferContentType_handlesHlsIsmUris
()
{
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest(format=m3u8-aapl)"
))
.
isEqualTo
(
C
.
TYPE_HLS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest(format=m3u8-aapl,quality=hd)"
))
.
isEqualTo
(
C
.
TYPE_HLS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest(quality=hd,format=m3u8-aapl)"
))
.
isEqualTo
(
C
.
TYPE_HLS
);
}
@Test
public
void
inferContentType_handlesHlsIsmV3Uris
()
{
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest(format=m3u8-aapl-v3)"
))
.
isEqualTo
(
C
.
TYPE_HLS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest(format=m3u8-aapl-v3,quality=hd)"
))
.
isEqualTo
(
C
.
TYPE_HLS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest(quality=hd,format=m3u8-aapl-v3)"
))
.
isEqualTo
(
C
.
TYPE_HLS
);
}
@Test
public
void
inferContentType_handlesDashIsmUris
()
{
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/manifest(format=mpd-time-csf)"
))
.
isEqualTo
(
C
.
TYPE_DASH
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/manifest(format=mpd-time-csf,quality=hd)"
))
.
isEqualTo
(
C
.
TYPE_DASH
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/manifest(quality=hd,format=mpd-time-csf)"
))
.
isEqualTo
(
C
.
TYPE_DASH
);
}
@Test
public
void
inferContentType_handlesSmoothStreamingIsmUris
()
{
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/Manifest"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/manifest"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/manifest(filter=x)"
)).
isEqualTo
(
C
.
TYPE_SS
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.isml/manifest_hd"
)).
isEqualTo
(
C
.
TYPE_SS
);
}
@Test
public
void
inferContentType_handlesOtherIsmUris
()
{
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/video.mp4"
)).
isEqualTo
(
C
.
TYPE_OTHER
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/prefix-manifest"
)).
isEqualTo
(
C
.
TYPE_OTHER
);
assertThat
(
Util
.
inferContentType
(
"http://a.b/c.ism/manifest-suffix"
)).
isEqualTo
(
C
.
TYPE_OTHER
);
}
@Test
public
void
fixSmoothStreamingIsmManifestUri_addsManifestSuffix
()
{
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.ism"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest"
));
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.isml"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.isml/Manifest"
));
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.ism/"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest"
));
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.isml/"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.isml/Manifest"
));
}
@Test
public
void
fixSmoothStreamingIsmManifestUri_doesNotAlterManifestUri
()
{
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest"
));
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.isml/Manifest"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.isml/Manifest"
));
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest(filter=x)"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest(filter=x)"
));
assertThat
(
Util
.
fixSmoothStreamingIsmManifestUri
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest_hd"
)))
.
isEqualTo
(
Uri
.
parse
(
"http://a.b/c.ism/Manifest_hd"
));
}
@Test
...
...
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java
View file @
e8221963
...
...
@@ -39,7 +39,6 @@ import com.google.android.exoplayer2.source.SinglePeriodTimeline;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest
;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement
;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser
;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil
;
import
com.google.android.exoplayer2.upstream.Allocator
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy
;
...
...
@@ -50,6 +49,7 @@ import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.upstream.TransferListener
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -531,7 +531,7 @@ public final class SsMediaSource extends BaseMediaSource
@Nullable
Object
tag
)
{
Assertions
.
checkState
(
manifest
==
null
||
!
manifest
.
isLive
);
this
.
manifest
=
manifest
;
this
.
manifestUri
=
manifestUri
==
null
?
null
:
SsUtil
.
fix
ManifestUri
(
manifestUri
);
this
.
manifestUri
=
manifestUri
==
null
?
null
:
Util
.
fixSmoothStreamingIsm
ManifestUri
(
manifestUri
);
this
.
manifestDataSourceFactory
=
manifestDataSourceFactory
;
this
.
manifestParser
=
manifestParser
;
this
.
chunkSourceFactory
=
chunkSourceFactory
;
...
...
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsUtil.java
deleted
100644 → 0
View file @
5bfad37c
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
smoothstreaming
.
manifest
;
import
android.net.Uri
;
import
com.google.android.exoplayer2.util.Util
;
/** SmoothStreaming related utility methods. */
public
final
class
SsUtil
{
/** Returns a fixed SmoothStreaming client manifest {@link Uri}. */
public
static
Uri
fixManifestUri
(
Uri
manifestUri
)
{
String
lastPathSegment
=
manifestUri
.
getLastPathSegment
();
if
(
lastPathSegment
!=
null
&&
Util
.
toLowerInvariant
(
lastPathSegment
).
matches
(
"manifest(\\(.+\\))?"
))
{
return
manifestUri
;
}
return
Uri
.
withAppendedPath
(
manifestUri
,
"Manifest"
);
}
private
SsUtil
()
{}
}
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java
View file @
e8221963
...
...
@@ -23,10 +23,10 @@ import com.google.android.exoplayer2.offline.StreamKey;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest
;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement
;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser
;
import
com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -64,7 +64,7 @@ public final class SsDownloader extends SegmentDownloader<SsManifest> {
*/
public
SsDownloader
(
Uri
manifestUri
,
List
<
StreamKey
>
streamKeys
,
DownloaderConstructorHelper
constructorHelper
)
{
super
(
SsUtil
.
fix
ManifestUri
(
manifestUri
),
streamKeys
,
constructorHelper
);
super
(
Util
.
fixSmoothStreamingIsm
ManifestUri
(
manifestUri
),
streamKeys
,
constructorHelper
);
}
@Override
...
...
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