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
41b3fc11
authored
Oct 18, 2019
by
Oliver Woodman
Committed by
GitHub
Oct 18, 2019
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #6542 from google/dev-v2-r2.10.6
r2.10.6
parents
176d211b
2671ff0c
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
62 changed files
with
765 additions
and
294 deletions
.gitignore
.hgignore
README.md
RELEASENOTES.md
build.gradle
constants.gradle
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
extensions/ffmpeg/README.md
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java
extensions/flac/src/main/jni/flac_jni.cc
extensions/flac/src/main/jni/flac_parser.cc
extensions/flac/src/main/jni/include/flac_parser.h
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java
gradle/wrapper/gradle-wrapper.properties
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/Format.java
library/core/src/main/java/com/google/android/exoplayer2/Player.java
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/MlltSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Seeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSourceFactory.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/ResolvingDataSource.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java
library/core/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java
library/core/src/main/java/com/google/android/exoplayer2/util/GlUtil.java
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyStreamInfoTest.java → library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyInfoTest.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
library/dash/src/test/assets/sample_mpd_1 → library/dash/src/test/assets/sample_mpd
library/dash/src/test/assets/sample_mpd_4_event_stream → library/dash/src/test/assets/sample_mpd_event_stream
library/dash/src/test/assets/sample_mpd_labels
library/dash/src/test/assets/sample_mpd_3_segment_template → library/dash/src/test/assets/sample_mpd_segment_template
library/dash/src/test/assets/sample_mpd_2_unknown_mime_type → library/dash/src/test/assets/sample_mpd_unknown_mime_type
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMetadataType.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java
.gitignore
View file @
41b3fc11
...
@@ -71,7 +71,3 @@ extensions/cronet/jniLibs/*
...
@@ -71,7 +71,3 @@ extensions/cronet/jniLibs/*
!extensions/cronet/jniLibs/README.md
!extensions/cronet/jniLibs/README.md
extensions/cronet/libs/*
extensions/cronet/libs/*
!extensions/cronet/libs/README.md
!extensions/cronet/libs/README.md
# Cast receiver
cast_receiver_app/external-js
cast_receiver_app/bazel-cast_receiver_app
.hgignore
View file @
41b3fc11
...
@@ -12,13 +12,14 @@ libs
...
@@ -12,13 +12,14 @@ libs
obj
obj
lint.xml
lint.xml
# IntelliJ IDEA
# IntelliJ IDEA
& Android Studio
.idea
.idea
*.iml
*.iml
*.ipr
*.ipr
*.iws
*.iws
classes
classes
gen-external-apklibs
gen-external-apklibs
*.li
# Eclipse
# Eclipse
.project
.project
...
@@ -75,7 +76,3 @@ extensions/cronet/jniLibs/*
...
@@ -75,7 +76,3 @@ extensions/cronet/jniLibs/*
!extensions/cronet/jniLibs/README.md
!extensions/cronet/jniLibs/README.md
extensions/cronet/libs/*
extensions/cronet/libs/*
!extensions/cronet/libs/README.md
!extensions/cronet/libs/README.md
# Cast receiver
cast_receiver_app/external-js
cast_receiver_app/bazel-cast_receiver_app
README.md
View file @
41b3fc11
...
@@ -107,6 +107,7 @@ branch:
...
@@ -107,6 +107,7 @@ branch:
```
sh
```
sh
git clone https://github.com/google/ExoPlayer.git
git clone https://github.com/google/ExoPlayer.git
cd
ExoPlayer
git checkout release-v2
git checkout release-v2
```
```
...
...
RELEASENOTES.md
View file @
41b3fc11
# Release notes #
# Release notes #
### 2.10.6 (2019-10-18) ###
*
Add
`Player.onPlaybackSuppressionReasonChanged`
to allow listeners to
detect playbacks suppressions (e.g. transient audio focus loss) directly
(
[
#6203
](
https://github.com/google/ExoPlayer/issues/6203
)
).
*
DASH:
*
Support
`Label`
elements
(
[
#6297
](
https://github.com/google/ExoPlayer/issues/6297
)
).
*
Support legacy audio channel configuration
(
[
#6523
](
https://github.com/google/ExoPlayer/issues/6523
)
).
*
HLS: Add support for ID3 in EMSG when using FMP4 streams
(
[
spec
](
https://aomediacodec.github.io/av1-id3/
)
).
*
MP3: Add workaround to avoid prematurely ending playback of some SHOUTcast
live streams (
[
#6537
](
https://github.com/google/ExoPlayer/issues/6537
)
,
[
#6315
](
https://github.com/google/ExoPlayer/issues/6315
)
and
[
#5658
](
https://github.com/google/ExoPlayer/issues/5658
)
).
*
Metadata: Expose the raw ICY metadata through
`IcyInfo`
(
[
#6476
](
https://github.com/google/ExoPlayer/issues/6476
)
).
*
UI:
*
Setting
`app:played_color`
on
`PlayerView`
and
`PlayerControlView`
no longer
adjusts the colors of the scrubber handle , buffered and unplayed parts of
the time bar. These can be set separately using
`app:scrubber_color`
,
`app:buffered_color`
and
`app_unplayed_color`
respectively.
*
Setting
`app:ad_marker_color`
on
`PlayerView`
and
`PlayerControlView`
no
longer adjusts the color of played ad markers. The color of played ad
markers can be set separately using
`app:played_ad_marker_color`
.
### 2.10.5 (2019-09-20) ###
### 2.10.5 (2019-09-20) ###
*
Add
`Player.isPlaying`
and
`EventListener.onIsPlayingChanged`
to check whether
*
Add
`Player.isPlaying`
and
`EventListener.onIsPlayingChanged`
to check whether
...
...
build.gradle
View file @
41b3fc11
...
@@ -17,9 +17,9 @@ buildscript {
...
@@ -17,9 +17,9 @@ buildscript {
jcenter
()
jcenter
()
}
}
dependencies
{
dependencies
{
classpath
'com.android.tools.build:gradle:3.
4.0
'
classpath
'com.android.tools.build:gradle:3.
5.1
'
classpath
'com.novoda:bintray-release:0.9'
classpath
'com.novoda:bintray-release:0.9
.1
'
classpath
'com.google.android.gms:strict-version-matcher-plugin:1.
1
.0'
classpath
'com.google.android.gms:strict-version-matcher-plugin:1.
2
.0'
}
}
}
}
allprojects
{
allprojects
{
...
...
constants.gradle
View file @
41b3fc11
...
@@ -13,8 +13,8 @@
...
@@ -13,8 +13,8 @@
// limitations under the License.
// limitations under the License.
project
.
ext
{
project
.
ext
{
// ExoPlayer version and version code.
// ExoPlayer version and version code.
releaseVersion
=
'2.10.
5
'
releaseVersion
=
'2.10.
6
'
releaseVersionCode
=
201000
5
releaseVersionCode
=
201000
6
minSdkVersion
=
16
minSdkVersion
=
16
targetSdkVersion
=
28
targetSdkVersion
=
28
compileSdkVersion
=
28
compileSdkVersion
=
28
...
...
extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java
View file @
41b3fc11
...
@@ -21,6 +21,7 @@ import androidx.annotation.Nullable;
...
@@ -21,6 +21,7 @@ import androidx.annotation.Nullable;
import
com.google.android.exoplayer2.BasePlayer
;
import
com.google.android.exoplayer2.BasePlayer
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlaybackException
;
import
com.google.android.exoplayer2.ExoPlaybackException
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.Timeline
;
...
@@ -67,6 +68,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
...
@@ -67,6 +68,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
*/
public
final
class
CastPlayer
extends
BasePlayer
{
public
final
class
CastPlayer
extends
BasePlayer
{
static
{
ExoPlayerLibraryInfo
.
registerModule
(
"goog.exo.cast"
);
}
private
static
final
String
TAG
=
"CastPlayer"
;
private
static
final
String
TAG
=
"CastPlayer"
;
private
static
final
int
RENDERER_COUNT
=
3
;
private
static
final
int
RENDERER_COUNT
=
3
;
...
...
extensions/ffmpeg/README.md
View file @
41b3fc11
...
@@ -25,8 +25,7 @@ follows:
...
@@ -25,8 +25,7 @@ follows:
```
```
cd "<path to exoplayer checkout>"
cd "<path to exoplayer checkout>"
EXOPLAYER_ROOT="$(pwd)"
FFMPEG_EXT_PATH="$(pwd)/extensions/ffmpeg/src/main/jni"
FFMPEG_EXT_PATH="${EXOPLAYER_ROOT}/extensions/ffmpeg/src/main"
```
```
*
Download the
[
Android NDK
][]
and set its location in an environment variable.
*
Download the
[
Android NDK
][]
and set its location in an environment variable.
...
@@ -69,7 +68,7 @@ COMMON_OPTIONS="\
...
@@ -69,7 +68,7 @@ COMMON_OPTIONS="\
--enable-decoder=opus \
--enable-decoder=opus \
--enable-decoder=flac \
--enable-decoder=flac \
" && \
" && \
cd "${FFMPEG_EXT_PATH}
/jni
" && \
cd "${FFMPEG_EXT_PATH}" && \
(git -C ffmpeg pull || git clone git://source.ffmpeg.org/ffmpeg ffmpeg) && \
(git -C ffmpeg pull || git clone git://source.ffmpeg.org/ffmpeg ffmpeg) && \
cd ffmpeg && git checkout release/4.0 && \
cd ffmpeg && git checkout release/4.0 && \
./configure \
./configure \
...
@@ -112,7 +111,7 @@ make clean
...
@@ -112,7 +111,7 @@ make clean
built in the previous step. For example:
built in the previous step. For example:
```
```
cd "${FFMPEG_EXT_PATH}"
/jni
&& \
cd "${FFMPEG_EXT_PATH}" && \
${NDK_PATH}/ndk-build APP_ABI="armeabi-v7a arm64-v8a x86" -j4
${NDK_PATH}/ndk-build APP_ABI="armeabi-v7a arm64-v8a x86" -j4
```
```
...
...
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java
View file @
41b3fc11
...
@@ -19,6 +19,8 @@ import androidx.annotation.Nullable;
...
@@ -19,6 +19,8 @@ import androidx.annotation.Nullable;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.ParserException
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.SeekPoint
;
import
com.google.android.exoplayer2.util.FlacStreamMetadata
;
import
com.google.android.exoplayer2.util.FlacStreamMetadata
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
...
@@ -216,15 +218,25 @@ import java.nio.ByteBuffer;
...
@@ -216,15 +218,25 @@ import java.nio.ByteBuffer;
}
}
/**
/**
* Maps a seek position in microseconds to
a corresponding position (byte offset) in the flac
* Maps a seek position in microseconds to
the corresponding {@link SeekMap.SeekPoints} in the
* stream.
* stream.
*
*
* @param timeUs A seek position in microseconds.
* @param timeUs A seek position in microseconds.
* @return The corresponding
position (byte offset) in the flac stream or -1 if the stream doesn't
* @return The corresponding
{@link SeekMap.SeekPoints} obtained from the seek table, or {@code
* have a seek table.
*
null} if the stream doesn't
have a seek table.
*/
*/
public
long
getSeekPosition
(
long
timeUs
)
{
@Nullable
return
flacGetSeekPosition
(
nativeDecoderContext
,
timeUs
);
public
SeekMap
.
SeekPoints
getSeekPoints
(
long
timeUs
)
{
long
[]
seekPoints
=
new
long
[
4
];
if
(!
flacGetSeekPoints
(
nativeDecoderContext
,
timeUs
,
seekPoints
))
{
return
null
;
}
SeekPoint
firstSeekPoint
=
new
SeekPoint
(
seekPoints
[
0
],
seekPoints
[
1
]);
SeekPoint
secondSeekPoint
=
seekPoints
[
2
]
==
seekPoints
[
0
]
?
firstSeekPoint
:
new
SeekPoint
(
seekPoints
[
2
],
seekPoints
[
3
]);
return
new
SeekMap
.
SeekPoints
(
firstSeekPoint
,
secondSeekPoint
);
}
}
public
String
getStateString
()
{
public
String
getStateString
()
{
...
@@ -283,7 +295,7 @@ import java.nio.ByteBuffer;
...
@@ -283,7 +295,7 @@ import java.nio.ByteBuffer;
private
native
long
flacGetNextFrameFirstSampleIndex
(
long
context
);
private
native
long
flacGetNextFrameFirstSampleIndex
(
long
context
);
private
native
long
flacGetSeekPosition
(
long
context
,
long
timeU
s
);
private
native
boolean
flacGetSeekPoints
(
long
context
,
long
timeUs
,
long
[]
outSeekPoint
s
);
private
native
String
flacGetStateString
(
long
context
);
private
native
String
flacGetStateString
(
long
context
);
...
...
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacExtractor.java
View file @
41b3fc11
...
@@ -276,10 +276,10 @@ public final class FlacExtractor implements Extractor {
...
@@ -276,10 +276,10 @@ public final class FlacExtractor implements Extractor {
FlacStreamMetadata
streamMetadata
,
FlacStreamMetadata
streamMetadata
,
long
streamLength
,
long
streamLength
,
ExtractorOutput
output
)
{
ExtractorOutput
output
)
{
boolean
ha
sSeekTable
=
decoderJni
.
getSeekPosition
(
/* timeUs= */
0
)
!=
-
1
;
boolean
ha
veSeekTable
=
decoderJni
.
getSeekPoints
(
/* timeUs= */
0
)
!=
null
;
FlacBinarySearchSeeker
binarySearchSeeker
=
null
;
FlacBinarySearchSeeker
binarySearchSeeker
=
null
;
SeekMap
seekMap
;
SeekMap
seekMap
;
if
(
ha
s
SeekTable
)
{
if
(
ha
ve
SeekTable
)
{
seekMap
=
new
FlacSeekMap
(
streamMetadata
.
durationUs
(),
decoderJni
);
seekMap
=
new
FlacSeekMap
(
streamMetadata
.
durationUs
(),
decoderJni
);
}
else
if
(
streamLength
!=
C
.
LENGTH_UNSET
)
{
}
else
if
(
streamLength
!=
C
.
LENGTH_UNSET
)
{
long
firstFramePosition
=
decoderJni
.
getDecodePosition
();
long
firstFramePosition
=
decoderJni
.
getDecodePosition
();
...
@@ -341,8 +341,8 @@ public final class FlacExtractor implements Extractor {
...
@@ -341,8 +341,8 @@ public final class FlacExtractor implements Extractor {
@Override
@Override
public
SeekPoints
getSeekPoints
(
long
timeUs
)
{
public
SeekPoints
getSeekPoints
(
long
timeUs
)
{
// TODO: Access the seek table via JNI to return two seek points when appropriate.
@Nullable
SeekPoints
seekPoints
=
decoderJni
.
getSeekPoints
(
timeUs
);
return
new
SeekPoints
(
new
SeekPoint
(
timeUs
,
decoderJni
.
getSeekPosition
(
timeUs
)))
;
return
seekPoints
==
null
?
new
SeekPoints
(
SeekPoint
.
START
)
:
seekPoints
;
}
}
@Override
@Override
...
...
extensions/flac/src/main/jni/flac_jni.cc
View file @
41b3fc11
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
#include <android/log.h>
#include <android/log.h>
#include <jni.h>
#include <jni.h>
#include <array>
#include <cstdlib>
#include <cstdlib>
#include <cstring>
#include <cstring>
...
@@ -46,7 +47,6 @@ class JavaDataSource : public DataSource {
...
@@ -46,7 +47,6 @@ class JavaDataSource : public DataSource {
if
(
mid
==
NULL
)
{
if
(
mid
==
NULL
)
{
jclass
cls
=
env
->
GetObjectClass
(
flacDecoderJni
);
jclass
cls
=
env
->
GetObjectClass
(
flacDecoderJni
);
mid
=
env
->
GetMethodID
(
cls
,
"read"
,
"(Ljava/nio/ByteBuffer;)I"
);
mid
=
env
->
GetMethodID
(
cls
,
"read"
,
"(Ljava/nio/ByteBuffer;)I"
);
env
->
DeleteLocalRef
(
cls
);
}
}
}
}
...
@@ -57,7 +57,6 @@ class JavaDataSource : public DataSource {
...
@@ -57,7 +57,6 @@ class JavaDataSource : public DataSource {
// Exception is thrown in Java when returning from the native call.
// Exception is thrown in Java when returning from the native call.
result
=
-
1
;
result
=
-
1
;
}
}
env
->
DeleteLocalRef
(
byteBuffer
);
return
result
;
return
result
;
}
}
...
@@ -200,9 +199,15 @@ DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) {
...
@@ -200,9 +199,15 @@ DECODER_FUNC(jlong, flacGetNextFrameFirstSampleIndex, jlong jContext) {
return
context
->
parser
->
getNextFrameFirstSampleIndex
();
return
context
->
parser
->
getNextFrameFirstSampleIndex
();
}
}
DECODER_FUNC
(
jlong
,
flacGetSeekPosition
,
jlong
jContext
,
jlong
timeUs
)
{
DECODER_FUNC
(
jboolean
,
flacGetSeekPoints
,
jlong
jContext
,
jlong
timeUs
,
jlongArray
outSeekPoints
)
{
Context
*
context
=
reinterpret_cast
<
Context
*>
(
jContext
);
Context
*
context
=
reinterpret_cast
<
Context
*>
(
jContext
);
return
context
->
parser
->
getSeekPosition
(
timeUs
);
std
::
array
<
int64_t
,
4
>
result
;
bool
success
=
context
->
parser
->
getSeekPositions
(
timeUs
,
result
);
if
(
success
)
{
env
->
SetLongArrayRegion
(
outSeekPoints
,
0
,
result
.
size
(),
result
.
data
());
}
return
success
;
}
}
DECODER_FUNC
(
jstring
,
flacGetStateString
,
jlong
jContext
)
{
DECODER_FUNC
(
jstring
,
flacGetStateString
,
jlong
jContext
)
{
...
...
extensions/flac/src/main/jni/flac_parser.cc
View file @
41b3fc11
...
@@ -438,22 +438,41 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
...
@@ -438,22 +438,41 @@ size_t FLACParser::readBuffer(void *output, size_t output_size) {
return
bufferSize
;
return
bufferSize
;
}
}
int64_t
FLACParser
::
getSeekPosition
(
int64_t
timeUs
)
{
bool
FLACParser
::
getSeekPositions
(
int64_t
timeUs
,
std
::
array
<
int64_t
,
4
>
&
result
)
{
if
(
!
mSeekTable
)
{
if
(
!
mSeekTable
)
{
return
-
1
;
return
false
;
}
}
int64_t
sample
=
(
timeUs
*
getSampleRate
())
/
1000000LL
;
unsigned
sampleRate
=
getSampleRate
();
if
(
sample
>=
getTotalSamples
())
{
int64_t
totalSamples
=
getTotalSamples
();
sample
=
getTotalSamples
();
int64_t
targetSampleNumber
=
(
timeUs
*
sampleRate
)
/
1000000LL
;
if
(
targetSampleNumber
>=
totalSamples
)
{
targetSampleNumber
=
totalSamples
-
1
;
}
}
FLAC__StreamMetadata_SeekPoint
*
points
=
mSeekTable
->
points
;
FLAC__StreamMetadata_SeekPoint
*
points
=
mSeekTable
->
points
;
for
(
unsigned
i
=
mSeekTable
->
num_points
;
i
>
0
;
)
{
unsigned
length
=
mSeekTable
->
num_points
;
i
--
;
if
(
points
[
i
].
sample_number
<=
sample
)
{
for
(
unsigned
i
=
length
;
i
!=
0
;
i
--
)
{
return
firstFrameOffset
+
points
[
i
].
stream_offset
;
int64_t
sampleNumber
=
points
[
i
-
1
].
sample_number
;
if
(
sampleNumber
<=
targetSampleNumber
)
{
result
[
0
]
=
(
sampleNumber
*
1000000LL
)
/
sampleRate
;
result
[
1
]
=
firstFrameOffset
+
points
[
i
-
1
].
stream_offset
;
if
(
sampleNumber
==
targetSampleNumber
||
i
>=
length
)
{
// exact seek, or no following seek point.
result
[
2
]
=
result
[
0
];
result
[
3
]
=
result
[
1
];
}
else
{
result
[
2
]
=
(
points
[
i
].
sample_number
*
1000000LL
)
/
sampleRate
;
result
[
3
]
=
firstFrameOffset
+
points
[
i
].
stream_offset
;
}
return
true
;
}
}
}
}
return
firstFrameOffset
;
result
[
0
]
=
0
;
result
[
1
]
=
firstFrameOffset
;
result
[
2
]
=
0
;
result
[
3
]
=
firstFrameOffset
;
return
true
;
}
}
extensions/flac/src/main/jni/include/flac_parser.h
View file @
41b3fc11
...
@@ -19,6 +19,7 @@
...
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <stdint.h>
#include <array>
#include <cstdlib>
#include <cstdlib>
#include <string>
#include <string>
#include <vector>
#include <vector>
...
@@ -82,7 +83,7 @@ class FLACParser {
...
@@ -82,7 +83,7 @@ class FLACParser {
bool
decodeMetadata
();
bool
decodeMetadata
();
size_t
readBuffer
(
void
*
output
,
size_t
output_size
);
size_t
readBuffer
(
void
*
output
,
size_t
output_size
);
int64_t
getSeekPosition
(
int64_t
timeUs
);
bool
getSeekPositions
(
int64_t
timeUs
,
std
::
array
<
int64_t
,
4
>
&
result
);
void
flush
()
{
void
flush
()
{
reset
(
mCurrentPos
);
reset
(
mCurrentPos
);
...
...
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
View file @
41b3fc11
...
@@ -868,26 +868,27 @@ public final class MediaSessionConnector {
...
@@ -868,26 +868,27 @@ public final class MediaSessionConnector {
private
void
rewind
(
Player
player
)
{
private
void
rewind
(
Player
player
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
rewindMs
>
0
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
rewindMs
>
0
)
{
seekTo
(
player
,
player
.
getCurrentPosition
()
-
rewindMs
);
seekTo
Offset
(
player
,
/* offsetMs= */
-
rewindMs
);
}
}
}
}
private
void
fastForward
(
Player
player
)
{
private
void
fastForward
(
Player
player
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
fastForwardMs
>
0
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
fastForwardMs
>
0
)
{
seekTo
(
player
,
player
.
getCurrentPosition
()
+
fastForwardMs
);
seekTo
Offset
(
player
,
/* offsetMs= */
fastForwardMs
);
}
}
}
}
private
void
seekTo
(
Player
player
,
long
positionMs
)
{
private
void
seekToOffset
(
Player
player
,
long
offsetMs
)
{
seekTo
(
player
,
player
.
getCurrentWindowIndex
(),
positionMs
);
long
positionMs
=
player
.
getCurrentPosition
()
+
offsetMs
;
}
private
void
seekTo
(
Player
player
,
int
windowIndex
,
long
positionMs
)
{
long
durationMs
=
player
.
getDuration
();
long
durationMs
=
player
.
getDuration
();
if
(
durationMs
!=
C
.
TIME_UNSET
)
{
if
(
durationMs
!=
C
.
TIME_UNSET
)
{
positionMs
=
Math
.
min
(
positionMs
,
durationMs
);
positionMs
=
Math
.
min
(
positionMs
,
durationMs
);
}
}
positionMs
=
Math
.
max
(
positionMs
,
0
);
positionMs
=
Math
.
max
(
positionMs
,
0
);
seekTo
(
player
,
player
.
getCurrentWindowIndex
(),
positionMs
);
}
private
void
seekTo
(
Player
player
,
int
windowIndex
,
long
positionMs
)
{
controlDispatcher
.
dispatchSeekTo
(
player
,
windowIndex
,
positionMs
);
controlDispatcher
.
dispatchSeekTo
(
player
,
windowIndex
,
positionMs
);
}
}
...
@@ -1096,7 +1097,7 @@ public final class MediaSessionConnector {
...
@@ -1096,7 +1097,7 @@ public final class MediaSessionConnector {
playbackPreparer
.
onPrepare
(
/* playWhenReady= */
true
);
playbackPreparer
.
onPrepare
(
/* playWhenReady= */
true
);
}
}
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
controlDispatcher
.
dispatchS
eekTo
(
player
,
player
.
getCurrentWindowIndex
(),
C
.
TIME_UNSET
);
s
eekTo
(
player
,
player
.
getCurrentWindowIndex
(),
C
.
TIME_UNSET
);
}
}
controlDispatcher
.
dispatchSetPlayWhenReady
(
controlDispatcher
.
dispatchSetPlayWhenReady
(
Assertions
.
checkNotNull
(
player
),
/* playWhenReady= */
true
);
Assertions
.
checkNotNull
(
player
),
/* playWhenReady= */
true
);
...
@@ -1113,7 +1114,7 @@ public final class MediaSessionConnector {
...
@@ -1113,7 +1114,7 @@ public final class MediaSessionConnector {
@Override
@Override
public
void
onSeekTo
(
long
positionMs
)
{
public
void
onSeekTo
(
long
positionMs
)
{
if
(
canDispatchPlaybackAction
(
PlaybackStateCompat
.
ACTION_SEEK_TO
))
{
if
(
canDispatchPlaybackAction
(
PlaybackStateCompat
.
ACTION_SEEK_TO
))
{
seekTo
(
player
,
positionMs
);
seekTo
(
player
,
p
layer
.
getCurrentWindowIndex
(),
p
ositionMs
);
}
}
}
}
...
...
extensions/rtmp/src/main/java/com/google/android/exoplayer2/ext/rtmp/RtmpDataSourceFactory.java
View file @
41b3fc11
...
@@ -37,7 +37,7 @@ public final class RtmpDataSourceFactory implements DataSource.Factory {
...
@@ -37,7 +37,7 @@ public final class RtmpDataSourceFactory implements DataSource.Factory {
}
}
@Override
@Override
public
DataSource
createDataSource
()
{
public
Rtmp
DataSource
createDataSource
()
{
RtmpDataSource
dataSource
=
new
RtmpDataSource
();
RtmpDataSource
dataSource
=
new
RtmpDataSource
();
if
(
listener
!=
null
)
{
if
(
listener
!=
null
)
{
dataSource
.
addTransferListener
(
listener
);
dataSource
.
addTransferListener
(
listener
);
...
...
gradle/wrapper/gradle-wrapper.properties
View file @
41b3fc11
#
Thu Apr 25 13:15:25
BST 2019
#
Mon Oct 07 17:24:00
BST 2019
distributionBase
=
GRADLE_USER_HOME
distributionBase
=
GRADLE_USER_HOME
distributionPath
=
wrapper/dists
distributionPath
=
wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
zipStorePath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-5.
1
.1-all.zip
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-5.
4
.1-all.zip
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java
View file @
41b3fc11
...
@@ -260,17 +260,21 @@ import java.util.concurrent.CopyOnWriteArrayList;
...
@@ -260,17 +260,21 @@ import java.util.concurrent.CopyOnWriteArrayList;
internalPlayer
.
setPlayWhenReady
(
internalPlayWhenReady
);
internalPlayer
.
setPlayWhenReady
(
internalPlayWhenReady
);
}
}
boolean
playWhenReadyChanged
=
this
.
playWhenReady
!=
playWhenReady
;
boolean
playWhenReadyChanged
=
this
.
playWhenReady
!=
playWhenReady
;
boolean
suppressionReasonChanged
=
this
.
playbackSuppressionReason
!=
playbackSuppressionReason
;
this
.
playWhenReady
=
playWhenReady
;
this
.
playWhenReady
=
playWhenReady
;
this
.
playbackSuppressionReason
=
playbackSuppressionReason
;
this
.
playbackSuppressionReason
=
playbackSuppressionReason
;
boolean
isPlaying
=
isPlaying
();
boolean
isPlaying
=
isPlaying
();
boolean
isPlayingChanged
=
oldIsPlaying
!=
isPlaying
;
boolean
isPlayingChanged
=
oldIsPlaying
!=
isPlaying
;
if
(
playWhenReadyChanged
||
isPlayingChanged
)
{
if
(
playWhenReadyChanged
||
suppressionReasonChanged
||
isPlayingChanged
)
{
int
playbackState
=
playbackInfo
.
playbackState
;
int
playbackState
=
playbackInfo
.
playbackState
;
notifyListeners
(
notifyListeners
(
listener
->
{
listener
->
{
if
(
playWhenReadyChanged
)
{
if
(
playWhenReadyChanged
)
{
listener
.
onPlayerStateChanged
(
playWhenReady
,
playbackState
);
listener
.
onPlayerStateChanged
(
playWhenReady
,
playbackState
);
}
}
if
(
suppressionReasonChanged
)
{
listener
.
onPlaybackSuppressionReasonChanged
(
playbackSuppressionReason
);
}
if
(
isPlayingChanged
)
{
if
(
isPlayingChanged
)
{
listener
.
onIsPlayingChanged
(
isPlaying
);
listener
.
onIsPlayingChanged
(
isPlaying
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
41b3fc11
...
@@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
...
@@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3". */
/** 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.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public
static
final
String
VERSION
=
"2.10.
5
"
;
public
static
final
String
VERSION
=
"2.10.
6
"
;
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.10.
5
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.10.
6
"
;
/**
/**
* The version of the library expressed as an integer, for example 1002003.
* The version of the library expressed as an integer, for example 1002003.
...
@@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
...
@@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
* integer version 123045006 (123-045-006).
*/
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
int
VERSION_INT
=
201000
5
;
public
static
final
int
VERSION_INT
=
201000
6
;
/**
/**
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
* Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions}
...
...
library/core/src/main/java/com/google/android/exoplayer2/Format.java
View file @
41b3fc11
...
@@ -1066,6 +1066,38 @@ public final class Format implements Parcelable {
...
@@ -1066,6 +1066,38 @@ public final class Format implements Parcelable {
accessibilityChannel
);
accessibilityChannel
);
}
}
public
Format
copyWithLabel
(
@Nullable
String
label
)
{
return
new
Format
(
id
,
label
,
selectionFlags
,
roleFlags
,
bitrate
,
codecs
,
metadata
,
containerMimeType
,
sampleMimeType
,
maxInputSize
,
initializationData
,
drmInitData
,
subsampleOffsetUs
,
width
,
height
,
frameRate
,
rotationDegrees
,
pixelWidthHeightRatio
,
projectionData
,
stereoMode
,
colorInfo
,
channelCount
,
sampleRate
,
pcmEncoding
,
encoderDelay
,
encoderPadding
,
language
,
accessibilityChannel
);
}
public
Format
copyWithContainerInfo
(
public
Format
copyWithContainerInfo
(
@Nullable
String
id
,
@Nullable
String
id
,
@Nullable
String
label
,
@Nullable
String
label
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/Player.java
View file @
41b3fc11
...
@@ -366,6 +366,14 @@ public interface Player {
...
@@ -366,6 +366,14 @@ public interface Player {
default
void
onPlayerStateChanged
(
boolean
playWhenReady
,
int
playbackState
)
{}
default
void
onPlayerStateChanged
(
boolean
playWhenReady
,
int
playbackState
)
{}
/**
/**
* Called when the value returned from {@link #getPlaybackSuppressionReason()} changes.
*
* @param playbackSuppressionReason The current {@link PlaybackSuppressionReason}.
*/
default
void
onPlaybackSuppressionReasonChanged
(
@PlaybackSuppressionReason
int
playbackSuppressionReason
)
{}
/**
* Called when the value of {@link #isPlaying()} changes.
* Called when the value of {@link #isPlaying()} changes.
*
*
* @param isPlaying Whether the player is playing.
* @param isPlaying Whether the player is playing.
...
@@ -470,18 +478,21 @@ public interface Player {
...
@@ -470,18 +478,21 @@ public interface Player {
int
STATE_ENDED
=
4
;
int
STATE_ENDED
=
4
;
/**
/**
* Reason why playback is suppressed even
if {@link #getPlaybackState()} is {@link #STATE_READY}
* Reason why playback is suppressed even
though {@link #getPlayWhenReady()} is {@code true}. One
*
and {@link #getPlayWhenReady()} is {@code true}. One of
{@link
*
of {@link #PLAYBACK_SUPPRESSION_REASON_NONE} or
{@link
* #PLAYBACK_SUPPRESSION_REASON_
NONE} or {@link #PLAYBACK_SUPPRESSION_REASON
_AUDIO_FOCUS_LOSS}.
* #PLAYBACK_SUPPRESSION_REASON_
TRANSIENT
_AUDIO_FOCUS_LOSS}.
*/
*/
@Documented
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
PLAYBACK_SUPPRESSION_REASON_NONE
,
PLAYBACK_SUPPRESSION_REASON_AUDIO_FOCUS_LOSS
})
@IntDef
({
PLAYBACK_SUPPRESSION_REASON_NONE
,
PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS
})
@interface
PlaybackSuppressionReason
{}
@interface
PlaybackSuppressionReason
{}
/** Playback is not suppressed. */
/** Playback is not suppressed. */
int
PLAYBACK_SUPPRESSION_REASON_NONE
=
0
;
int
PLAYBACK_SUPPRESSION_REASON_NONE
=
0
;
/** Playback is suppressed
because audio focus is lost or can't be acquired
. */
/** Playback is suppressed
due to transient audio focus loss
. */
int
PLAYBACK_SUPPRESSION_REASON_AUDIO_FOCUS_LOSS
=
1
;
int
PLAYBACK_SUPPRESSION_REASON_
TRANSIENT_
AUDIO_FOCUS_LOSS
=
1
;
/**
/**
* Repeat modes for playback. One of {@link #REPEAT_MODE_OFF}, {@link #REPEAT_MODE_ONE} or {@link
* Repeat modes for playback. One of {@link #REPEAT_MODE_OFF}, {@link #REPEAT_MODE_ONE} or {@link
...
@@ -609,13 +620,10 @@ public interface Player {
...
@@ -609,13 +620,10 @@ public interface Player {
int
getPlaybackState
();
int
getPlaybackState
();
/**
/**
* Returns reason why playback is suppressed even if {@link #getPlaybackState()} is {@link
* Returns the reason why playback is suppressed even though {@link #getPlayWhenReady()} is {@code
* #STATE_READY} and {@link #getPlayWhenReady()} is {@code true}.
* true}, or {@link #PLAYBACK_SUPPRESSION_REASON_NONE} if playback is not suppressed.
*
* <p>Note that {@link #PLAYBACK_SUPPRESSION_REASON_NONE} indicates that playback is not
* suppressed.
*
*
* @return The current {@link PlaybackSuppressionReason}.
* @return The current {@link PlaybackSuppressionReason
playback suppression reason
}.
*/
*/
@PlaybackSuppressionReason
@PlaybackSuppressionReason
int
getPlaybackSuppressionReason
();
int
getPlaybackSuppressionReason
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
View file @
41b3fc11
...
@@ -1228,13 +1228,13 @@ public class SimpleExoPlayer extends BasePlayer
...
@@ -1228,13 +1228,13 @@ public class SimpleExoPlayer extends BasePlayer
private
void
updatePlayWhenReady
(
private
void
updatePlayWhenReady
(
boolean
playWhenReady
,
@AudioFocusManager
.
PlayerCommand
int
playerCommand
)
{
boolean
playWhenReady
,
@AudioFocusManager
.
PlayerCommand
int
playerCommand
)
{
playWhenReady
=
playWhenReady
&&
playerCommand
!=
AudioFocusManager
.
PLAYER_COMMAND_DO_NOT_PLAY
;
@PlaybackSuppressionReason
int
playbackSuppressionReason
=
int
playbackSuppressionReason
=
playerCommand
==
AudioFocusManager
.
PLAYER_COMMAND_PLAY_WHEN_READY
playWhenReady
&&
playerCommand
!=
AudioFocusManager
.
PLAYER_COMMAND_PLAY_WHEN_READY
?
Player
.
PLAYBACK_SUPPRESSION_REASON_NONE
?
Player
.
PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS
:
Player
.
PLAYBACK_SUPPRESSION_REASON_AUDIO_FOCUS_LOSS
;
:
Player
.
PLAYBACK_SUPPRESSION_REASON_NONE
;
player
.
setPlayWhenReady
(
player
.
setPlayWhenReady
(
playWhenReady
,
playbackSuppressionReason
);
playWhenReady
&&
playerCommand
!=
AudioFocusManager
.
PLAYER_COMMAND_DO_NOT_PLAY
,
playbackSuppressionReason
);
}
}
private
void
verifyApplicationThread
()
{
private
void
verifyApplicationThread
()
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
View file @
41b3fc11
...
@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
...
@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Player.PlaybackSuppressionReason
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.Timeline.Period
;
import
com.google.android.exoplayer2.Timeline.Period
;
import
com.google.android.exoplayer2.Timeline.Window
;
import
com.google.android.exoplayer2.Timeline.Window
;
...
@@ -472,6 +473,23 @@ public class AnalyticsCollector
...
@@ -472,6 +473,23 @@ public class AnalyticsCollector
}
}
@Override
@Override
public
void
onPlaybackSuppressionReasonChanged
(
@PlaybackSuppressionReason
int
playbackSuppressionReason
)
{
EventTime
eventTime
=
generatePlayingMediaPeriodEventTime
();
for
(
AnalyticsListener
listener
:
listeners
)
{
listener
.
onPlaybackSuppressionReasonChanged
(
eventTime
,
playbackSuppressionReason
);
}
}
@Override
public
void
onIsPlayingChanged
(
boolean
isPlaying
)
{
EventTime
eventTime
=
generatePlayingMediaPeriodEventTime
();
for
(
AnalyticsListener
listener
:
listeners
)
{
listener
.
onIsPlayingChanged
(
eventTime
,
isPlaying
);
}
}
@Override
public
final
void
onRepeatModeChanged
(
@Player
.
RepeatMode
int
repeatMode
)
{
public
final
void
onRepeatModeChanged
(
@Player
.
RepeatMode
int
repeatMode
)
{
EventTime
eventTime
=
generatePlayingMediaPeriodEventTime
();
EventTime
eventTime
=
generatePlayingMediaPeriodEventTime
();
for
(
AnalyticsListener
listener
:
listeners
)
{
for
(
AnalyticsListener
listener
:
listeners
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
View file @
41b3fc11
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer2.Format;
...
@@ -23,6 +23,7 @@ import com.google.android.exoplayer2.Format;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Player.DiscontinuityReason
;
import
com.google.android.exoplayer2.Player.DiscontinuityReason
;
import
com.google.android.exoplayer2.Player.PlaybackSuppressionReason
;
import
com.google.android.exoplayer2.Player.TimelineChangeReason
;
import
com.google.android.exoplayer2.Player.TimelineChangeReason
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.Timeline
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
...
@@ -133,6 +134,23 @@ public interface AnalyticsListener {
...
@@ -133,6 +134,23 @@ public interface AnalyticsListener {
EventTime
eventTime
,
boolean
playWhenReady
,
int
playbackState
)
{}
EventTime
eventTime
,
boolean
playWhenReady
,
int
playbackState
)
{}
/**
/**
* Called when playback suppression reason changed.
*
* @param eventTime The event time.
* @param playbackSuppressionReason The new {@link PlaybackSuppressionReason}.
*/
default
void
onPlaybackSuppressionReasonChanged
(
EventTime
eventTime
,
@PlaybackSuppressionReason
int
playbackSuppressionReason
)
{}
/**
* Called when the player starts or stops playing.
*
* @param eventTime The event time.
* @param isPlaying Whether the player is playing.
*/
default
void
onIsPlayingChanged
(
EventTime
eventTime
,
boolean
isPlaying
)
{}
/**
* Called when the timeline changed.
* Called when the timeline changed.
*
*
* @param eventTime The event time.
* @param eventTime The event time.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/SeekMap.java
View file @
41b3fc11
...
@@ -25,7 +25,7 @@ import com.google.android.exoplayer2.util.Assertions;
...
@@ -25,7 +25,7 @@ import com.google.android.exoplayer2.util.Assertions;
public
interface
SeekMap
{
public
interface
SeekMap
{
/** A {@link SeekMap} that does not support seeking. */
/** A {@link SeekMap} that does not support seeking. */
final
class
Unseekable
implements
SeekMap
{
class
Unseekable
implements
SeekMap
{
private
final
long
durationUs
;
private
final
long
durationUs
;
private
final
SeekPoints
startSeekPoints
;
private
final
SeekPoints
startSeekPoints
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/ConstantBitrateSeeker.java
View file @
41b3fc11
...
@@ -22,8 +22,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
...
@@ -22,8 +22,7 @@ import com.google.android.exoplayer2.extractor.MpegAudioHeader;
/**
/**
* MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate.
* MP3 seeker that doesn't rely on metadata and seeks assuming the source has a constant bitrate.
*/
*/
/* package */
final
class
ConstantBitrateSeeker
extends
ConstantBitrateSeekMap
/* package */
final
class
ConstantBitrateSeeker
extends
ConstantBitrateSeekMap
implements
Seeker
{
implements
Mp3Extractor
.
Seeker
{
/**
/**
* @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown.
* @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/MlltSeeker.java
View file @
41b3fc11
...
@@ -22,7 +22,7 @@ import com.google.android.exoplayer2.metadata.id3.MlltFrame;
...
@@ -22,7 +22,7 @@ import com.google.android.exoplayer2.metadata.id3.MlltFrame;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
/** MP3 seeker that uses metadata from an {@link MlltFrame}. */
/** MP3 seeker that uses metadata from an {@link MlltFrame}. */
/* package */
final
class
MlltSeeker
implements
Mp3Extractor
.
Seeker
{
/* package */
final
class
MlltSeeker
implements
Seeker
{
/**
/**
* Returns an {@link MlltSeeker} for seeking in the stream.
* Returns an {@link MlltSeeker} for seeking in the stream.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java
View file @
41b3fc11
...
@@ -28,8 +28,8 @@ import com.google.android.exoplayer2.extractor.GaplessInfoHolder;
...
@@ -28,8 +28,8 @@ import com.google.android.exoplayer2.extractor.GaplessInfoHolder;
import
com.google.android.exoplayer2.extractor.Id3Peeker
;
import
com.google.android.exoplayer2.extractor.Id3Peeker
;
import
com.google.android.exoplayer2.extractor.MpegAudioHeader
;
import
com.google.android.exoplayer2.extractor.MpegAudioHeader
;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.mp3.Seeker.UnseekableSeeker
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate
;
import
com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate
;
...
@@ -114,7 +114,8 @@ public final class Mp3Extractor implements Extractor {
...
@@ -114,7 +114,8 @@ public final class Mp3Extractor implements Extractor {
private
int
synchronizedHeaderData
;
private
int
synchronizedHeaderData
;
private
Metadata
metadata
;
private
Metadata
metadata
;
private
Seeker
seeker
;
@Nullable
private
Seeker
seeker
;
private
boolean
disableSeeking
;
private
long
basisTimeUs
;
private
long
basisTimeUs
;
private
long
samplesRead
;
private
long
samplesRead
;
private
long
firstSamplePosition
;
private
long
firstSamplePosition
;
...
@@ -188,14 +189,19 @@ public final class Mp3Extractor implements Extractor {
...
@@ -188,14 +189,19 @@ public final class Mp3Extractor implements Extractor {
// takes priority as it can provide greater precision.
// takes priority as it can provide greater precision.
Seeker
seekFrameSeeker
=
maybeReadSeekFrame
(
input
);
Seeker
seekFrameSeeker
=
maybeReadSeekFrame
(
input
);
Seeker
metadataSeeker
=
maybeHandleSeekMetadata
(
metadata
,
input
.
getPosition
());
Seeker
metadataSeeker
=
maybeHandleSeekMetadata
(
metadata
,
input
.
getPosition
());
if
(
metadataSeeker
!=
null
)
{
seeker
=
metadataSeeker
;
if
(
disableSeeking
)
{
}
else
if
(
seekFrameSeeker
!=
null
)
{
seeker
=
new
UnseekableSeeker
();
seeker
=
seekFrameSeeker
;
}
else
{
}
if
(
metadataSeeker
!=
null
)
{
if
(
seeker
==
null
seeker
=
metadataSeeker
;
||
(!
seeker
.
isSeekable
()
&&
(
flags
&
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
)
!=
0
))
{
}
else
if
(
seekFrameSeeker
!=
null
)
{
seeker
=
getConstantBitrateSeeker
(
input
);
seeker
=
seekFrameSeeker
;
}
if
(
seeker
==
null
||
(!
seeker
.
isSeekable
()
&&
(
flags
&
FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
)
!=
0
))
{
seeker
=
getConstantBitrateSeeker
(
input
);
}
}
}
extractorOutput
.
seekMap
(
seeker
);
extractorOutput
.
seekMap
(
seeker
);
trackOutput
.
format
(
trackOutput
.
format
(
...
@@ -226,6 +232,15 @@ public final class Mp3Extractor implements Extractor {
...
@@ -226,6 +232,15 @@ public final class Mp3Extractor implements Extractor {
return
readSample
(
input
);
return
readSample
(
input
);
}
}
/**
* Disables the extractor from being able to seek through the media.
*
* <p>Please note that this needs to be called before {@link #read}.
*/
public
void
disableSeeking
()
{
disableSeeking
=
true
;
}
// Internal methods.
// Internal methods.
private
int
readSample
(
ExtractorInput
extractorInput
)
throws
IOException
,
InterruptedException
{
private
int
readSample
(
ExtractorInput
extractorInput
)
throws
IOException
,
InterruptedException
{
...
@@ -464,26 +479,5 @@ public final class Mp3Extractor implements Extractor {
...
@@ -464,26 +479,5 @@ public final class Mp3Extractor implements Extractor {
return
null
;
return
null
;
}
}
/**
* {@link SeekMap} that provides the end position of audio data and also allows mapping from
* position (byte offset) back to time, which can be used to work out the new sample basis
* timestamp after seeking and resynchronization.
*/
/* package */
interface
Seeker
extends
SeekMap
{
/**
* Maps a position (byte offset) to a corresponding sample timestamp.
*
* @param position A seek position (byte offset) relative to the start of the stream.
* @return The corresponding timestamp of the next sample to be read, in microseconds.
*/
long
getTimeUs
(
long
position
);
/**
* Returns the position (byte offset) in the stream that is immediately after audio data, or
* {@link C#POSITION_UNSET} if not known.
*/
long
getDataEndPosition
();
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/Seeker.java
0 → 100644
View file @
41b3fc11
/*
* Copyright (C) 2019 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
.
extractor
.
mp3
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
/**
* {@link SeekMap} that provides the end position of audio data and also allows mapping from
* position (byte offset) back to time, which can be used to work out the new sample basis timestamp
* after seeking and resynchronization.
*/
/* package */
interface
Seeker
extends
SeekMap
{
/**
* Maps a position (byte offset) to a corresponding sample timestamp.
*
* @param position A seek position (byte offset) relative to the start of the stream.
* @return The corresponding timestamp of the next sample to be read, in microseconds.
*/
long
getTimeUs
(
long
position
);
/**
* Returns the position (byte offset) in the stream that is immediately after audio data, or
* {@link C#POSITION_UNSET} if not known.
*/
long
getDataEndPosition
();
/** A {@link Seeker} that does not support seeking through audio data. */
/* package */
class
UnseekableSeeker
extends
SeekMap
.
Unseekable
implements
Seeker
{
public
UnseekableSeeker
()
{
super
(
/* durationUs= */
C
.
TIME_UNSET
);
}
@Override
public
long
getTimeUs
(
long
position
)
{
return
0
;
}
@Override
public
long
getDataEndPosition
()
{
// Position unset as we do not know the data end position. Note that returning 0 doesn't work.
return
C
.
POSITION_UNSET
;
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/VbriSeeker.java
View file @
41b3fc11
...
@@ -23,10 +23,8 @@ import com.google.android.exoplayer2.util.Log;
...
@@ -23,10 +23,8 @@ import com.google.android.exoplayer2.util.Log;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
/**
/** MP3 seeker that uses metadata from a VBRI header. */
* MP3 seeker that uses metadata from a VBRI header.
/* package */
final
class
VbriSeeker
implements
Seeker
{
*/
/* package */
final
class
VbriSeeker
implements
Mp3Extractor
.
Seeker
{
private
static
final
String
TAG
=
"VbriSeeker"
;
private
static
final
String
TAG
=
"VbriSeeker"
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp3/XingSeeker.java
View file @
41b3fc11
...
@@ -24,10 +24,8 @@ import com.google.android.exoplayer2.util.Log;
...
@@ -24,10 +24,8 @@ import com.google.android.exoplayer2.util.Log;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
/**
/** MP3 seeker that uses metadata from a Xing header. */
* MP3 seeker that uses metadata from a Xing header.
/* package */
final
class
XingSeeker
implements
Seeker
{
*/
/* package */
final
class
XingSeeker
implements
Mp3Extractor
.
Seeker
{
private
static
final
String
TAG
=
"XingSeeker"
;
private
static
final
String
TAG
=
"XingSeeker"
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java
View file @
41b3fc11
...
@@ -377,18 +377,13 @@ public final class MediaCodecInfo {
...
@@ -377,18 +377,13 @@ public final class MediaCodecInfo {
@TargetApi
(
21
)
@TargetApi
(
21
)
public
Point
alignVideoSizeV21
(
int
width
,
int
height
)
{
public
Point
alignVideoSizeV21
(
int
width
,
int
height
)
{
if
(
capabilities
==
null
)
{
if
(
capabilities
==
null
)
{
logNoSupport
(
"align.caps"
);
return
null
;
return
null
;
}
}
VideoCapabilities
videoCapabilities
=
capabilities
.
getVideoCapabilities
();
VideoCapabilities
videoCapabilities
=
capabilities
.
getVideoCapabilities
();
if
(
videoCapabilities
==
null
)
{
if
(
videoCapabilities
==
null
)
{
logNoSupport
(
"align.vCaps"
);
return
null
;
return
null
;
}
}
int
widthAlignment
=
videoCapabilities
.
getWidthAlignment
();
return
alignVideoSizeV21
(
videoCapabilities
,
width
,
height
);
int
heightAlignment
=
videoCapabilities
.
getHeightAlignment
();
return
new
Point
(
Util
.
ceilDivide
(
width
,
widthAlignment
)
*
widthAlignment
,
Util
.
ceilDivide
(
height
,
heightAlignment
)
*
heightAlignment
);
}
}
/**
/**
...
@@ -519,6 +514,11 @@ public final class MediaCodecInfo {
...
@@ -519,6 +514,11 @@ public final class MediaCodecInfo {
@TargetApi
(
21
)
@TargetApi
(
21
)
private
static
boolean
areSizeAndRateSupportedV21
(
VideoCapabilities
capabilities
,
int
width
,
private
static
boolean
areSizeAndRateSupportedV21
(
VideoCapabilities
capabilities
,
int
width
,
int
height
,
double
frameRate
)
{
int
height
,
double
frameRate
)
{
// Don't ever fail due to alignment. See: https://github.com/google/ExoPlayer/issues/6551.
Point
alignedSize
=
alignVideoSizeV21
(
capabilities
,
width
,
height
);
width
=
alignedSize
.
x
;
height
=
alignedSize
.
y
;
if
(
frameRate
==
Format
.
NO_VALUE
||
frameRate
<=
0
)
{
if
(
frameRate
==
Format
.
NO_VALUE
||
frameRate
<=
0
)
{
return
capabilities
.
isSizeSupported
(
width
,
height
);
return
capabilities
.
isSizeSupported
(
width
,
height
);
}
else
{
}
else
{
...
@@ -530,6 +530,15 @@ public final class MediaCodecInfo {
...
@@ -530,6 +530,15 @@ public final class MediaCodecInfo {
}
}
}
}
@TargetApi
(
21
)
private
static
Point
alignVideoSizeV21
(
VideoCapabilities
capabilities
,
int
width
,
int
height
)
{
int
widthAlignment
=
capabilities
.
getWidthAlignment
();
int
heightAlignment
=
capabilities
.
getHeightAlignment
();
return
new
Point
(
Util
.
ceilDivide
(
width
,
widthAlignment
)
*
widthAlignment
,
Util
.
ceilDivide
(
height
,
heightAlignment
)
*
heightAlignment
);
}
@TargetApi
(
23
)
@TargetApi
(
23
)
private
static
int
getMaxSupportedInstancesV23
(
CodecCapabilities
capabilities
)
{
private
static
int
getMaxSupportedInstancesV23
(
CodecCapabilities
capabilities
)
{
return
capabilities
.
getMaxSupportedInstances
();
return
capabilities
.
getMaxSupportedInstances
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
View file @
41b3fc11
...
@@ -277,13 +277,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -277,13 +277,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private
static
final
int
ADAPTATION_WORKAROUND_MODE_ALWAYS
=
2
;
private
static
final
int
ADAPTATION_WORKAROUND_MODE_ALWAYS
=
2
;
/**
/**
* H.264/AVC buffer to queue when using the adaptation workaround (see
* H.264/AVC buffer to queue when using the adaptation workaround (see
{@link
*
{@link #codecAdaptationWorkaroundMode(String)}. Consists of three NAL units with start codes:
*
#codecAdaptationWorkaroundMode(String)}. Consists of three NAL units with start codes: Baseline
*
Baseline sequence/picture parameter sets and a 32 * 32 pixel IDR slice. This stream can be
*
sequence/picture parameter sets and a 32 * 32 pixel IDR slice. This stream can be queued to
*
queued to
force a resolution change when adapting to a new format.
* force a resolution change when adapting to a new format.
*/
*/
private
static
final
byte
[]
ADAPTATION_WORKAROUND_BUFFER
=
Util
.
getBytesFromHexString
(
private
static
final
byte
[]
ADAPTATION_WORKAROUND_BUFFER
=
"0000016742C00BDA259000000168CE0F13200000016588840DCE7118A0002FBF1C31C3275D78"
);
new
byte
[]
{
0
,
0
,
1
,
103
,
66
,
-
64
,
11
,
-
38
,
37
,
-
112
,
0
,
0
,
1
,
104
,
-
50
,
15
,
19
,
32
,
0
,
0
,
1
,
101
,
-
120
,
-
124
,
13
,
-
50
,
113
,
24
,
-
96
,
0
,
47
,
-
65
,
28
,
49
,
-
61
,
39
,
93
,
120
};
private
static
final
int
ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
=
32
;
private
static
final
int
ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
=
32
;
private
final
MediaCodecSelector
mediaCodecSelector
;
private
final
MediaCodecSelector
mediaCodecSelector
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyDecoder.java
View file @
41b3fc11
...
@@ -15,12 +15,10 @@
...
@@ -15,12 +15,10 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
metadata
.
icy
;
package
com
.
google
.
android
.
exoplayer2
.
metadata
.
icy
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.MetadataDecoder
;
import
com.google.android.exoplayer2.metadata.MetadataDecoder
;
import
com.google.android.exoplayer2.metadata.MetadataInputBuffer
;
import
com.google.android.exoplayer2.metadata.MetadataInputBuffer
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.regex.Matcher
;
import
java.util.regex.Matcher
;
...
@@ -36,7 +34,6 @@ public final class IcyDecoder implements MetadataDecoder {
...
@@ -36,7 +34,6 @@ public final class IcyDecoder implements MetadataDecoder {
private
static
final
String
STREAM_KEY_URL
=
"streamurl"
;
private
static
final
String
STREAM_KEY_URL
=
"streamurl"
;
@Override
@Override
@Nullable
@SuppressWarnings
(
"ByteBufferBackingArray"
)
@SuppressWarnings
(
"ByteBufferBackingArray"
)
public
Metadata
decode
(
MetadataInputBuffer
inputBuffer
)
{
public
Metadata
decode
(
MetadataInputBuffer
inputBuffer
)
{
ByteBuffer
buffer
=
inputBuffer
.
data
;
ByteBuffer
buffer
=
inputBuffer
.
data
;
...
@@ -45,7 +42,6 @@ public final class IcyDecoder implements MetadataDecoder {
...
@@ -45,7 +42,6 @@ public final class IcyDecoder implements MetadataDecoder {
return
decode
(
Util
.
fromUtf8Bytes
(
data
,
0
,
length
));
return
decode
(
Util
.
fromUtf8Bytes
(
data
,
0
,
length
));
}
}
@Nullable
@VisibleForTesting
@VisibleForTesting
/* package */
Metadata
decode
(
String
metadata
)
{
/* package */
Metadata
decode
(
String
metadata
)
{
String
name
=
null
;
String
name
=
null
;
...
@@ -62,12 +58,9 @@ public final class IcyDecoder implements MetadataDecoder {
...
@@ -62,12 +58,9 @@ public final class IcyDecoder implements MetadataDecoder {
case
STREAM_KEY_URL:
case
STREAM_KEY_URL:
url
=
value
;
url
=
value
;
break
;
break
;
default
:
Log
.
w
(
TAG
,
"Unrecognized ICY tag: "
+
name
);
break
;
}
}
index
=
matcher
.
end
();
index
=
matcher
.
end
();
}
}
return
(
name
!=
null
||
url
!=
null
)
?
new
Metadata
(
new
IcyInfo
(
name
,
url
))
:
null
;
return
new
Metadata
(
new
IcyInfo
(
metadata
,
name
,
url
))
;
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/metadata/icy/IcyInfo.java
View file @
41b3fc11
...
@@ -19,26 +19,35 @@ import android.os.Parcel;
...
@@ -19,26 +19,35 @@ import android.os.Parcel;
import
android.os.Parcelable
;
import
android.os.Parcelable
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
/** ICY in-stream information. */
/** ICY in-stream information. */
public
final
class
IcyInfo
implements
Metadata
.
Entry
{
public
final
class
IcyInfo
implements
Metadata
.
Entry
{
/** The complete metadata string used to construct this IcyInfo. */
public
final
String
rawMetadata
;
/** The stream title if present, or {@code null}. */
/** The stream title if present, or {@code null}. */
@Nullable
public
final
String
title
;
@Nullable
public
final
String
title
;
/** The stream
title
if present, or {@code null}. */
/** The stream
URL
if present, or {@code null}. */
@Nullable
public
final
String
url
;
@Nullable
public
final
String
url
;
/**
/**
* Construct a new IcyInfo from the source metadata string, and optionally a StreamTitle and
* StreamUrl that have been extracted.
*
* @param rawMetadata See {@link #rawMetadata}.
* @param title See {@link #title}.
* @param title See {@link #title}.
* @param url See {@link #url}.
* @param url See {@link #url}.
*/
*/
public
IcyInfo
(
@Nullable
String
title
,
@Nullable
String
url
)
{
public
IcyInfo
(
String
rawMetadata
,
@Nullable
String
title
,
@Nullable
String
url
)
{
this
.
rawMetadata
=
rawMetadata
;
this
.
title
=
title
;
this
.
title
=
title
;
this
.
url
=
url
;
this
.
url
=
url
;
}
}
/* package */
IcyInfo
(
Parcel
in
)
{
/* package */
IcyInfo
(
Parcel
in
)
{
rawMetadata
=
Assertions
.
checkNotNull
(
in
.
readString
());
title
=
in
.
readString
();
title
=
in
.
readString
();
url
=
in
.
readString
();
url
=
in
.
readString
();
}
}
...
@@ -52,26 +61,27 @@ public final class IcyInfo implements Metadata.Entry {
...
@@ -52,26 +61,27 @@ public final class IcyInfo implements Metadata.Entry {
return
false
;
return
false
;
}
}
IcyInfo
other
=
(
IcyInfo
)
obj
;
IcyInfo
other
=
(
IcyInfo
)
obj
;
return
Util
.
areEqual
(
title
,
other
.
title
)
&&
Util
.
areEqual
(
url
,
other
.
url
);
// title & url are derived from rawMetadata, so no need to include them in the comparison.
return
Util
.
areEqual
(
rawMetadata
,
other
.
rawMetadata
);
}
}
@Override
@Override
public
int
hashCode
()
{
public
int
hashCode
()
{
int
result
=
17
;
// title & url are derived from rawMetadata, so no need to include them in the hash.
result
=
31
*
result
+
(
title
!=
null
?
title
.
hashCode
()
:
0
);
return
rawMetadata
.
hashCode
();
result
=
31
*
result
+
(
url
!=
null
?
url
.
hashCode
()
:
0
);
return
result
;
}
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"ICY: title=\""
+
title
+
"\", url=\""
+
url
+
"\""
;
return
String
.
format
(
"ICY: title=\"%s\", url=\"%s\", rawMetadata=\"%s\""
,
title
,
url
,
rawMetadata
);
}
}
// Parcelable implementation.
// Parcelable implementation.
@Override
@Override
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
dest
.
writeString
(
rawMetadata
);
dest
.
writeString
(
title
);
dest
.
writeString
(
title
);
dest
.
writeString
(
url
);
dest
.
writeString
(
url
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java
View file @
41b3fc11
...
@@ -33,6 +33,7 @@ import com.google.android.exoplayer2.extractor.SeekMap;
...
@@ -33,6 +33,7 @@ import com.google.android.exoplayer2.extractor.SeekMap;
import
com.google.android.exoplayer2.extractor.SeekMap.SeekPoints
;
import
com.google.android.exoplayer2.extractor.SeekMap.SeekPoints
;
import
com.google.android.exoplayer2.extractor.SeekMap.Unseekable
;
import
com.google.android.exoplayer2.extractor.SeekMap.Unseekable
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.mp3.Mp3Extractor
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.icy.IcyHeaders
;
import
com.google.android.exoplayer2.metadata.icy.IcyHeaders
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher
;
...
@@ -949,6 +950,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -949,6 +950,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
}
}
input
=
new
DefaultExtractorInput
(
extractorDataSource
,
position
,
length
);
input
=
new
DefaultExtractorInput
(
extractorDataSource
,
position
,
length
);
Extractor
extractor
=
extractorHolder
.
selectExtractor
(
input
,
extractorOutput
,
uri
);
Extractor
extractor
=
extractorHolder
.
selectExtractor
(
input
,
extractorOutput
,
uri
);
// MP3 live streams commonly have seekable metadata, despite being unseekable.
if
(
icyHeaders
!=
null
&&
extractor
instanceof
Mp3Extractor
)
{
((
Mp3Extractor
)
extractor
).
disableSeeking
();
}
if
(
pendingExtractorSeek
)
{
if
(
pendingExtractorSeek
)
{
extractor
.
seek
(
position
,
seekTimeUs
);
extractor
.
seek
(
position
,
seekTimeUs
);
pendingExtractorSeek
=
false
;
pendingExtractorSeek
=
false
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/trackselection/AdaptiveTrackSelection.java
View file @
41b3fc11
...
@@ -308,7 +308,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
...
@@ -308,7 +308,7 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
public
static
final
int
DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS
=
10000
;
public
static
final
int
DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS
=
10000
;
public
static
final
int
DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS
=
25000
;
public
static
final
int
DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS
=
25000
;
public
static
final
int
DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS
=
25000
;
public
static
final
int
DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS
=
25000
;
public
static
final
float
DEFAULT_BANDWIDTH_FRACTION
=
0.7
5
f
;
public
static
final
float
DEFAULT_BANDWIDTH_FRACTION
=
0.7f
;
public
static
final
float
DEFAULT_BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE
=
0.75f
;
public
static
final
float
DEFAULT_BUFFERED_FRACTION_TO_LIVE_EDGE_FOR_QUALITY_INCREASE
=
0.75f
;
public
static
final
long
DEFAULT_MIN_TIME_BETWEEN_BUFFER_REEVALUTATION_MS
=
2000
;
public
static
final
long
DEFAULT_MIN_TIME_BETWEEN_BUFFER_REEVALUTATION_MS
=
2000
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/FileDataSourceFactory.java
View file @
41b3fc11
...
@@ -33,7 +33,7 @@ public final class FileDataSourceFactory implements DataSource.Factory {
...
@@ -33,7 +33,7 @@ public final class FileDataSourceFactory implements DataSource.Factory {
}
}
@Override
@Override
public
DataSource
createDataSource
()
{
public
File
DataSource
createDataSource
()
{
FileDataSource
dataSource
=
new
FileDataSource
();
FileDataSource
dataSource
=
new
FileDataSource
();
if
(
listener
!=
null
)
{
if
(
listener
!=
null
)
{
dataSource
.
addTransferListener
(
listener
);
dataSource
.
addTransferListener
(
listener
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/ResolvingDataSource.java
View file @
41b3fc11
...
@@ -64,9 +64,7 @@ public final class ResolvingDataSource implements DataSource {
...
@@ -64,9 +64,7 @@ public final class ResolvingDataSource implements DataSource {
private
final
Resolver
resolver
;
private
final
Resolver
resolver
;
/**
/**
* Creates factory for {@link ResolvingDataSource} instances.
* @param upstreamFactory The wrapped {@link DataSource.Factory} for handling resolved {@link
*
* @param upstreamFactory The wrapped {@link DataSource.Factory} handling the resolved {@link
* DataSpec DataSpecs}.
* DataSpec DataSpecs}.
* @param resolver The {@link Resolver} to resolve the {@link DataSpec DataSpecs}.
* @param resolver The {@link Resolver} to resolve the {@link DataSpec DataSpecs}.
*/
*/
...
@@ -76,7 +74,7 @@ public final class ResolvingDataSource implements DataSource {
...
@@ -76,7 +74,7 @@ public final class ResolvingDataSource implements DataSource {
}
}
@Override
@Override
public
DataSource
createDataSource
()
{
public
Resolving
DataSource
createDataSource
()
{
return
new
ResolvingDataSource
(
upstreamFactory
.
createDataSource
(),
resolver
);
return
new
ResolvingDataSource
(
upstreamFactory
.
createDataSource
(),
resolver
);
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSink.java
View file @
41b3fc11
...
@@ -53,7 +53,6 @@ public final class CacheDataSink implements DataSink {
...
@@ -53,7 +53,6 @@ public final class CacheDataSink implements DataSink {
private
long
dataSpecFragmentSize
;
private
long
dataSpecFragmentSize
;
private
File
file
;
private
File
file
;
private
OutputStream
outputStream
;
private
OutputStream
outputStream
;
private
FileOutputStream
underlyingFileOutputStream
;
private
long
outputStreamBytesWritten
;
private
long
outputStreamBytesWritten
;
private
long
dataSpecBytesWritten
;
private
long
dataSpecBytesWritten
;
private
ReusableBufferedOutputStream
bufferedOutputStream
;
private
ReusableBufferedOutputStream
bufferedOutputStream
;
...
@@ -171,7 +170,7 @@ public final class CacheDataSink implements DataSink {
...
@@ -171,7 +170,7 @@ public final class CacheDataSink implements DataSink {
file
=
file
=
cache
.
startFile
(
cache
.
startFile
(
dataSpec
.
key
,
dataSpec
.
absoluteStreamPosition
+
dataSpecBytesWritten
,
length
);
dataSpec
.
key
,
dataSpec
.
absoluteStreamPosition
+
dataSpecBytesWritten
,
length
);
underlyingFileOutputStream
=
new
FileOutputStream
(
file
);
FileOutputStream
underlyingFileOutputStream
=
new
FileOutputStream
(
file
);
if
(
bufferSize
>
0
)
{
if
(
bufferSize
>
0
)
{
if
(
bufferedOutputStream
==
null
)
{
if
(
bufferedOutputStream
==
null
)
{
bufferedOutputStream
=
new
ReusableBufferedOutputStream
(
underlyingFileOutputStream
,
bufferedOutputStream
=
new
ReusableBufferedOutputStream
(
underlyingFileOutputStream
,
...
...
library/core/src/main/java/com/google/android/exoplayer2/upstream/crypto/AesCipherDataSink.java
View file @
41b3fc11
...
@@ -49,10 +49,11 @@ public final class AesCipherDataSink implements DataSink {
...
@@ -49,10 +49,11 @@ public final class AesCipherDataSink implements DataSink {
*
*
* @param secretKey The key data.
* @param secretKey The key data.
* @param wrappedDataSink The wrapped {@link DataSink}.
* @param wrappedDataSink The wrapped {@link DataSink}.
* @param scratch Scratch space. Data is
de
crypted into this array before being written to the
* @param scratch Scratch space. Data is
en
crypted into this array before being written to the
* wrapped {@link DataSink}. It should be of appropriate size for the expected writes. If a
* wrapped {@link DataSink}. It should be of appropriate size for the expected writes. If a
* write is larger than the size of this array the write will still succeed, but multiple
* write is larger than the size of this array the write will still succeed, but multiple
* cipher calls will be required to complete the operation.
* cipher calls will be required to complete the operation. If {@code null} then encryption
* will overwrite the input {@code data}.
*/
*/
public
AesCipherDataSink
(
byte
[]
secretKey
,
DataSink
wrappedDataSink
,
byte
[]
scratch
)
{
public
AesCipherDataSink
(
byte
[]
secretKey
,
DataSink
wrappedDataSink
,
byte
[]
scratch
)
{
this
.
wrappedDataSink
=
wrappedDataSink
;
this
.
wrappedDataSink
=
wrappedDataSink
;
...
@@ -91,5 +92,4 @@ public final class AesCipherDataSink implements DataSink {
...
@@ -91,5 +92,4 @@ public final class AesCipherDataSink implements DataSink {
cipher
=
null
;
cipher
=
null
;
wrappedDataSink
.
close
();
wrappedDataSink
.
close
();
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/util/GlUtil.java
View file @
41b3fc11
...
@@ -42,7 +42,7 @@ public final class GlUtil {
...
@@ -42,7 +42,7 @@ public final class GlUtil {
int
lastError
=
GLES20
.
GL_NO_ERROR
;
int
lastError
=
GLES20
.
GL_NO_ERROR
;
int
error
;
int
error
;
while
((
error
=
GLES20
.
glGetError
())
!=
GLES20
.
GL_NO_ERROR
)
{
while
((
error
=
GLES20
.
glGetError
())
!=
GLES20
.
GL_NO_ERROR
)
{
Log
.
e
(
TAG
,
"glError "
+
gluErrorString
(
lastE
rror
));
Log
.
e
(
TAG
,
"glError "
+
gluErrorString
(
e
rror
));
lastError
=
error
;
lastError
=
error
;
}
}
if
(
ExoPlayerLibraryInfo
.
GL_ASSERTIONS_ENABLED
&&
lastError
!=
GLES20
.
GL_NO_ERROR
)
{
if
(
ExoPlayerLibraryInfo
.
GL_ASSERTIONS_ENABLED
&&
lastError
!=
GLES20
.
GL_NO_ERROR
)
{
...
...
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
View file @
41b3fc11
...
@@ -63,6 +63,7 @@ import java.util.Arrays;
...
@@ -63,6 +63,7 @@ import java.util.Arrays;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicLong
;
import
java.util.concurrent.atomic.AtomicLong
;
import
java.util.concurrent.atomic.AtomicReference
;
import
java.util.concurrent.atomic.AtomicReference
;
...
@@ -2659,6 +2660,34 @@ public final class ExoPlayerTest {
...
@@ -2659,6 +2660,34 @@ public final class ExoPlayerTest {
assertThat
(
contentStartPositionMs
.
get
()).
isAtLeast
(
5_000L
);
assertThat
(
contentStartPositionMs
.
get
()).
isAtLeast
(
5_000L
);
}
}
@Test
public
void
simplePlaybackHasNoPlaybackSuppression
()
throws
Exception
{
ActionSchedule
actionSchedule
=
new
ActionSchedule
.
Builder
(
"simplePlaybackHasNoPlaybackSuppression"
)
.
play
()
.
waitForPlaybackState
(
Player
.
STATE_READY
)
.
pause
()
.
play
()
.
build
();
AtomicBoolean
seenPlaybackSuppression
=
new
AtomicBoolean
();
EventListener
listener
=
new
EventListener
()
{
@Override
public
void
onPlaybackSuppressionReasonChanged
(
@Player
.
PlaybackSuppressionReason
int
playbackSuppressionReason
)
{
seenPlaybackSuppression
.
set
(
true
);
}
};
new
ExoPlayerTestRunner
.
Builder
()
.
setActionSchedule
(
actionSchedule
)
.
setEventListener
(
listener
)
.
build
(
context
)
.
start
()
.
blockUntilEnded
(
TIMEOUT_MS
);
assertThat
(
seenPlaybackSuppression
.
get
()).
isFalse
();
}
// Internal methods.
// Internal methods.
private
static
ActionSchedule
.
Builder
addSurfaceSwitch
(
ActionSchedule
.
Builder
builder
)
{
private
static
ActionSchedule
.
Builder
addSurfaceSwitch
(
ActionSchedule
.
Builder
builder
)
{
...
...
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyDecoderTest.java
View file @
41b3fc11
...
@@ -29,10 +29,12 @@ public final class IcyDecoderTest {
...
@@ -29,10 +29,12 @@ public final class IcyDecoderTest {
@Test
@Test
public
void
decode
()
{
public
void
decode
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test title';StreamURL='test_url';"
);
String
icyContent
=
"StreamTitle='test title';StreamURL='test_url';"
;
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
}
...
@@ -40,21 +42,39 @@ public final class IcyDecoderTest {
...
@@ -40,21 +42,39 @@ public final class IcyDecoderTest {
@Test
@Test
public
void
decode_titleOnly
()
{
public
void
decode_titleOnly
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test title';"
);
String
icyContent
=
"StreamTitle='test title';"
;
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
url
).
isNull
();
assertThat
(
streamInfo
.
url
).
isNull
();
}
}
@Test
@Test
public
void
decode_extraTags
()
{
String
icyContent
=
"StreamTitle='test title';StreamURL='test_url';CustomTag|withWeirdSeparator"
;
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
@Test
public
void
decode_emptyTitle
()
{
public
void
decode_emptyTitle
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='';StreamURL='test_url';"
);
String
icyContent
=
"StreamTitle='';StreamURL='test_url';"
;
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEmpty
();
assertThat
(
streamInfo
.
title
).
isEmpty
();
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
}
...
@@ -62,10 +82,12 @@ public final class IcyDecoderTest {
...
@@ -62,10 +82,12 @@ public final class IcyDecoderTest {
@Test
@Test
public
void
decode_semiColonInTitle
()
{
public
void
decode_semiColonInTitle
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test; title';StreamURL='test_url';"
);
String
icyContent
=
"StreamTitle='test; title';StreamURL='test_url';"
;
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test; title"
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test; title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
}
...
@@ -73,10 +95,12 @@ public final class IcyDecoderTest {
...
@@ -73,10 +95,12 @@ public final class IcyDecoderTest {
@Test
@Test
public
void
decode_quoteInTitle
()
{
public
void
decode_quoteInTitle
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test' title';StreamURL='test_url';"
);
String
icyContent
=
"StreamTitle='test' title';StreamURL='test_url';"
;
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test' title"
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test' title"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
}
...
@@ -84,19 +108,25 @@ public final class IcyDecoderTest {
...
@@ -84,19 +108,25 @@ public final class IcyDecoderTest {
@Test
@Test
public
void
decode_lineTerminatorInTitle
()
{
public
void
decode_lineTerminatorInTitle
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"StreamTitle='test\r\ntitle';StreamURL='test_url';"
);
String
icyContent
=
"StreamTitle='test\r\ntitle';StreamURL='test_url';"
;
Metadata
metadata
=
decoder
.
decode
(
icyContent
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
icyContent
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test\r\ntitle"
);
assertThat
(
streamInfo
.
title
).
isEqualTo
(
"test\r\ntitle"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
assertThat
(
streamInfo
.
url
).
isEqualTo
(
"test_url"
);
}
}
@Test
@Test
public
void
decode_no
tIcy
()
{
public
void
decode_no
ReconisedHeaders
()
{
IcyDecoder
decoder
=
new
IcyDecoder
();
IcyDecoder
decoder
=
new
IcyDecoder
();
Metadata
metadata
=
decoder
.
decode
(
"NotIcyData"
);
Metadata
metadata
=
decoder
.
decode
(
"NotIcyData"
);
assertThat
(
metadata
).
isNull
();
assertThat
(
metadata
.
length
()).
isEqualTo
(
1
);
IcyInfo
streamInfo
=
(
IcyInfo
)
metadata
.
get
(
0
);
assertThat
(
streamInfo
.
rawMetadata
).
isEqualTo
(
"NotIcyData"
);
assertThat
(
streamInfo
.
title
).
isNull
();
assertThat
(
streamInfo
.
url
).
isNull
();
}
}
}
}
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/Icy
Stream
InfoTest.java
→
library/core/src/test/java/com/google/android/exoplayer2/metadata/icy/IcyInfoTest.java
View file @
41b3fc11
...
@@ -24,11 +24,11 @@ import org.junit.runner.RunWith;
...
@@ -24,11 +24,11 @@ import org.junit.runner.RunWith;
/** Test for {@link IcyInfo}. */
/** Test for {@link IcyInfo}. */
@RunWith
(
AndroidJUnit4
.
class
)
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
Icy
Stream
InfoTest
{
public
final
class
IcyInfoTest
{
@Test
@Test
public
void
parcelEquals
()
{
public
void
parcelEquals
()
{
IcyInfo
streamInfo
=
new
IcyInfo
(
"name"
,
"url"
);
IcyInfo
streamInfo
=
new
IcyInfo
(
"
StreamName='name';StreamUrl='url'"
,
"
name"
,
"url"
);
// Write to parcel.
// Write to parcel.
Parcel
parcel
=
Parcel
.
obtain
();
Parcel
parcel
=
Parcel
.
obtain
();
streamInfo
.
writeToParcel
(
parcel
,
0
);
streamInfo
.
writeToParcel
(
parcel
,
0
);
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
View file @
41b3fc11
...
@@ -686,7 +686,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -686,7 +686,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
newPeriodDurationUs
,
newRepresentation
,
extractorWrapper
,
segmentNumShift
,
newIndex
);
newPeriodDurationUs
,
newRepresentation
,
extractorWrapper
,
segmentNumShift
,
newIndex
);
}
}
long
oldIndexLastSegmentNum
=
oldIndex
.
getFirstSegmentNum
()
+
oldIndexSegmentCount
-
1
;
long
oldIndexFirstSegmentNum
=
oldIndex
.
getFirstSegmentNum
();
long
oldIndexStartTimeUs
=
oldIndex
.
getTimeUs
(
oldIndexFirstSegmentNum
);
long
oldIndexLastSegmentNum
=
oldIndexFirstSegmentNum
+
oldIndexSegmentCount
-
1
;
long
oldIndexEndTimeUs
=
long
oldIndexEndTimeUs
=
oldIndex
.
getTimeUs
(
oldIndexLastSegmentNum
)
oldIndex
.
getTimeUs
(
oldIndexLastSegmentNum
)
+
oldIndex
.
getDurationUs
(
oldIndexLastSegmentNum
,
newPeriodDurationUs
);
+
oldIndex
.
getDurationUs
(
oldIndexLastSegmentNum
,
newPeriodDurationUs
);
...
@@ -700,8 +702,14 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -700,8 +702,14 @@ public class DefaultDashChunkSource implements DashChunkSource {
// There's a gap between the old index and the new one which means we've slipped behind the
// There's a gap between the old index and the new one which means we've slipped behind the
// live window and can't proceed.
// live window and can't proceed.
throw
new
BehindLiveWindowException
();
throw
new
BehindLiveWindowException
();
}
else
if
(
newIndexStartTimeUs
<
oldIndexStartTimeUs
)
{
// The new index overlaps with (but does not have a start position contained within) the old
// index. This can only happen if extra segments have been added to the start of the index.
newSegmentNumShift
-=
newIndex
.
getSegmentNum
(
oldIndexStartTimeUs
,
newPeriodDurationUs
)
-
oldIndexFirstSegmentNum
;
}
else
{
}
else
{
// The new index overlaps with
the old one
.
// The new index overlaps with
(and has a start position contained within) the old index
.
newSegmentNumShift
+=
newSegmentNumShift
+=
oldIndex
.
getSegmentNum
(
newIndexStartTimeUs
,
newPeriodDurationUs
)
oldIndex
.
getSegmentNum
(
newIndexStartTimeUs
,
newPeriodDurationUs
)
-
newIndexFirstSegmentNum
;
-
newIndexFirstSegmentNum
;
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
View file @
41b3fc11
...
@@ -313,7 +313,6 @@ public class DashManifestParser extends DefaultHandler
...
@@ -313,7 +313,6 @@ public class DashManifestParser extends DefaultHandler
parseRepresentation
(
parseRepresentation
(
xpp
,
xpp
,
baseUrl
,
baseUrl
,
label
,
mimeType
,
mimeType
,
codecs
,
codecs
,
width
,
width
,
...
@@ -338,6 +337,8 @@ public class DashManifestParser extends DefaultHandler
...
@@ -338,6 +337,8 @@ public class DashManifestParser extends DefaultHandler
parseSegmentTemplate
(
xpp
,
(
SegmentTemplate
)
segmentBase
,
supplementalProperties
);
parseSegmentTemplate
(
xpp
,
(
SegmentTemplate
)
segmentBase
,
supplementalProperties
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"InbandEventStream"
))
{
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"InbandEventStream"
))
{
inbandEventStreams
.
add
(
parseDescriptor
(
xpp
,
"InbandEventStream"
));
inbandEventStreams
.
add
(
parseDescriptor
(
xpp
,
"InbandEventStream"
));
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
,
"Label"
))
{
label
=
parseLabel
(
xpp
);
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
))
{
}
else
if
(
XmlPullParserUtil
.
isStartTag
(
xpp
))
{
parseAdaptationSetChild
(
xpp
);
parseAdaptationSetChild
(
xpp
);
}
}
...
@@ -348,7 +349,11 @@ public class DashManifestParser extends DefaultHandler
...
@@ -348,7 +349,11 @@ public class DashManifestParser extends DefaultHandler
for
(
int
i
=
0
;
i
<
representationInfos
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
representationInfos
.
size
();
i
++)
{
representations
.
add
(
representations
.
add
(
buildRepresentation
(
buildRepresentation
(
representationInfos
.
get
(
i
),
drmSchemeType
,
drmSchemeDatas
,
inbandEventStreams
));
representationInfos
.
get
(
i
),
label
,
drmSchemeType
,
drmSchemeDatas
,
inbandEventStreams
));
}
}
return
buildAdaptationSet
(
id
,
contentType
,
representations
,
accessibilityDescriptors
,
return
buildAdaptationSet
(
id
,
contentType
,
representations
,
accessibilityDescriptors
,
...
@@ -484,7 +489,6 @@ public class DashManifestParser extends DefaultHandler
...
@@ -484,7 +489,6 @@ public class DashManifestParser extends DefaultHandler
protected
RepresentationInfo
parseRepresentation
(
protected
RepresentationInfo
parseRepresentation
(
XmlPullParser
xpp
,
XmlPullParser
xpp
,
String
baseUrl
,
String
baseUrl
,
String
label
,
String
adaptationSetMimeType
,
String
adaptationSetMimeType
,
String
adaptationSetCodecs
,
String
adaptationSetCodecs
,
int
adaptationSetWidth
,
int
adaptationSetWidth
,
...
@@ -551,7 +555,6 @@ public class DashManifestParser extends DefaultHandler
...
@@ -551,7 +555,6 @@ public class DashManifestParser extends DefaultHandler
Format
format
=
Format
format
=
buildFormat
(
buildFormat
(
id
,
id
,
label
,
mimeType
,
mimeType
,
width
,
width
,
height
,
height
,
...
@@ -572,7 +575,6 @@ public class DashManifestParser extends DefaultHandler
...
@@ -572,7 +575,6 @@ public class DashManifestParser extends DefaultHandler
protected
Format
buildFormat
(
protected
Format
buildFormat
(
String
id
,
String
id
,
String
label
,
String
containerMimeType
,
String
containerMimeType
,
int
width
,
int
width
,
int
height
,
int
height
,
...
@@ -596,7 +598,7 @@ public class DashManifestParser extends DefaultHandler
...
@@ -596,7 +598,7 @@ public class DashManifestParser extends DefaultHandler
if
(
MimeTypes
.
isVideo
(
sampleMimeType
))
{
if
(
MimeTypes
.
isVideo
(
sampleMimeType
))
{
return
Format
.
createVideoContainerFormat
(
return
Format
.
createVideoContainerFormat
(
id
,
id
,
labe
l
,
/* label= */
nul
l
,
containerMimeType
,
containerMimeType
,
sampleMimeType
,
sampleMimeType
,
codecs
,
codecs
,
...
@@ -611,7 +613,7 @@ public class DashManifestParser extends DefaultHandler
...
@@ -611,7 +613,7 @@ public class DashManifestParser extends DefaultHandler
}
else
if
(
MimeTypes
.
isAudio
(
sampleMimeType
))
{
}
else
if
(
MimeTypes
.
isAudio
(
sampleMimeType
))
{
return
Format
.
createAudioContainerFormat
(
return
Format
.
createAudioContainerFormat
(
id
,
id
,
labe
l
,
/* label= */
nul
l
,
containerMimeType
,
containerMimeType
,
sampleMimeType
,
sampleMimeType
,
codecs
,
codecs
,
...
@@ -634,7 +636,7 @@ public class DashManifestParser extends DefaultHandler
...
@@ -634,7 +636,7 @@ public class DashManifestParser extends DefaultHandler
}
}
return
Format
.
createTextContainerFormat
(
return
Format
.
createTextContainerFormat
(
id
,
id
,
labe
l
,
/* label= */
nul
l
,
containerMimeType
,
containerMimeType
,
sampleMimeType
,
sampleMimeType
,
codecs
,
codecs
,
...
@@ -647,7 +649,7 @@ public class DashManifestParser extends DefaultHandler
...
@@ -647,7 +649,7 @@ public class DashManifestParser extends DefaultHandler
}
}
return
Format
.
createContainerFormat
(
return
Format
.
createContainerFormat
(
id
,
id
,
labe
l
,
/* label= */
nul
l
,
containerMimeType
,
containerMimeType
,
sampleMimeType
,
sampleMimeType
,
codecs
,
codecs
,
...
@@ -659,10 +661,14 @@ public class DashManifestParser extends DefaultHandler
...
@@ -659,10 +661,14 @@ public class DashManifestParser extends DefaultHandler
protected
Representation
buildRepresentation
(
protected
Representation
buildRepresentation
(
RepresentationInfo
representationInfo
,
RepresentationInfo
representationInfo
,
String
label
,
String
extraDrmSchemeType
,
String
extraDrmSchemeType
,
ArrayList
<
SchemeData
>
extraDrmSchemeDatas
,
ArrayList
<
SchemeData
>
extraDrmSchemeDatas
,
ArrayList
<
Descriptor
>
extraInbandEventStreams
)
{
ArrayList
<
Descriptor
>
extraInbandEventStreams
)
{
Format
format
=
representationInfo
.
format
;
Format
format
=
representationInfo
.
format
;
if
(
label
!=
null
)
{
format
=
format
.
copyWithLabel
(
label
);
}
String
drmSchemeType
=
representationInfo
.
drmSchemeType
!=
null
String
drmSchemeType
=
representationInfo
.
drmSchemeType
!=
null
?
representationInfo
.
drmSchemeType
:
extraDrmSchemeType
;
?
representationInfo
.
drmSchemeType
:
extraDrmSchemeType
;
ArrayList
<
SchemeData
>
drmSchemeDatas
=
representationInfo
.
drmSchemeDatas
;
ArrayList
<
SchemeData
>
drmSchemeDatas
=
representationInfo
.
drmSchemeDatas
;
...
@@ -1076,15 +1082,44 @@ public class DashManifestParser extends DefaultHandler
...
@@ -1076,15 +1082,44 @@ public class DashManifestParser extends DefaultHandler
return
new
ProgramInformation
(
title
,
source
,
copyright
,
moreInformationURL
,
lang
);
return
new
ProgramInformation
(
title
,
source
,
copyright
,
moreInformationURL
,
lang
);
}
}
/**
* Parses a Label element.
*
* @param xpp The parser from which to read.
* @throws XmlPullParserException If an error occurs parsing the element.
* @throws IOException If an error occurs reading the element.
* @return The parsed label.
*/
protected
String
parseLabel
(
XmlPullParser
xpp
)
throws
XmlPullParserException
,
IOException
{
return
parseText
(
xpp
,
"Label"
);
}
/**
* Parses a BaseURL element.
*
* @param xpp The parser from which to read.
* @param parentBaseUrl A base URL for resolving the parsed URL.
* @throws XmlPullParserException If an error occurs parsing the element.
* @throws IOException If an error occurs reading the element.
* @return The parsed and resolved URL.
*/
protected
String
parseBaseUrl
(
XmlPullParser
xpp
,
String
parentBaseUrl
)
throws
XmlPullParserException
,
IOException
{
return
UriUtil
.
resolve
(
parentBaseUrl
,
parseText
(
xpp
,
"BaseURL"
));
}
// AudioChannelConfiguration parsing.
// AudioChannelConfiguration parsing.
protected
int
parseAudioChannelConfiguration
(
XmlPullParser
xpp
)
protected
int
parseAudioChannelConfiguration
(
XmlPullParser
xpp
)
throws
XmlPullParserException
,
IOException
{
throws
XmlPullParserException
,
IOException
{
String
schemeIdUri
=
parseString
(
xpp
,
"schemeIdUri"
,
null
);
String
schemeIdUri
=
parseString
(
xpp
,
"schemeIdUri"
,
null
);
int
audioChannels
=
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
.
equals
(
schemeIdUri
)
int
audioChannels
=
?
parseInt
(
xpp
,
"value"
,
Format
.
NO_VALUE
)
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
.
equals
(
schemeIdUri
)
:
(
"tag:dolby.com,2014:dash:audio_channel_configuration:2011"
.
equals
(
schemeIdUri
)
?
parseInt
(
xpp
,
"value"
,
Format
.
NO_VALUE
)
?
parseDolbyChannelConfiguration
(
xpp
)
:
Format
.
NO_VALUE
);
:
(
"tag:dolby.com,2014:dash:audio_channel_configuration:2011"
.
equals
(
schemeIdUri
)
||
"urn:dolby:dash:audio_channel_configuration:2011"
.
equals
(
schemeIdUri
)
?
parseDolbyChannelConfiguration
(
xpp
)
:
Format
.
NO_VALUE
);
do
{
do
{
xpp
.
next
();
xpp
.
next
();
}
while
(!
XmlPullParserUtil
.
isEndTag
(
xpp
,
"AudioChannelConfiguration"
));
}
while
(!
XmlPullParserUtil
.
isEndTag
(
xpp
,
"AudioChannelConfiguration"
));
...
@@ -1427,10 +1462,18 @@ public class DashManifestParser extends DefaultHandler
...
@@ -1427,10 +1462,18 @@ public class DashManifestParser extends DefaultHandler
}
}
}
}
protected
static
String
parse
BaseUrl
(
XmlPullParser
xpp
,
String
parentBaseUr
l
)
protected
static
String
parse
Text
(
XmlPullParser
xpp
,
String
labe
l
)
throws
XmlPullParserException
,
IOException
{
throws
XmlPullParserException
,
IOException
{
xpp
.
next
();
String
text
=
""
;
return
UriUtil
.
resolve
(
parentBaseUrl
,
xpp
.
getText
());
do
{
xpp
.
next
();
if
(
xpp
.
getEventType
()
==
XmlPullParser
.
TEXT
)
{
text
=
xpp
.
getText
();
}
else
{
maybeSkipTag
(
xpp
);
}
}
while
(!
XmlPullParserUtil
.
isEndTag
(
xpp
,
label
));
return
text
;
}
}
protected
static
int
parseInt
(
XmlPullParser
xpp
,
String
name
,
int
defaultValue
)
{
protected
static
int
parseInt
(
XmlPullParser
xpp
,
String
name
,
int
defaultValue
)
{
...
@@ -1451,7 +1494,8 @@ public class DashManifestParser extends DefaultHandler
...
@@ -1451,7 +1494,8 @@ public class DashManifestParser extends DefaultHandler
/**
/**
* Parses the number of channels from the value attribute of an AudioElementConfiguration with
* Parses the number of channels from the value attribute of an AudioElementConfiguration with
* schemeIdUri "tag:dolby.com,2014:dash:audio_channel_configuration:2011", as defined by table E.5
* schemeIdUri "tag:dolby.com,2014:dash:audio_channel_configuration:2011", as defined by table E.5
* in ETSI TS 102 366.
* in ETSI TS 102 366, or the legacy schemeIdUri
* "urn:dolby:dash:audio_channel_configuration:2011".
*
*
* @param xpp The parser from which to read.
* @param xpp The parser from which to read.
* @return The parsed number of channels, or {@link Format#NO_VALUE} if the channel count could
* @return The parsed number of channels, or {@link Format#NO_VALUE} if the channel count could
...
...
library/dash/src/test/assets/sample_mpd
_1
→
library/dash/src/test/assets/sample_mpd
View file @
41b3fc11
...
@@ -102,4 +102,3 @@ http://www.test.com/vtt
...
@@ -102,4 +102,3 @@ http://www.test.com/vtt
</AdaptationSet>
</AdaptationSet>
</Period>
</Period>
</MPD>
</MPD>
library/dash/src/test/assets/sample_mpd_
4_
event_stream
→
library/dash/src/test/assets/sample_mpd_event_stream
View file @
41b3fc11
...
@@ -44,4 +44,3 @@
...
@@ -44,4 +44,3 @@
</AdaptationSet>
</AdaptationSet>
</Period>
</Period>
</MPD>
</MPD>
library/dash/src/test/assets/sample_mpd_labels
0 → 100644
View file @
41b3fc11
<?xml version="1.0" encoding="UTF-8"?>
<MPD
type=
"static"
duration=
"1s"
mediaPresentationDuration=
"PT1S"
>
<Period>
<SegmentTemplate
startNumber=
"0"
timescale=
"1000"
media=
"sq/$Number$"
>
<SegmentTimeline>
<S
d=
"1000"
/>
</SegmentTimeline>
</SegmentTemplate>
<AdaptationSet
id=
"0"
mimeType=
"audio/mp4"
subsegmentAlignment=
"true"
label=
"audio label"
>
<Representation
id=
"0"
codecs=
"mp4a.40.2"
audioSamplingRate=
"48000"
bandwidth=
"144000"
>
<BaseURL>
https://test.com/0
</BaseURL>
</Representation>
</AdaptationSet>
<AdaptationSet
id=
"1"
mimeType=
"video/mp4"
subsegmentAlignment=
"true"
label=
"ignored label"
>
<Representation
id=
"1"
codecs=
"avc1.4d4015"
width=
"426"
height=
"240"
bandwidth=
"258000"
>
<BaseURL>
https://test.com/1
</BaseURL>
</Representation>
<Label>
video label
</Label>
</AdaptationSet>
</Period>
</MPD>
library/dash/src/test/assets/sample_mpd_
3_
segment_template
→
library/dash/src/test/assets/sample_mpd_segment_template
View file @
41b3fc11
...
@@ -35,4 +35,3 @@
...
@@ -35,4 +35,3 @@
</AdaptationSet>
</AdaptationSet>
</Period>
</Period>
</MPD>
</MPD>
library/dash/src/test/assets/sample_mpd_
2_
unknown_mime_type
→
library/dash/src/test/assets/sample_mpd_unknown_mime_type
View file @
41b3fc11
...
@@ -115,4 +115,3 @@ http://www.test.com/vtt
...
@@ -115,4 +115,3 @@ http://www.test.com/vtt
</AdaptationSet>
</AdaptationSet>
</Period>
</Period>
</MPD>
</MPD>
library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
View file @
41b3fc11
...
@@ -26,42 +26,49 @@ import com.google.android.exoplayer2.metadata.emsg.EventMessage;
...
@@ -26,42 +26,49 @@ import com.google.android.exoplayer2.metadata.emsg.EventMessage;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.StringReader
;
import
java.nio.charset.Charset
;
import
java.nio.charset.Charset
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.xmlpull.v1.XmlPullParser
;
import
org.xmlpull.v1.XmlPullParserFactory
;
/** Unit tests for {@link DashManifestParser}. */
/** Unit tests for {@link DashManifestParser}. */
@RunWith
(
AndroidJUnit4
.
class
)
@RunWith
(
AndroidJUnit4
.
class
)
public
class
DashManifestParserTest
{
public
class
DashManifestParserTest
{
private
static
final
String
SAMPLE_MPD_1
=
"sample_mpd_1"
;
private
static
final
String
SAMPLE_MPD
=
"sample_mpd"
;
private
static
final
String
SAMPLE_MPD_2_UNKNOWN_MIME_TYPE
=
"sample_mpd_2_unknown_mime_type"
;
private
static
final
String
SAMPLE_MPD_UNKNOWN_MIME_TYPE
=
"sample_mpd_unknown_mime_type"
;
private
static
final
String
SAMPLE_MPD_3_SEGMENT_TEMPLATE
=
"sample_mpd_3_segment_template"
;
private
static
final
String
SAMPLE_MPD_SEGMENT_TEMPLATE
=
"sample_mpd_segment_template"
;
private
static
final
String
SAMPLE_MPD_4_EVENT_STREAM
=
"sample_mpd_4_event_stream"
;
private
static
final
String
SAMPLE_MPD_EVENT_STREAM
=
"sample_mpd_event_stream"
;
private
static
final
String
SAMPLE_MPD_LABELS
=
"sample_mpd_labels"
;
private
static
final
String
NEXT_TAG_NAME
=
"Next"
;
private
static
final
String
NEXT_TAG
=
"<"
+
NEXT_TAG_NAME
+
"/>"
;
/** Simple test to ensure the sample manifests parse without any exceptions being thrown. */
/** Simple test to ensure the sample manifests parse without any exceptions being thrown. */
@Test
@Test
public
void
testP
arseMediaPresentationDescription
()
throws
IOException
{
public
void
p
arseMediaPresentationDescription
()
throws
IOException
{
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifestParser
parser
=
new
DashManifestParser
();
parser
.
parse
(
parser
.
parse
(
Uri
.
parse
(
"https://example.com/test.mpd"
),
Uri
.
parse
(
"https://example.com/test.mpd"
),
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD
_1
));
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD
));
parser
.
parse
(
parser
.
parse
(
Uri
.
parse
(
"https://example.com/test.mpd"
),
Uri
.
parse
(
"https://example.com/test.mpd"
),
TestUtil
.
getInputStream
(
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_
2_
UNKNOWN_MIME_TYPE
));
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_UNKNOWN_MIME_TYPE
));
}
}
@Test
@Test
public
void
testParseMediaPresentationDescriptionWithS
egmentTemplate
()
throws
IOException
{
public
void
parseMediaPresentationDescription_s
egmentTemplate
()
throws
IOException
{
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifest
mpd
=
DashManifest
mpd
=
parser
.
parse
(
parser
.
parse
(
Uri
.
parse
(
"https://example.com/test.mpd"
),
Uri
.
parse
(
"https://example.com/test.mpd"
),
TestUtil
.
getInputStream
(
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_
3_
SEGMENT_TEMPLATE
));
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_SEGMENT_TEMPLATE
));
assertThat
(
mpd
.
getPeriodCount
()).
isEqualTo
(
1
);
assertThat
(
mpd
.
getPeriodCount
()).
isEqualTo
(
1
);
...
@@ -87,13 +94,13 @@ public class DashManifestParserTest {
...
@@ -87,13 +94,13 @@ public class DashManifestParserTest {
}
}
@Test
@Test
public
void
testParseMediaPresentationDescriptionCanParseE
ventStream
()
throws
IOException
{
public
void
parseMediaPresentationDescription_e
ventStream
()
throws
IOException
{
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifest
mpd
=
DashManifest
mpd
=
parser
.
parse
(
parser
.
parse
(
Uri
.
parse
(
"https://example.com/test.mpd"
),
Uri
.
parse
(
"https://example.com/test.mpd"
),
TestUtil
.
getInputStream
(
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_
4_
EVENT_STREAM
));
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_EVENT_STREAM
));
Period
period
=
mpd
.
getPeriod
(
0
);
Period
period
=
mpd
.
getPeriod
(
0
);
assertThat
(
period
.
eventStreams
).
hasSize
(
3
);
assertThat
(
period
.
eventStreams
).
hasSize
(
3
);
...
@@ -157,12 +164,12 @@ public class DashManifestParserTest {
...
@@ -157,12 +164,12 @@ public class DashManifestParserTest {
}
}
@Test
@Test
public
void
testParseMediaPresentationDescriptionCanParseP
rogramInformation
()
throws
IOException
{
public
void
parseMediaPresentationDescription_p
rogramInformation
()
throws
IOException
{
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifest
mpd
=
DashManifest
mpd
=
parser
.
parse
(
parser
.
parse
(
Uri
.
parse
(
"Https://example.com/test.mpd"
),
Uri
.
parse
(
"Https://example.com/test.mpd"
),
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD
_1
));
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD
));
ProgramInformation
expectedProgramInformation
=
ProgramInformation
expectedProgramInformation
=
new
ProgramInformation
(
new
ProgramInformation
(
"MediaTitle"
,
"MediaSource"
,
"MediaCopyright"
,
"www.example.com"
,
"enUs"
);
"MediaTitle"
,
"MediaSource"
,
"MediaCopyright"
,
"www.example.com"
,
"enUs"
);
...
@@ -170,7 +177,46 @@ public class DashManifestParserTest {
...
@@ -170,7 +177,46 @@ public class DashManifestParserTest {
}
}
@Test
@Test
public
void
testParseCea608AccessibilityChannel
()
{
public
void
parseMediaPresentationDescription_labels
()
throws
IOException
{
DashManifestParser
parser
=
new
DashManifestParser
();
DashManifest
manifest
=
parser
.
parse
(
Uri
.
parse
(
"https://example.com/test.mpd"
),
TestUtil
.
getInputStream
(
ApplicationProvider
.
getApplicationContext
(),
SAMPLE_MPD_LABELS
));
List
<
AdaptationSet
>
adaptationSets
=
manifest
.
getPeriod
(
0
).
adaptationSets
;
assertThat
(
adaptationSets
.
get
(
0
).
representations
.
get
(
0
).
format
.
label
).
isEqualTo
(
"audio label"
);
assertThat
(
adaptationSets
.
get
(
1
).
representations
.
get
(
0
).
format
.
label
).
isEqualTo
(
"video label"
);
}
@Test
public
void
parseLabel
()
throws
Exception
{
DashManifestParser
parser
=
new
DashManifestParser
();
XmlPullParser
xpp
=
XmlPullParserFactory
.
newInstance
().
newPullParser
();
xpp
.
setInput
(
new
StringReader
(
"<Label>test label</Label>"
+
NEXT_TAG
));
xpp
.
next
();
String
label
=
parser
.
parseLabel
(
xpp
);
assertThat
(
label
).
isEqualTo
(
"test label"
);
assertNextTag
(
xpp
);
}
@Test
public
void
parseLabel_noText
()
throws
Exception
{
DashManifestParser
parser
=
new
DashManifestParser
();
XmlPullParser
xpp
=
XmlPullParserFactory
.
newInstance
().
newPullParser
();
xpp
.
setInput
(
new
StringReader
(
"<Label/>"
+
NEXT_TAG
));
xpp
.
next
();
String
label
=
parser
.
parseLabel
(
xpp
);
assertThat
(
label
).
isEqualTo
(
""
);
assertNextTag
(
xpp
);
}
@Test
public
void
parseCea608AccessibilityChannel
()
{
assertThat
(
assertThat
(
DashManifestParser
.
parseCea608AccessibilityChannel
(
DashManifestParser
.
parseCea608AccessibilityChannel
(
buildCea608AccessibilityDescriptors
(
"CC1=eng"
)))
buildCea608AccessibilityDescriptors
(
"CC1=eng"
)))
...
@@ -211,7 +257,7 @@ public class DashManifestParserTest {
...
@@ -211,7 +257,7 @@ public class DashManifestParserTest {
}
}
@Test
@Test
public
void
testP
arseCea708AccessibilityChannel
()
{
public
void
p
arseCea708AccessibilityChannel
()
{
assertThat
(
assertThat
(
DashManifestParser
.
parseCea708AccessibilityChannel
(
DashManifestParser
.
parseCea708AccessibilityChannel
(
buildCea708AccessibilityDescriptors
(
"1=lang:eng"
)))
buildCea708AccessibilityDescriptors
(
"1=lang:eng"
)))
...
@@ -262,4 +308,10 @@ public class DashManifestParserTest {
...
@@ -262,4 +308,10 @@ public class DashManifestParserTest {
private
static
List
<
Descriptor
>
buildCea708AccessibilityDescriptors
(
String
value
)
{
private
static
List
<
Descriptor
>
buildCea708AccessibilityDescriptors
(
String
value
)
{
return
Collections
.
singletonList
(
new
Descriptor
(
"urn:scte:dash:cc:cea-708:2015"
,
value
,
null
));
return
Collections
.
singletonList
(
new
Descriptor
(
"urn:scte:dash:cc:cea-708:2015"
,
value
,
null
));
}
}
private
static
void
assertNextTag
(
XmlPullParser
xpp
)
throws
Exception
{
xpp
.
next
();
assertThat
(
xpp
.
getEventType
()).
isEqualTo
(
XmlPullParser
.
START_TAG
);
assertThat
(
xpp
.
getName
()).
isEqualTo
(
NEXT_TAG_NAME
);
}
}
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java
View file @
41b3fc11
...
@@ -29,6 +29,7 @@ import com.google.android.exoplayer2.extractor.ts.Ac4Extractor;
...
@@ -29,6 +29,7 @@ import com.google.android.exoplayer2.extractor.ts.Ac4Extractor;
import
com.google.android.exoplayer2.extractor.ts.AdtsExtractor
;
import
com.google.android.exoplayer2.extractor.ts.AdtsExtractor
;
import
com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory
;
import
com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory
;
import
com.google.android.exoplayer2.extractor.ts.TsExtractor
;
import
com.google.android.exoplayer2.extractor.ts.TsExtractor
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
java.io.EOFException
;
import
java.io.EOFException
;
...
@@ -158,7 +159,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
...
@@ -158,7 +159,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
if
(!(
extractorByFileExtension
instanceof
FragmentedMp4Extractor
))
{
if
(!(
extractorByFileExtension
instanceof
FragmentedMp4Extractor
))
{
FragmentedMp4Extractor
fragmentedMp4Extractor
=
FragmentedMp4Extractor
fragmentedMp4Extractor
=
createFragmentedMp4Extractor
(
timestampAdjuster
,
drmInitData
,
muxedCaptionFormats
);
createFragmentedMp4Extractor
(
timestampAdjuster
,
format
,
drmInitData
,
muxedCaptionFormats
);
if
(
sniffQuietly
(
fragmentedMp4Extractor
,
extractorInput
))
{
if
(
sniffQuietly
(
fragmentedMp4Extractor
,
extractorInput
))
{
return
buildResult
(
fragmentedMp4Extractor
);
return
buildResult
(
fragmentedMp4Extractor
);
}
}
...
@@ -208,7 +209,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
...
@@ -208,7 +209,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
||
lastPathSegment
.
startsWith
(
M4_FILE_EXTENSION_PREFIX
,
lastPathSegment
.
length
()
-
4
)
||
lastPathSegment
.
startsWith
(
M4_FILE_EXTENSION_PREFIX
,
lastPathSegment
.
length
()
-
4
)
||
lastPathSegment
.
startsWith
(
MP4_FILE_EXTENSION_PREFIX
,
lastPathSegment
.
length
()
-
5
)
||
lastPathSegment
.
startsWith
(
MP4_FILE_EXTENSION_PREFIX
,
lastPathSegment
.
length
()
-
5
)
||
lastPathSegment
.
startsWith
(
CMF_FILE_EXTENSION_PREFIX
,
lastPathSegment
.
length
()
-
5
))
{
||
lastPathSegment
.
startsWith
(
CMF_FILE_EXTENSION_PREFIX
,
lastPathSegment
.
length
()
-
5
))
{
return
createFragmentedMp4Extractor
(
timestampAdjuster
,
drmInitData
,
muxedCaptionFormats
);
return
createFragmentedMp4Extractor
(
timestampAdjuster
,
format
,
drmInitData
,
muxedCaptionFormats
);
}
else
{
}
else
{
// For any other file extension, we assume TS format.
// For any other file extension, we assume TS format.
return
createTsExtractor
(
return
createTsExtractor
(
...
@@ -267,10 +269,21 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
...
@@ -267,10 +269,21 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
private
static
FragmentedMp4Extractor
createFragmentedMp4Extractor
(
private
static
FragmentedMp4Extractor
createFragmentedMp4Extractor
(
TimestampAdjuster
timestampAdjuster
,
TimestampAdjuster
timestampAdjuster
,
Format
format
,
DrmInitData
drmInitData
,
DrmInitData
drmInitData
,
@Nullable
List
<
Format
>
muxedCaptionFormats
)
{
@Nullable
List
<
Format
>
muxedCaptionFormats
)
{
boolean
isVariant
=
false
;
for
(
int
i
=
0
;
i
<
format
.
metadata
.
length
();
i
++)
{
Metadata
.
Entry
entry
=
format
.
metadata
.
get
(
i
);
if
(
entry
instanceof
HlsTrackMetadataEntry
)
{
isVariant
=
!((
HlsTrackMetadataEntry
)
entry
).
variantInfos
.
isEmpty
();
break
;
}
}
// Only enable the EMSG TrackOutput if this is the 'variant' track (i.e. the main one) to avoid
// creating a separate EMSG track for every audio track in a video stream.
return
new
FragmentedMp4Extractor
(
return
new
FragmentedMp4Extractor
(
/* flags= */
0
,
/* flags= */
isVariant
?
FragmentedMp4Extractor
.
FLAG_ENABLE_EMSG_TRACK
:
0
,
timestampAdjuster
,
timestampAdjuster
,
/* sideloadedTrack= */
null
,
/* sideloadedTrack= */
null
,
drmInitData
,
drmInitData
,
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
View file @
41b3fc11
...
@@ -71,6 +71,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
...
@@ -71,6 +71,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
private
final
TimestampAdjusterProvider
timestampAdjusterProvider
;
private
final
TimestampAdjusterProvider
timestampAdjusterProvider
;
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
final
boolean
allowChunklessPreparation
;
private
final
boolean
allowChunklessPreparation
;
private
final
@HlsMetadataType
int
metadataType
;
private
final
boolean
useSessionKeys
;
private
final
boolean
useSessionKeys
;
private
@Nullable
Callback
callback
;
private
@Nullable
Callback
callback
;
...
@@ -110,6 +111,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
...
@@ -110,6 +111,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
Allocator
allocator
,
Allocator
allocator
,
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
,
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
,
boolean
allowChunklessPreparation
,
boolean
allowChunklessPreparation
,
@HlsMetadataType
int
metadataType
,
boolean
useSessionKeys
)
{
boolean
useSessionKeys
)
{
this
.
extractorFactory
=
extractorFactory
;
this
.
extractorFactory
=
extractorFactory
;
this
.
playlistTracker
=
playlistTracker
;
this
.
playlistTracker
=
playlistTracker
;
...
@@ -120,6 +122,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
...
@@ -120,6 +122,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
this
.
allocator
=
allocator
;
this
.
allocator
=
allocator
;
this
.
compositeSequenceableLoaderFactory
=
compositeSequenceableLoaderFactory
;
this
.
compositeSequenceableLoaderFactory
=
compositeSequenceableLoaderFactory
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
metadataType
=
metadataType
;
this
.
useSessionKeys
=
useSessionKeys
;
this
.
useSessionKeys
=
useSessionKeys
;
compositeSequenceableLoader
=
compositeSequenceableLoader
=
compositeSequenceableLoaderFactory
.
createCompositeSequenceableLoader
();
compositeSequenceableLoaderFactory
.
createCompositeSequenceableLoader
();
...
@@ -736,7 +739,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
...
@@ -736,7 +739,8 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
positionUs
,
positionUs
,
muxedAudioFormat
,
muxedAudioFormat
,
loadErrorHandlingPolicy
,
loadErrorHandlingPolicy
,
eventDispatcher
);
eventDispatcher
,
metadataType
);
}
}
private
static
Map
<
String
,
DrmInitData
>
deriveOverridingDrmInitData
(
private
static
Map
<
String
,
DrmInitData
>
deriveOverridingDrmInitData
(
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
View file @
41b3fc11
...
@@ -67,6 +67,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -67,6 +67,7 @@ public final class HlsMediaSource extends BaseMediaSource
private
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
;
private
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
;
private
boolean
allowChunklessPreparation
;
private
boolean
allowChunklessPreparation
;
@HlsMetadataType
private
int
metadataType
;
private
boolean
useSessionKeys
;
private
boolean
useSessionKeys
;
private
boolean
isCreateCalled
;
private
boolean
isCreateCalled
;
@Nullable
private
Object
tag
;
@Nullable
private
Object
tag
;
...
@@ -95,6 +96,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -95,6 +96,7 @@ public final class HlsMediaSource extends BaseMediaSource
extractorFactory
=
HlsExtractorFactory
.
DEFAULT
;
extractorFactory
=
HlsExtractorFactory
.
DEFAULT
;
loadErrorHandlingPolicy
=
new
DefaultLoadErrorHandlingPolicy
();
loadErrorHandlingPolicy
=
new
DefaultLoadErrorHandlingPolicy
();
compositeSequenceableLoaderFactory
=
new
DefaultCompositeSequenceableLoaderFactory
();
compositeSequenceableLoaderFactory
=
new
DefaultCompositeSequenceableLoaderFactory
();
metadataType
=
HlsMetadataType
.
ID3
;
}
}
/**
/**
...
@@ -238,6 +240,31 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -238,6 +240,31 @@ public final class HlsMediaSource extends BaseMediaSource
}
}
/**
/**
* Sets the type of metadata to extract from the HLS source (defaults to {@link
* HlsMetadataType#ID3}).
*
* <p>HLS supports in-band ID3 in both TS and fMP4 streams, but in the fMP4 case the data is
* wrapped in an EMSG box [<a href="https://aomediacodec.github.io/av1-id3/">spec</a>].
*
* <p>If this is set to {@link HlsMetadataType#ID3} then raw ID3 metadata of will be extracted
* from TS sources. From fMP4 streams EMSGs containing metadata of this type (in the variant
* stream only) will be unwrapped to expose the inner data. All other in-band metadata will be
* dropped.
*
* <p>If this is set to {@link HlsMetadataType#EMSG} then all EMSG data from the fMP4 variant
* stream will be extracted. No metadata will be extracted from TS streams, since they don't
* support EMSG.
*
* @param metadataType The type of metadata to extract.
* @return This factory, for convenience.
*/
public
Factory
setMetadataType
(
@HlsMetadataType
int
metadataType
)
{
Assertions
.
checkState
(!
isCreateCalled
);
this
.
metadataType
=
metadataType
;
return
this
;
}
/**
* Sets whether to use #EXT-X-SESSION-KEY tags provided in the master playlist. If enabled, it's
* Sets whether to use #EXT-X-SESSION-KEY tags provided in the master playlist. If enabled, it's
* assumed that any single session key declared in the master playlist can be used to obtain all
* assumed that any single session key declared in the master playlist can be used to obtain all
* of the keys required for playback. For media where this is not true, this option should not
* of the keys required for playback. For media where this is not true, this option should not
...
@@ -272,6 +299,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -272,6 +299,7 @@ public final class HlsMediaSource extends BaseMediaSource
playlistTrackerFactory
.
createTracker
(
playlistTrackerFactory
.
createTracker
(
hlsDataSourceFactory
,
loadErrorHandlingPolicy
,
playlistParserFactory
),
hlsDataSourceFactory
,
loadErrorHandlingPolicy
,
playlistParserFactory
),
allowChunklessPreparation
,
allowChunklessPreparation
,
metadataType
,
useSessionKeys
,
useSessionKeys
,
tag
);
tag
);
}
}
...
@@ -305,6 +333,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -305,6 +333,7 @@ public final class HlsMediaSource extends BaseMediaSource
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
final
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
;
private
final
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
;
private
final
boolean
allowChunklessPreparation
;
private
final
boolean
allowChunklessPreparation
;
private
final
@HlsMetadataType
int
metadataType
;
private
final
boolean
useSessionKeys
;
private
final
boolean
useSessionKeys
;
private
final
HlsPlaylistTracker
playlistTracker
;
private
final
HlsPlaylistTracker
playlistTracker
;
private
final
@Nullable
Object
tag
;
private
final
@Nullable
Object
tag
;
...
@@ -319,6 +348,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -319,6 +348,7 @@ public final class HlsMediaSource extends BaseMediaSource
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
,
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
,
HlsPlaylistTracker
playlistTracker
,
HlsPlaylistTracker
playlistTracker
,
boolean
allowChunklessPreparation
,
boolean
allowChunklessPreparation
,
@HlsMetadataType
int
metadataType
,
boolean
useSessionKeys
,
boolean
useSessionKeys
,
@Nullable
Object
tag
)
{
@Nullable
Object
tag
)
{
this
.
manifestUri
=
manifestUri
;
this
.
manifestUri
=
manifestUri
;
...
@@ -328,6 +358,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -328,6 +358,7 @@ public final class HlsMediaSource extends BaseMediaSource
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
playlistTracker
=
playlistTracker
;
this
.
playlistTracker
=
playlistTracker
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
metadataType
=
metadataType
;
this
.
useSessionKeys
=
useSessionKeys
;
this
.
useSessionKeys
=
useSessionKeys
;
this
.
tag
=
tag
;
this
.
tag
=
tag
;
}
}
...
@@ -363,6 +394,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -363,6 +394,7 @@ public final class HlsMediaSource extends BaseMediaSource
allocator
,
allocator
,
compositeSequenceableLoaderFactory
,
compositeSequenceableLoaderFactory
,
allowChunklessPreparation
,
allowChunklessPreparation
,
metadataType
,
useSessionKeys
);
useSessionKeys
);
}
}
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMetadataType.java
0 → 100644
View file @
41b3fc11
/*
* Copyright (C) 2019 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
.
hls
;
import
static
java
.
lang
.
annotation
.
RetentionPolicy
.
SOURCE
;
import
androidx.annotation.IntDef
;
import
java.lang.annotation.Retention
;
/**
* The types of metadata that can be extracted from HLS streams.
*
* <p>See {@link HlsMediaSource.Factory#setMetadataType(int)}.
*/
@Retention
(
SOURCE
)
@IntDef
({
HlsMetadataType
.
ID3
,
HlsMetadataType
.
EMSG
})
public
@interface
HlsMetadataType
{
int
ID3
=
1
;
int
EMSG
=
3
;
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java
View file @
41b3fc11
This diff is collapsed.
Click to expand it.
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java
View file @
41b3fc11
...
@@ -91,6 +91,7 @@ public final class HlsMediaPeriodTest {
...
@@ -91,6 +91,7 @@ public final class HlsMediaPeriodTest {
mock
(
Allocator
.
class
),
mock
(
Allocator
.
class
),
mock
(
CompositeSequenceableLoaderFactory
.
class
),
mock
(
CompositeSequenceableLoaderFactory
.
class
),
/* allowChunklessPreparation =*/
true
,
/* allowChunklessPreparation =*/
true
,
HlsMetadataType
.
ID3
,
/* useSessionKeys= */
false
);
/* useSessionKeys= */
false
);
};
};
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java
View file @
41b3fc11
...
@@ -98,19 +98,19 @@ import java.util.concurrent.CopyOnWriteArraySet;
...
@@ -98,19 +98,19 @@ import java.util.concurrent.CopyOnWriteArraySet;
* <li><b>{@code scrubber_color}</b> - Color for the scrubber handle.
* <li><b>{@code scrubber_color}</b> - Color for the scrubber handle.
* <ul>
* <ul>
* <li>Corresponding method: {@link #setScrubberColor(int)}
* <li>Corresponding method: {@link #setScrubberColor(int)}
* <li>Default:
see {@link #getDefaultScrubberColor(int)
}
* <li>Default:
{@link #DEFAULT_SCRUBBER_COLOR
}
* </ul>
* </ul>
* <li><b>{@code buffered_color}</b> - Color for the portion of the time bar after the current
* <li><b>{@code buffered_color}</b> - Color for the portion of the time bar after the current
* played position up to the current buffered position.
* played position up to the current buffered position.
* <ul>
* <ul>
* <li>Corresponding method: {@link #setBufferedColor(int)}
* <li>Corresponding method: {@link #setBufferedColor(int)}
* <li>Default:
see {@link #getDefaultBufferedColor(int)
}
* <li>Default:
{@link #DEFAULT_BUFFERED_COLOR
}
* </ul>
* </ul>
* <li><b>{@code unplayed_color}</b> - Color for the portion of the time bar after the current
* <li><b>{@code unplayed_color}</b> - Color for the portion of the time bar after the current
* buffered position.
* buffered position.
* <ul>
* <ul>
* <li>Corresponding method: {@link #setUnplayedColor(int)}
* <li>Corresponding method: {@link #setUnplayedColor(int)}
* <li>Default:
see {@link #getDefaultUnplayedColor(int)
}
* <li>Default:
{@link #DEFAULT_UNPLAYED_COLOR
}
* </ul>
* </ul>
* <li><b>{@code ad_marker_color}</b> - Color for unplayed ad markers.
* <li><b>{@code ad_marker_color}</b> - Color for unplayed ad markers.
* <ul>
* <ul>
...
@@ -120,7 +120,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
...
@@ -120,7 +120,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
* <li><b>{@code played_ad_marker_color}</b> - Color for played ad markers.
* <li><b>{@code played_ad_marker_color}</b> - Color for played ad markers.
* <ul>
* <ul>
* <li>Corresponding method: {@link #setPlayedAdMarkerColor(int)}
* <li>Corresponding method: {@link #setPlayedAdMarkerColor(int)}
* <li>Default:
see {@link #getDefaultPlayedAdMarkerColor(int)
}
* <li>Default:
{@link #DEFAULT_PLAYED_AD_MARKER_COLOR
}
* </ul>
* </ul>
* </ul>
* </ul>
*/
*/
...
@@ -154,10 +154,16 @@ public class DefaultTimeBar extends View implements TimeBar {
...
@@ -154,10 +154,16 @@ public class DefaultTimeBar extends View implements TimeBar {
* Default color for the played portion of the time bar.
* Default color for the played portion of the time bar.
*/
*/
public
static
final
int
DEFAULT_PLAYED_COLOR
=
0xFFFFFFFF
;
public
static
final
int
DEFAULT_PLAYED_COLOR
=
0xFFFFFFFF
;
/**
/** Default color for the played portion of the time bar. */
* Default color for ad markers.
public
static
final
int
DEFAULT_UNPLAYED_COLOR
=
0x33FFFFFF
;
*/
/** Default color for the buffered portion of the time bar. */
public
static
final
int
DEFAULT_BUFFERED_COLOR
=
0xCCFFFFFF
;
/** Default color for the scrubber handle. */
public
static
final
int
DEFAULT_SCRUBBER_COLOR
=
0xFFFFFFFF
;
/** Default color for ad markers. */
public
static
final
int
DEFAULT_AD_MARKER_COLOR
=
0xB2FFFF00
;
public
static
final
int
DEFAULT_AD_MARKER_COLOR
=
0xB2FFFF00
;
/** Default color for played ad markers. */
public
static
final
int
DEFAULT_PLAYED_AD_MARKER_COLOR
=
0x33FFFF00
;
/**
/**
* The threshold in dps above the bar at which touch events trigger fine scrub mode.
* The threshold in dps above the bar at which touch events trigger fine scrub mode.
...
@@ -289,16 +295,17 @@ public class DefaultTimeBar extends View implements TimeBar {
...
@@ -289,16 +295,17 @@ public class DefaultTimeBar extends View implements TimeBar {
scrubberDraggedSize
=
a
.
getDimensionPixelSize
(
scrubberDraggedSize
=
a
.
getDimensionPixelSize
(
R
.
styleable
.
DefaultTimeBar_scrubber_dragged_size
,
defaultScrubberDraggedSize
);
R
.
styleable
.
DefaultTimeBar_scrubber_dragged_size
,
defaultScrubberDraggedSize
);
int
playedColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_played_color
,
DEFAULT_PLAYED_COLOR
);
int
playedColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_played_color
,
DEFAULT_PLAYED_COLOR
);
int
scrubberColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_scrubber_color
,
int
scrubberColor
=
getDefaultScrubberColor
(
playedColor
)
);
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_scrubber_color
,
DEFAULT_SCRUBBER_COLOR
);
int
bufferedColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_buffered_color
,
int
bufferedColor
=
getDefaultBufferedColor
(
playedColor
)
);
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_buffered_color
,
DEFAULT_BUFFERED_COLOR
);
int
unplayedColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_unplayed_color
,
int
unplayedColor
=
getDefaultUnplayedColor
(
playedColor
)
);
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_unplayed_color
,
DEFAULT_UNPLAYED_COLOR
);
int
adMarkerColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_ad_marker_color
,
int
adMarkerColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_ad_marker_color
,
DEFAULT_AD_MARKER_COLOR
);
DEFAULT_AD_MARKER_COLOR
);
int
playedAdMarkerColor
=
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_played_ad_marker_color
,
int
playedAdMarkerColor
=
getDefaultPlayedAdMarkerColor
(
adMarkerColor
));
a
.
getInt
(
R
.
styleable
.
DefaultTimeBar_played_ad_marker_color
,
DEFAULT_PLAYED_AD_MARKER_COLOR
);
playedPaint
.
setColor
(
playedColor
);
playedPaint
.
setColor
(
playedColor
);
scrubberPaint
.
setColor
(
scrubberColor
);
scrubberPaint
.
setColor
(
scrubberColor
);
bufferedPaint
.
setColor
(
bufferedColor
);
bufferedPaint
.
setColor
(
bufferedColor
);
...
@@ -316,10 +323,11 @@ public class DefaultTimeBar extends View implements TimeBar {
...
@@ -316,10 +323,11 @@ public class DefaultTimeBar extends View implements TimeBar {
scrubberDisabledSize
=
defaultScrubberDisabledSize
;
scrubberDisabledSize
=
defaultScrubberDisabledSize
;
scrubberDraggedSize
=
defaultScrubberDraggedSize
;
scrubberDraggedSize
=
defaultScrubberDraggedSize
;
playedPaint
.
setColor
(
DEFAULT_PLAYED_COLOR
);
playedPaint
.
setColor
(
DEFAULT_PLAYED_COLOR
);
scrubberPaint
.
setColor
(
getDefaultScrubberColor
(
DEFAULT_PLAYED_COLOR
)
);
scrubberPaint
.
setColor
(
DEFAULT_SCRUBBER_COLOR
);
bufferedPaint
.
setColor
(
getDefaultBufferedColor
(
DEFAULT_PLAYED_COLOR
)
);
bufferedPaint
.
setColor
(
DEFAULT_BUFFERED_COLOR
);
unplayedPaint
.
setColor
(
getDefaultUnplayedColor
(
DEFAULT_PLAYED_COLOR
)
);
unplayedPaint
.
setColor
(
DEFAULT_UNPLAYED_COLOR
);
adMarkerPaint
.
setColor
(
DEFAULT_AD_MARKER_COLOR
);
adMarkerPaint
.
setColor
(
DEFAULT_AD_MARKER_COLOR
);
playedAdMarkerPaint
.
setColor
(
DEFAULT_PLAYED_AD_MARKER_COLOR
);
scrubberDrawable
=
null
;
scrubberDrawable
=
null
;
}
}
formatBuilder
=
new
StringBuilder
();
formatBuilder
=
new
StringBuilder
();
...
@@ -856,22 +864,6 @@ public class DefaultTimeBar extends View implements TimeBar {
...
@@ -856,22 +864,6 @@ public class DefaultTimeBar extends View implements TimeBar {
return
Util
.
SDK_INT
>=
23
&&
drawable
.
setLayoutDirection
(
layoutDirection
);
return
Util
.
SDK_INT
>=
23
&&
drawable
.
setLayoutDirection
(
layoutDirection
);
}
}
public
static
int
getDefaultScrubberColor
(
int
playedColor
)
{
return
0xFF000000
|
playedColor
;
}
public
static
int
getDefaultUnplayedColor
(
int
playedColor
)
{
return
0x33000000
|
(
playedColor
&
0x00FFFFFF
);
}
public
static
int
getDefaultBufferedColor
(
int
playedColor
)
{
return
0xCC000000
|
(
playedColor
&
0x00FFFFFF
);
}
public
static
int
getDefaultPlayedAdMarkerColor
(
int
adMarkerColor
)
{
return
0x33000000
|
(
adMarkerColor
&
0x00FFFFFF
);
}
private
static
int
dpToPx
(
float
density
,
int
dps
)
{
private
static
int
dpToPx
(
float
density
,
int
dps
)
{
return
(
int
)
(
dps
*
density
+
0.5f
);
return
(
int
)
(
dps
*
density
+
0.5f
);
}
}
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
View file @
41b3fc11
...
@@ -748,14 +748,14 @@ public class PlayerControlView extends FrameLayout {
...
@@ -748,14 +748,14 @@ public class PlayerControlView extends FrameLayout {
return
;
return
;
}
}
boolean
requestPlayPauseFocus
=
false
;
boolean
requestPlayPauseFocus
=
false
;
boolean
playing
=
isPlaying
();
boolean
shouldShowPauseButton
=
shouldShowPauseButton
();
if
(
playButton
!=
null
)
{
if
(
playButton
!=
null
)
{
requestPlayPauseFocus
|=
playing
&&
playButton
.
isFocused
();
requestPlayPauseFocus
|=
shouldShowPauseButton
&&
playButton
.
isFocused
();
playButton
.
setVisibility
(
playing
?
GONE
:
VISIBLE
);
playButton
.
setVisibility
(
shouldShowPauseButton
?
GONE
:
VISIBLE
);
}
}
if
(
pauseButton
!=
null
)
{
if
(
pauseButton
!=
null
)
{
requestPlayPauseFocus
|=
!
playing
&&
pauseButton
.
isFocused
();
requestPlayPauseFocus
|=
!
shouldShowPauseButton
&&
pauseButton
.
isFocused
();
pauseButton
.
setVisibility
(
!
playing
?
GONE
:
VISIBL
E
);
pauseButton
.
setVisibility
(
shouldShowPauseButton
?
VISIBLE
:
GON
E
);
}
}
if
(
requestPlayPauseFocus
)
{
if
(
requestPlayPauseFocus
)
{
requestPlayPauseFocus
();
requestPlayPauseFocus
();
...
@@ -943,7 +943,7 @@ public class PlayerControlView extends FrameLayout {
...
@@ -943,7 +943,7 @@ public class PlayerControlView extends FrameLayout {
// Cancel any pending updates and schedule a new one if necessary.
// Cancel any pending updates and schedule a new one if necessary.
removeCallbacks
(
updateProgressAction
);
removeCallbacks
(
updateProgressAction
);
int
playbackState
=
player
==
null
?
Player
.
STATE_IDLE
:
player
.
getPlaybackState
();
int
playbackState
=
player
==
null
?
Player
.
STATE_IDLE
:
player
.
getPlaybackState
();
if
(
play
backState
==
Player
.
STATE_READY
&&
player
.
getPlayWhenReady
())
{
if
(
play
er
!=
null
&&
player
.
isPlaying
())
{
long
mediaTimeDelayMs
=
long
mediaTimeDelayMs
=
timeBar
!=
null
?
timeBar
.
getPreferredUpdateDelay
()
:
MAX_UPDATE_INTERVAL_MS
;
timeBar
!=
null
?
timeBar
.
getPreferredUpdateDelay
()
:
MAX_UPDATE_INTERVAL_MS
;
...
@@ -965,10 +965,10 @@ public class PlayerControlView extends FrameLayout {
...
@@ -965,10 +965,10 @@ public class PlayerControlView extends FrameLayout {
}
}
private
void
requestPlayPauseFocus
()
{
private
void
requestPlayPauseFocus
()
{
boolean
playing
=
isPlaying
();
boolean
shouldShowPauseButton
=
shouldShowPauseButton
();
if
(!
playing
&&
playButton
!=
null
)
{
if
(!
shouldShowPauseButton
&&
playButton
!=
null
)
{
playButton
.
requestFocus
();
playButton
.
requestFocus
();
}
else
if
(
playing
&&
pauseButton
!=
null
)
{
}
else
if
(
shouldShowPauseButton
&&
pauseButton
!=
null
)
{
pauseButton
.
requestFocus
();
pauseButton
.
requestFocus
();
}
}
}
}
...
@@ -995,7 +995,7 @@ public class PlayerControlView extends FrameLayout {
...
@@ -995,7 +995,7 @@ public class PlayerControlView extends FrameLayout {
||
(
window
.
isDynamic
&&
!
window
.
isSeekable
)))
{
||
(
window
.
isDynamic
&&
!
window
.
isSeekable
)))
{
seekTo
(
player
,
previousWindowIndex
,
C
.
TIME_UNSET
);
seekTo
(
player
,
previousWindowIndex
,
C
.
TIME_UNSET
);
}
else
{
}
else
{
seekTo
(
player
,
0
);
seekTo
(
player
,
windowIndex
,
/* positionMs= */
0
);
}
}
}
}
...
@@ -1015,27 +1015,24 @@ public class PlayerControlView extends FrameLayout {
...
@@ -1015,27 +1015,24 @@ public class PlayerControlView extends FrameLayout {
private
void
rewind
(
Player
player
)
{
private
void
rewind
(
Player
player
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
rewindMs
>
0
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
rewindMs
>
0
)
{
seekTo
(
player
,
player
.
getCurrentPosition
()
-
rewindMs
);
seekTo
Offset
(
player
,
-
rewindMs
);
}
}
}
}
private
void
fastForward
(
Player
player
)
{
private
void
fastForward
(
Player
player
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
fastForwardMs
>
0
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
fastForwardMs
>
0
)
{
seekTo
(
player
,
player
.
getCurrentPosition
()
+
fastForwardMs
);
seekTo
Offset
(
player
,
fastForwardMs
);
}
}
}
}
private
void
seekTo
(
Player
player
,
long
positionMs
)
{
private
void
seekToOffset
(
Player
player
,
long
offsetMs
)
{
seekTo
(
player
,
player
.
getCurrentWindowIndex
(),
positionMs
);
long
positionMs
=
player
.
getCurrentPosition
()
+
offsetMs
;
}
private
boolean
seekTo
(
Player
player
,
int
windowIndex
,
long
positionMs
)
{
long
durationMs
=
player
.
getDuration
();
long
durationMs
=
player
.
getDuration
();
if
(
durationMs
!=
C
.
TIME_UNSET
)
{
if
(
durationMs
!=
C
.
TIME_UNSET
)
{
positionMs
=
Math
.
min
(
positionMs
,
durationMs
);
positionMs
=
Math
.
min
(
positionMs
,
durationMs
);
}
}
positionMs
=
Math
.
max
(
positionMs
,
0
);
positionMs
=
Math
.
max
(
positionMs
,
0
);
return
controlDispatcher
.
dispatchSeekTo
(
player
,
windowIndex
,
positionMs
);
seekTo
(
player
,
player
.
getCurrentWindowIndex
()
,
positionMs
);
}
}
private
void
seekToTimeBarPosition
(
Player
player
,
long
positionMs
)
{
private
void
seekToTimeBarPosition
(
Player
player
,
long
positionMs
)
{
...
@@ -1067,6 +1064,10 @@ public class PlayerControlView extends FrameLayout {
...
@@ -1067,6 +1064,10 @@ public class PlayerControlView extends FrameLayout {
}
}
}
}
private
boolean
seekTo
(
Player
player
,
int
windowIndex
,
long
positionMs
)
{
return
controlDispatcher
.
dispatchSeekTo
(
player
,
windowIndex
,
positionMs
);
}
@Override
@Override
public
void
onAttachedToWindow
()
{
public
void
onAttachedToWindow
()
{
super
.
onAttachedToWindow
();
super
.
onAttachedToWindow
();
...
@@ -1149,7 +1150,7 @@ public class PlayerControlView extends FrameLayout {
...
@@ -1149,7 +1150,7 @@ public class PlayerControlView extends FrameLayout {
return
true
;
return
true
;
}
}
private
boolean
isPlaying
()
{
private
boolean
shouldShowPauseButton
()
{
return
player
!=
null
return
player
!=
null
&&
player
.
getPlaybackState
()
!=
Player
.
STATE_ENDED
&&
player
.
getPlaybackState
()
!=
Player
.
STATE_ENDED
&&
player
.
getPlaybackState
()
!=
Player
.
STATE_IDLE
&&
player
.
getPlaybackState
()
!=
Player
.
STATE_IDLE
...
@@ -1220,6 +1221,11 @@ public class PlayerControlView extends FrameLayout {
...
@@ -1220,6 +1221,11 @@ public class PlayerControlView extends FrameLayout {
}
}
@Override
@Override
public
void
onIsPlayingChanged
(
boolean
isPlaying
)
{
updateProgress
();
}
@Override
public
void
onRepeatModeChanged
(
int
repeatMode
)
{
public
void
onRepeatModeChanged
(
int
repeatMode
)
{
updateRepeatModeButton
();
updateRepeatModeButton
();
updateNavigation
();
updateNavigation
();
...
@@ -1264,7 +1270,7 @@ public class PlayerControlView extends FrameLayout {
...
@@ -1264,7 +1270,7 @@ public class PlayerControlView extends FrameLayout {
playbackPreparer
.
preparePlayback
();
playbackPreparer
.
preparePlayback
();
}
}
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
controlDispatcher
.
dispatchS
eekTo
(
player
,
player
.
getCurrentWindowIndex
(),
C
.
TIME_UNSET
);
s
eekTo
(
player
,
player
.
getCurrentWindowIndex
(),
C
.
TIME_UNSET
);
}
}
controlDispatcher
.
dispatchSetPlayWhenReady
(
player
,
true
);
controlDispatcher
.
dispatchSetPlayWhenReady
(
player
,
true
);
}
else
if
(
pauseButton
==
view
)
{
}
else
if
(
pauseButton
==
view
)
{
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
View file @
41b3fc11
...
@@ -382,8 +382,6 @@ public class PlayerNotificationManager {
...
@@ -382,8 +382,6 @@ public class PlayerNotificationManager {
private
int
visibility
;
private
int
visibility
;
@Priority
private
int
priority
;
@Priority
private
int
priority
;
private
boolean
useChronometer
;
private
boolean
useChronometer
;
private
boolean
wasPlayWhenReady
;
private
int
lastPlaybackState
;
/**
/**
* @deprecated Use {@link #createWithNotificationChannel(Context, String, int, int, int,
* @deprecated Use {@link #createWithNotificationChannel(Context, String, int, int, int,
...
@@ -663,8 +661,6 @@ public class PlayerNotificationManager {
...
@@ -663,8 +661,6 @@ public class PlayerNotificationManager {
}
}
this
.
player
=
player
;
this
.
player
=
player
;
if
(
player
!=
null
)
{
if
(
player
!=
null
)
{
wasPlayWhenReady
=
player
.
getPlayWhenReady
();
lastPlaybackState
=
player
.
getPlaybackState
();
player
.
addListener
(
playerListener
);
player
.
addListener
(
playerListener
);
startOrUpdateNotification
();
startOrUpdateNotification
();
}
}
...
@@ -1070,10 +1066,9 @@ public class PlayerNotificationManager {
...
@@ -1070,10 +1066,9 @@ public class PlayerNotificationManager {
// Changing "showWhen" causes notification flicker if SDK_INT < 21.
// Changing "showWhen" causes notification flicker if SDK_INT < 21.
if
(
Util
.
SDK_INT
>=
21
if
(
Util
.
SDK_INT
>=
21
&&
useChronometer
&&
useChronometer
&&
player
.
isPlaying
()
&&
!
player
.
isPlayingAd
()
&&
!
player
.
isPlayingAd
()
&&
!
player
.
isCurrentWindowDynamic
()
&&
!
player
.
isCurrentWindowDynamic
())
{
&&
player
.
getPlayWhenReady
()
&&
player
.
getPlaybackState
()
==
Player
.
STATE_READY
)
{
builder
builder
.
setWhen
(
System
.
currentTimeMillis
()
-
player
.
getContentPosition
())
.
setWhen
(
System
.
currentTimeMillis
()
-
player
.
getContentPosition
())
.
setShowWhen
(
true
)
.
setShowWhen
(
true
)
...
@@ -1138,7 +1133,7 @@ public class PlayerNotificationManager {
...
@@ -1138,7 +1133,7 @@ public class PlayerNotificationManager {
stringActions
.
add
(
ACTION_REWIND
);
stringActions
.
add
(
ACTION_REWIND
);
}
}
if
(
usePlayPauseActions
)
{
if
(
usePlayPauseActions
)
{
if
(
isPlaying
(
player
))
{
if
(
shouldShowPauseButton
(
player
))
{
stringActions
.
add
(
ACTION_PAUSE
);
stringActions
.
add
(
ACTION_PAUSE
);
}
else
{
}
else
{
stringActions
.
add
(
ACTION_PLAY
);
stringActions
.
add
(
ACTION_PLAY
);
...
@@ -1182,10 +1177,10 @@ public class PlayerNotificationManager {
...
@@ -1182,10 +1177,10 @@ public class PlayerNotificationManager {
if
(
skipPreviousActionIndex
!=
-
1
)
{
if
(
skipPreviousActionIndex
!=
-
1
)
{
actionIndices
[
actionCounter
++]
=
skipPreviousActionIndex
;
actionIndices
[
actionCounter
++]
=
skipPreviousActionIndex
;
}
}
boolean
isPlaying
=
isPlaying
(
player
);
boolean
shouldShowPauseButton
=
shouldShowPauseButton
(
player
);
if
(
pauseActionIndex
!=
-
1
&&
isPlaying
)
{
if
(
pauseActionIndex
!=
-
1
&&
shouldShowPauseButton
)
{
actionIndices
[
actionCounter
++]
=
pauseActionIndex
;
actionIndices
[
actionCounter
++]
=
pauseActionIndex
;
}
else
if
(
playActionIndex
!=
-
1
&&
!
isPlaying
)
{
}
else
if
(
playActionIndex
!=
-
1
&&
!
shouldShowPauseButton
)
{
actionIndices
[
actionCounter
++]
=
playActionIndex
;
actionIndices
[
actionCounter
++]
=
playActionIndex
;
}
}
if
(
skipNextActionIndex
!=
-
1
)
{
if
(
skipNextActionIndex
!=
-
1
)
{
...
@@ -1214,7 +1209,7 @@ public class PlayerNotificationManager {
...
@@ -1214,7 +1209,7 @@ public class PlayerNotificationManager {
||
(
window
.
isDynamic
&&
!
window
.
isSeekable
)))
{
||
(
window
.
isDynamic
&&
!
window
.
isSeekable
)))
{
seekTo
(
player
,
previousWindowIndex
,
C
.
TIME_UNSET
);
seekTo
(
player
,
previousWindowIndex
,
C
.
TIME_UNSET
);
}
else
{
}
else
{
seekTo
(
player
,
0
);
seekTo
(
player
,
windowIndex
,
/* positionMs= */
0
);
}
}
}
}
...
@@ -1234,30 +1229,31 @@ public class PlayerNotificationManager {
...
@@ -1234,30 +1229,31 @@ public class PlayerNotificationManager {
private
void
rewind
(
Player
player
)
{
private
void
rewind
(
Player
player
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
rewindMs
>
0
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
rewindMs
>
0
)
{
seekTo
(
player
,
Math
.
max
(
player
.
getCurrentPosition
()
-
rewindMs
,
0
)
);
seekTo
Offset
(
player
,
/* offsetMs= */
-
rewindMs
);
}
}
}
}
private
void
fastForward
(
Player
player
)
{
private
void
fastForward
(
Player
player
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
fastForwardMs
>
0
)
{
if
(
player
.
isCurrentWindowSeekable
()
&&
fastForwardMs
>
0
)
{
seekTo
(
player
,
player
.
getCurrentPosition
()
+
fastForwardMs
);
seekTo
Offset
(
player
,
/* offsetMs= */
fastForwardMs
);
}
}
}
}
private
void
seekTo
(
Player
player
,
long
positionMs
)
{
private
void
seekToOffset
(
Player
player
,
long
offsetMs
)
{
long
positionMs
=
player
.
getCurrentPosition
()
+
offsetMs
;
long
durationMs
=
player
.
getDuration
();
if
(
durationMs
!=
C
.
TIME_UNSET
)
{
positionMs
=
Math
.
min
(
positionMs
,
durationMs
);
}
positionMs
=
Math
.
max
(
positionMs
,
0
);
seekTo
(
player
,
player
.
getCurrentWindowIndex
(),
positionMs
);
seekTo
(
player
,
player
.
getCurrentWindowIndex
(),
positionMs
);
}
}
private
void
seekTo
(
Player
player
,
int
windowIndex
,
long
positionMs
)
{
private
void
seekTo
(
Player
player
,
int
windowIndex
,
long
positionMs
)
{
long
duration
=
player
.
getDuration
();
if
(
duration
!=
C
.
TIME_UNSET
)
{
positionMs
=
Math
.
min
(
positionMs
,
duration
);
}
positionMs
=
Math
.
max
(
positionMs
,
0
);
controlDispatcher
.
dispatchSeekTo
(
player
,
windowIndex
,
positionMs
);
controlDispatcher
.
dispatchSeekTo
(
player
,
windowIndex
,
positionMs
);
}
}
private
boolean
isPlaying
(
Player
player
)
{
private
boolean
shouldShowPauseButton
(
Player
player
)
{
return
player
.
getPlaybackState
()
!=
Player
.
STATE_ENDED
return
player
.
getPlaybackState
()
!=
Player
.
STATE_ENDED
&&
player
.
getPlaybackState
()
!=
Player
.
STATE_IDLE
&&
player
.
getPlaybackState
()
!=
Player
.
STATE_IDLE
&&
player
.
getPlayWhenReady
();
&&
player
.
getPlayWhenReady
();
...
@@ -1328,11 +1324,12 @@ public class PlayerNotificationManager {
...
@@ -1328,11 +1324,12 @@ public class PlayerNotificationManager {
@Override
@Override
public
void
onPlayerStateChanged
(
boolean
playWhenReady
,
int
playbackState
)
{
public
void
onPlayerStateChanged
(
boolean
playWhenReady
,
int
playbackState
)
{
if
(
wasPlayWhenReady
!=
playWhenReady
||
lastPlaybackState
!=
playbackState
)
{
startOrUpdateNotification
();
startOrUpdateNotification
();
}
wasPlayWhenReady
=
playWhenReady
;
lastPlaybackState
=
playbackState
;
@Override
}
public
void
onIsPlayingChanged
(
boolean
isPlaying
)
{
startOrUpdateNotification
();
}
}
@Override
@Override
...
@@ -1373,7 +1370,7 @@ public class PlayerNotificationManager {
...
@@ -1373,7 +1370,7 @@ public class PlayerNotificationManager {
playbackPreparer
.
preparePlayback
();
playbackPreparer
.
preparePlayback
();
}
}
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
}
else
if
(
player
.
getPlaybackState
()
==
Player
.
STATE_ENDED
)
{
controlDispatcher
.
dispatchS
eekTo
(
player
,
player
.
getCurrentWindowIndex
(),
C
.
TIME_UNSET
);
s
eekTo
(
player
,
player
.
getCurrentWindowIndex
(),
C
.
TIME_UNSET
);
}
}
controlDispatcher
.
dispatchSetPlayWhenReady
(
player
,
/* playWhenReady= */
true
);
controlDispatcher
.
dispatchSetPlayWhenReady
(
player
,
/* playWhenReady= */
true
);
}
else
if
(
ACTION_PAUSE
.
equals
(
action
))
{
}
else
if
(
ACTION_PAUSE
.
equals
(
action
))
{
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeDataSource.java
View file @
41b3fc11
...
@@ -52,7 +52,7 @@ public class FakeDataSource extends BaseDataSource {
...
@@ -52,7 +52,7 @@ public class FakeDataSource extends BaseDataSource {
}
}
@Override
@Override
public
DataSource
createDataSource
()
{
public
Fake
DataSource
createDataSource
()
{
return
new
FakeDataSource
(
fakeDataSet
,
isNetwork
);
return
new
FakeDataSource
(
fakeDataSet
,
isNetwork
);
}
}
}
}
...
...
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