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
ce48a28a
authored
Feb 25, 2021
by
Marc Baechinger
Committed by
GitHub
Feb 25, 2021
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #8634 from google/dev-v2-r2.13.2
r2.13.2
parents
4b1e0fa9
c96f695a
Show whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
308 additions
and
154 deletions
.gitignore
RELEASENOTES.md
constants.gradle
extensions/ffmpeg/README.md
extensions/flac/README.md
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
extensions/opus/README.md
extensions/vp9/README.md
library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java
library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java
library/core/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheWriterTest.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.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
library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
library/ui/src/main/res/layout/exo_styled_player_control_ffwd_button.xml
library/ui/src/main/res/layout/exo_styled_player_control_rewind_button.xml
library/ui/src/main/res/layout/exo_styled_player_control_view.xml
library/ui/src/main/res/layout/exo_styled_settings_list_item.xml
library/ui/src/main/res/layout/exo_styled_sub_settings_list_item.xml
library/ui/src/main/res/values/ids.xml
publish.gradle
testdata/src/test/assets/media/ssa/colors → testdata/src/test/assets/media/ssa/style_colors
testdata/src/test/assets/media/ssa/style_font_size
testutils/src/main/java/com/google/android/exoplayer2/testutil/HttpDataSourceTestEnv.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/WebServerDispatcher.java
testutils/src/test/java/com/google/android/exoplayer2/testutil/WebServerDispatcherTest.java
.gitignore
View file @
ce48a28a
...
@@ -47,6 +47,7 @@ bazel-testlogs
...
@@ -47,6 +47,7 @@ bazel-testlogs
.DS_Store
.DS_Store
cmake-build-debug
cmake-build-debug
dist
dist
jacoco.exec
tmp
tmp
# External native builds
# External native builds
...
...
RELEASENOTES.md
View file @
ce48a28a
# Release notes
# Release notes
### 2.13.2 (2021-02-25)
*
Extractors:
*
Add support for MP4 and QuickTime meta atoms that are not full atoms.
*
UI:
*
Make conditions to enable UI actions consistent in
`DefaultControlDispatcher`
,
`PlayerControlView`
,
`StyledPlayerControlView`
,
`PlayerNotificationManager`
and
`TimelineQueueNavigator`
.
*
Fix conditions to enable seeking to next/previous media item to handle
the case where a live stream has ended.
*
Audio:
*
Fix
`SimpleExoPlayer`
reporting audio session ID as 0 in some cases
(
[
#8585
](
https://github.com/google/ExoPlayer/issues/8585
)
).
*
IMA extension:
*
Fix a bug where playback could get stuck when seeking into a playlist
item with ads, if the preroll ad had preloaded but the window position
of the seek should instead trigger playback of a midroll.
*
Fix a bug with playback of ads in playlists, where the incorrect period
index was used when deciding whether to trigger playback of an ad after
a seek.
*
Text:
*
Parse SSA/ASS font size in
`Style:`
lines
(
[
#8435
](
https://github.com/google/ExoPlayer/issues/8435
)
).
*
VP9 extension: Update to use NDK r21
(
[
#8581
](
https://github.com/google/ExoPlayer/issues/8581
)
).
*
FLAC extension: Update to use NDK r21
(
[
#8581
](
https://github.com/google/ExoPlayer/issues/8581
)
).
*
Opus extension: Update to use NDK r21
(
[
#8581
](
https://github.com/google/ExoPlayer/issues/8581
)
).
*
FFmpeg extension: Update to use NDK r21
(
[
#8581
](
https://github.com/google/ExoPlayer/issues/8581
)
).
### 2.13.1 (2021-02-12)
### 2.13.1 (2021-02-12)
*
Live streaming:
*
Live streaming:
...
...
constants.gradle
View file @
ce48a28a
...
@@ -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.13.
1
'
releaseVersion
=
'2.13.
2
'
releaseVersionCode
=
201300
1
releaseVersionCode
=
201300
2
minSdkVersion
=
16
minSdkVersion
=
16
appTargetSdkVersion
=
29
appTargetSdkVersion
=
29
targetSdkVersion
=
28
// TODO: Bump once b/143232359 is resolved. Also fix TODOs in UtilTest.
targetSdkVersion
=
28
// TODO: Bump once b/143232359 is resolved. Also fix TODOs in UtilTest.
...
...
extensions/ffmpeg/README.md
View file @
ce48a28a
...
@@ -30,7 +30,7 @@ FFMPEG_EXT_PATH="${EXOPLAYER_ROOT}/extensions/ffmpeg/src/main"
...
@@ -30,7 +30,7 @@ FFMPEG_EXT_PATH="${EXOPLAYER_ROOT}/extensions/ffmpeg/src/main"
```
```
*
Download the
[
Android NDK
][]
and set its location in a shell variable.
*
Download the
[
Android NDK
][]
and set its location in a shell variable.
This build configuration has been tested on NDK r2
0
.
This build configuration has been tested on NDK r2
1
.
```
```
NDK_PATH="<path to Android NDK>"
NDK_PATH="<path to Android NDK>"
...
...
extensions/flac/README.md
View file @
ce48a28a
...
@@ -29,7 +29,7 @@ FLAC_EXT_PATH="${EXOPLAYER_ROOT}/extensions/flac/src/main"
...
@@ -29,7 +29,7 @@ FLAC_EXT_PATH="${EXOPLAYER_ROOT}/extensions/flac/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.
This build configuration has been tested on NDK r2
0
.
This build configuration has been tested on NDK r2
1
.
```
```
NDK_PATH="<path to Android NDK>"
NDK_PATH="<path to Android NDK>"
...
...
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java
View file @
ce48a28a
...
@@ -341,13 +341,27 @@ import java.util.Map;
...
@@ -341,13 +341,27 @@ import java.util.Map;
boolean
playWhenReady
=
player
.
getPlayWhenReady
();
boolean
playWhenReady
=
player
.
getPlayWhenReady
();
onTimelineChanged
(
player
.
getCurrentTimeline
(),
Player
.
TIMELINE_CHANGE_REASON_SOURCE_UPDATE
);
onTimelineChanged
(
player
.
getCurrentTimeline
(),
Player
.
TIMELINE_CHANGE_REASON_SOURCE_UPDATE
);
if
(!
AdPlaybackState
.
NONE
.
equals
(
adPlaybackState
)
@Nullable
AdsManager
adsManager
=
this
.
adsManager
;
&&
adsManager
!=
null
if
(!
AdPlaybackState
.
NONE
.
equals
(
adPlaybackState
)
&&
adsManager
!=
null
&&
imaPausedContent
)
{
&&
imaPausedContent
// Check whether the current ad break matches the expected ad break based on the current
&&
playWhenReady
)
{
// position. If not, discard the current ad break so that the correct ad break can load.
long
contentPositionMs
=
getContentPeriodPositionMs
(
player
,
timeline
,
period
);
int
adGroupForPositionIndex
=
adPlaybackState
.
getAdGroupIndexForPositionUs
(
C
.
msToUs
(
contentPositionMs
),
C
.
msToUs
(
contentDurationMs
));
if
(
adGroupForPositionIndex
!=
C
.
INDEX_UNSET
&&
imaAdInfo
!=
null
&&
imaAdInfo
.
adGroupIndex
!=
adGroupForPositionIndex
)
{
if
(
configuration
.
debugModeEnabled
)
{
Log
.
d
(
TAG
,
"Discarding preloaded ad "
+
imaAdInfo
);
}
adsManager
.
discardAdBreak
();
}
if
(
playWhenReady
)
{
adsManager
.
resume
();
adsManager
.
resume
();
}
}
}
}
}
/** Deactivates playback. */
/** Deactivates playback. */
public
void
deactivate
()
{
public
void
deactivate
()
{
...
@@ -826,7 +840,7 @@ import java.util.Map;
...
@@ -826,7 +840,7 @@ import java.util.Map;
ensureSentContentCompleteIfAtEndOfStream
();
ensureSentContentCompleteIfAtEndOfStream
();
if
(!
sentContentComplete
&&
!
timeline
.
isEmpty
())
{
if
(!
sentContentComplete
&&
!
timeline
.
isEmpty
())
{
long
positionMs
=
getContentPeriodPositionMs
(
player
,
timeline
,
period
);
long
positionMs
=
getContentPeriodPositionMs
(
player
,
timeline
,
period
);
timeline
.
getPeriod
(
/* periodIndex= */
0
,
period
);
timeline
.
getPeriod
(
player
.
getCurrentPeriodIndex
()
,
period
);
int
newAdGroupIndex
=
period
.
getAdGroupIndexForPositionUs
(
C
.
msToUs
(
positionMs
));
int
newAdGroupIndex
=
period
.
getAdGroupIndexForPositionUs
(
C
.
msToUs
(
positionMs
));
if
(
newAdGroupIndex
!=
C
.
INDEX_UNSET
)
{
if
(
newAdGroupIndex
!=
C
.
INDEX_UNSET
)
{
sentPendingContentPositionMs
=
false
;
sentPendingContentPositionMs
=
false
;
...
...
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
View file @
ce48a28a
...
@@ -98,8 +98,8 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
...
@@ -98,8 +98,8 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
if
(!
timeline
.
isEmpty
()
&&
!
player
.
isPlayingAd
())
{
if
(!
timeline
.
isEmpty
()
&&
!
player
.
isPlayingAd
())
{
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
enableSkipTo
=
timeline
.
getWindowCount
()
>
1
;
enableSkipTo
=
timeline
.
getWindowCount
()
>
1
;
enablePrevious
=
window
.
isSeekable
||
!
window
.
is
Dynamic
||
player
.
hasPrevious
();
enablePrevious
=
window
.
isSeekable
||
!
window
.
is
Live
()
||
player
.
hasPrevious
();
enableNext
=
window
.
isDynamic
||
player
.
hasNext
();
enableNext
=
(
window
.
isLive
()
&&
window
.
isDynamic
)
||
player
.
hasNext
();
}
}
long
actions
=
0
;
long
actions
=
0
;
...
...
extensions/opus/README.md
View file @
ce48a28a
...
@@ -29,7 +29,7 @@ OPUS_EXT_PATH="${EXOPLAYER_ROOT}/extensions/opus/src/main"
...
@@ -29,7 +29,7 @@ OPUS_EXT_PATH="${EXOPLAYER_ROOT}/extensions/opus/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.
This build configuration has been tested on NDK r2
0
.
This build configuration has been tested on NDK r2
1
.
```
```
NDK_PATH="<path to Android NDK>"
NDK_PATH="<path to Android NDK>"
...
...
extensions/vp9/README.md
View file @
ce48a28a
...
@@ -29,7 +29,7 @@ VP9_EXT_PATH="${EXOPLAYER_ROOT}/extensions/vp9/src/main"
...
@@ -29,7 +29,7 @@ VP9_EXT_PATH="${EXOPLAYER_ROOT}/extensions/vp9/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.
This build configuration has been tested on NDK r2
0
.
This build configuration has been tested on NDK r2
1
.
```
```
NDK_PATH="<path to Android NDK>"
NDK_PATH="<path to Android NDK>"
...
...
library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
ce48a28a
...
@@ -30,11 +30,11 @@ public final class ExoPlayerLibraryInfo {
...
@@ -30,11 +30,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.13.
1
"
;
public
static
final
String
VERSION
=
"2.13.
2
"
;
/** 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.13.
1
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.13.
2
"
;
/**
/**
* The version of the library expressed as an integer, for example 1002003.
* The version of the library expressed as an integer, for example 1002003.
...
@@ -44,7 +44,7 @@ public final class ExoPlayerLibraryInfo {
...
@@ -44,7 +44,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
=
201300
1
;
public
static
final
int
VERSION_INT
=
201300
2
;
/**
/**
* The default user agent for requests made by the library.
* The default user agent for requests made by the library.
...
...
library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
View file @
ce48a28a
...
@@ -79,11 +79,12 @@ public class DefaultControlDispatcher implements ControlDispatcher {
...
@@ -79,11 +79,12 @@ public class DefaultControlDispatcher implements ControlDispatcher {
int
windowIndex
=
player
.
getCurrentWindowIndex
();
int
windowIndex
=
player
.
getCurrentWindowIndex
();
timeline
.
getWindow
(
windowIndex
,
window
);
timeline
.
getWindow
(
windowIndex
,
window
);
int
previousWindowIndex
=
player
.
getPreviousWindowIndex
();
int
previousWindowIndex
=
player
.
getPreviousWindowIndex
();
boolean
isUnseekableLiveStream
=
window
.
isLive
()
&&
!
window
.
isSeekable
;
if
(
previousWindowIndex
!=
C
.
INDEX_UNSET
if
(
previousWindowIndex
!=
C
.
INDEX_UNSET
&&
(
player
.
getCurrentPosition
()
<=
MAX_POSITION_FOR_SEEK_TO_PREVIOUS
&&
(
player
.
getCurrentPosition
()
<=
MAX_POSITION_FOR_SEEK_TO_PREVIOUS
||
(
window
.
isDynamic
&&
!
window
.
isSeekable
)
))
{
||
isUnseekableLiveStream
))
{
player
.
seekTo
(
previousWindowIndex
,
C
.
TIME_UNSET
);
player
.
seekTo
(
previousWindowIndex
,
C
.
TIME_UNSET
);
}
else
{
}
else
if
(!
isUnseekableLiveStream
)
{
player
.
seekTo
(
windowIndex
,
/* positionMs= */
0
);
player
.
seekTo
(
windowIndex
,
/* positionMs= */
0
);
}
}
return
true
;
return
true
;
...
@@ -96,10 +97,11 @@ public class DefaultControlDispatcher implements ControlDispatcher {
...
@@ -96,10 +97,11 @@ public class DefaultControlDispatcher implements ControlDispatcher {
return
true
;
return
true
;
}
}
int
windowIndex
=
player
.
getCurrentWindowIndex
();
int
windowIndex
=
player
.
getCurrentWindowIndex
();
timeline
.
getWindow
(
windowIndex
,
window
);
int
nextWindowIndex
=
player
.
getNextWindowIndex
();
int
nextWindowIndex
=
player
.
getNextWindowIndex
();
if
(
nextWindowIndex
!=
C
.
INDEX_UNSET
)
{
if
(
nextWindowIndex
!=
C
.
INDEX_UNSET
)
{
player
.
seekTo
(
nextWindowIndex
,
C
.
TIME_UNSET
);
player
.
seekTo
(
nextWindowIndex
,
C
.
TIME_UNSET
);
}
else
if
(
timeline
.
getWindow
(
windowIndex
,
window
).
isLive
()
)
{
}
else
if
(
window
.
isLive
()
&&
window
.
isDynamic
)
{
player
.
seekTo
(
windowIndex
,
C
.
TIME_UNSET
);
player
.
seekTo
(
windowIndex
,
C
.
TIME_UNSET
);
}
}
return
true
;
return
true
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
View file @
ce48a28a
...
@@ -2140,7 +2140,6 @@ public class SimpleExoPlayer extends BasePlayer
...
@@ -2140,7 +2140,6 @@ public class SimpleExoPlayer extends BasePlayer
analyticsCollector
.
onAudioDisabled
(
counters
);
analyticsCollector
.
onAudioDisabled
(
counters
);
audioFormat
=
null
;
audioFormat
=
null
;
audioDecoderCounters
=
null
;
audioDecoderCounters
=
null
;
audioSessionId
=
C
.
AUDIO_SESSION_ID_UNSET
;
}
}
@Override
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/SilenceMediaSource.java
View file @
ce48a28a
...
@@ -305,11 +305,15 @@ public final class SilenceMediaSource extends BaseMediaSource {
...
@@ -305,11 +305,15 @@ public final class SilenceMediaSource extends BaseMediaSource {
return
C
.
RESULT_BUFFER_READ
;
return
C
.
RESULT_BUFFER_READ
;
}
}
buffer
.
timeUs
=
getAudioPositionUs
(
positionBytes
);
buffer
.
addFlag
(
C
.
BUFFER_FLAG_KEY_FRAME
);
if
(
buffer
.
isFlagsOnly
())
{
return
C
.
RESULT_BUFFER_READ
;
}
int
bytesToWrite
=
(
int
)
min
(
SILENCE_SAMPLE
.
length
,
bytesRemaining
);
int
bytesToWrite
=
(
int
)
min
(
SILENCE_SAMPLE
.
length
,
bytesRemaining
);
buffer
.
ensureSpaceForWrite
(
bytesToWrite
);
buffer
.
ensureSpaceForWrite
(
bytesToWrite
);
buffer
.
data
.
put
(
SILENCE_SAMPLE
,
/* offset= */
0
,
bytesToWrite
);
buffer
.
data
.
put
(
SILENCE_SAMPLE
,
/* offset= */
0
,
bytesToWrite
);
buffer
.
timeUs
=
getAudioPositionUs
(
positionBytes
);
buffer
.
addFlag
(
C
.
BUFFER_FLAG_KEY_FRAME
);
positionBytes
+=
bytesToWrite
;
positionBytes
+=
bytesToWrite
;
return
C
.
RESULT_BUFFER_READ
;
return
C
.
RESULT_BUFFER_READ
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java
View file @
ce48a28a
...
@@ -51,9 +51,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -51,9 +51,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/**
/**
* A {@link MediaSource} that inserts ads linearly
with a provided content media source. This source
* A {@link MediaSource} that inserts ads linearly
into a provided content media source.
*
cannot be used as a child source in a composition. It must be the top-level source used to
*
*
prepare the player
.
*
<p>The wrapped content media source must contain a single {@link Timeline.Period}
.
*/
*/
public
final
class
AdsMediaSource
extends
CompositeMediaSource
<
MediaPeriodId
>
{
public
final
class
AdsMediaSource
extends
CompositeMediaSource
<
MediaPeriodId
>
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java
View file @
ce48a28a
...
@@ -314,6 +314,10 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
...
@@ -314,6 +314,10 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
/* end= */
spannableText
.
length
(),
/* end= */
spannableText
.
length
(),
SpannableString
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
SpannableString
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
}
}
if
(
style
.
fontSize
!=
Cue
.
DIMEN_UNSET
&&
screenHeight
!=
Cue
.
DIMEN_UNSET
)
{
cue
.
setTextSize
(
style
.
fontSize
/
screenHeight
,
Cue
.
TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING
);
}
}
}
@SsaStyle
.
SsaAlignment
int
alignment
;
@SsaStyle
.
SsaAlignment
int
alignment
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java
View file @
ce48a28a
...
@@ -27,6 +27,7 @@ import androidx.annotation.ColorInt;
...
@@ -27,6 +27,7 @@ import androidx.annotation.ColorInt;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
...
@@ -90,12 +91,17 @@ import java.util.regex.Pattern;
...
@@ -90,12 +91,17 @@ import java.util.regex.Pattern;
public
final
String
name
;
public
final
String
name
;
@SsaAlignment
public
final
int
alignment
;
@SsaAlignment
public
final
int
alignment
;
@Nullable
@ColorInt
public
final
Integer
primaryColor
;
@Nullable
@ColorInt
public
final
Integer
primaryColor
;
public
final
float
fontSize
;
private
SsaStyle
(
private
SsaStyle
(
String
name
,
@SsaAlignment
int
alignment
,
@Nullable
@ColorInt
Integer
primaryColor
)
{
String
name
,
@SsaAlignment
int
alignment
,
@Nullable
@ColorInt
Integer
primaryColor
,
float
fontSize
)
{
this
.
name
=
name
;
this
.
name
=
name
;
this
.
alignment
=
alignment
;
this
.
alignment
=
alignment
;
this
.
primaryColor
=
primaryColor
;
this
.
primaryColor
=
primaryColor
;
this
.
fontSize
=
fontSize
;
}
}
@Nullable
@Nullable
...
@@ -114,7 +120,8 @@ import java.util.regex.Pattern;
...
@@ -114,7 +120,8 @@ import java.util.regex.Pattern;
return
new
SsaStyle
(
return
new
SsaStyle
(
styleValues
[
format
.
nameIndex
].
trim
(),
styleValues
[
format
.
nameIndex
].
trim
(),
parseAlignment
(
styleValues
[
format
.
alignmentIndex
].
trim
()),
parseAlignment
(
styleValues
[
format
.
alignmentIndex
].
trim
()),
parseColor
(
styleValues
[
format
.
primaryColorIndex
].
trim
()));
parseColor
(
styleValues
[
format
.
primaryColorIndex
].
trim
()),
parseFontSize
(
styleValues
[
format
.
fontSizeIndex
].
trim
()));
}
catch
(
RuntimeException
e
)
{
}
catch
(
RuntimeException
e
)
{
Log
.
w
(
TAG
,
"Skipping malformed 'Style:' line: '"
+
styleLine
+
"'"
,
e
);
Log
.
w
(
TAG
,
"Skipping malformed 'Style:' line: '"
+
styleLine
+
"'"
,
e
);
return
null
;
return
null
;
...
@@ -191,6 +198,15 @@ import java.util.regex.Pattern;
...
@@ -191,6 +198,15 @@ import java.util.regex.Pattern;
return
Color
.
argb
(
a
,
r
,
g
,
b
);
return
Color
.
argb
(
a
,
r
,
g
,
b
);
}
}
private
static
float
parseFontSize
(
String
fontSize
)
{
try
{
return
Float
.
parseFloat
(
fontSize
);
}
catch
(
NumberFormatException
e
)
{
Log
.
w
(
TAG
,
"Failed to parse font size: '"
+
fontSize
+
"'"
,
e
);
return
Cue
.
DIMEN_UNSET
;
}
}
/**
/**
* Represents a {@code Format:} line from the {@code [V4+ Styles]} section
* Represents a {@code Format:} line from the {@code [V4+ Styles]} section
*
*
...
@@ -202,12 +218,15 @@ import java.util.regex.Pattern;
...
@@ -202,12 +218,15 @@ import java.util.regex.Pattern;
public
final
int
nameIndex
;
public
final
int
nameIndex
;
public
final
int
alignmentIndex
;
public
final
int
alignmentIndex
;
public
final
int
primaryColorIndex
;
public
final
int
primaryColorIndex
;
public
final
int
fontSizeIndex
;
public
final
int
length
;
public
final
int
length
;
private
Format
(
int
nameIndex
,
int
alignmentIndex
,
int
primaryColorIndex
,
int
length
)
{
private
Format
(
int
nameIndex
,
int
alignmentIndex
,
int
primaryColorIndex
,
int
fontSizeIndex
,
int
length
)
{
this
.
nameIndex
=
nameIndex
;
this
.
nameIndex
=
nameIndex
;
this
.
alignmentIndex
=
alignmentIndex
;
this
.
alignmentIndex
=
alignmentIndex
;
this
.
primaryColorIndex
=
primaryColorIndex
;
this
.
primaryColorIndex
=
primaryColorIndex
;
this
.
fontSizeIndex
=
fontSizeIndex
;
this
.
length
=
length
;
this
.
length
=
length
;
}
}
...
@@ -221,6 +240,7 @@ import java.util.regex.Pattern;
...
@@ -221,6 +240,7 @@ import java.util.regex.Pattern;
int
nameIndex
=
C
.
INDEX_UNSET
;
int
nameIndex
=
C
.
INDEX_UNSET
;
int
alignmentIndex
=
C
.
INDEX_UNSET
;
int
alignmentIndex
=
C
.
INDEX_UNSET
;
int
primaryColorIndex
=
C
.
INDEX_UNSET
;
int
primaryColorIndex
=
C
.
INDEX_UNSET
;
int
fontSizeIndex
=
C
.
INDEX_UNSET
;
String
[]
keys
=
String
[]
keys
=
TextUtils
.
split
(
styleFormatLine
.
substring
(
SsaDecoder
.
FORMAT_LINE_PREFIX
.
length
()),
","
);
TextUtils
.
split
(
styleFormatLine
.
substring
(
SsaDecoder
.
FORMAT_LINE_PREFIX
.
length
()),
","
);
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
...
@@ -234,10 +254,13 @@ import java.util.regex.Pattern;
...
@@ -234,10 +254,13 @@ import java.util.regex.Pattern;
case
"primarycolour"
:
case
"primarycolour"
:
primaryColorIndex
=
i
;
primaryColorIndex
=
i
;
break
;
break
;
case
"fontsize"
:
fontSizeIndex
=
i
;
break
;
}
}
}
}
return
nameIndex
!=
C
.
INDEX_UNSET
return
nameIndex
!=
C
.
INDEX_UNSET
?
new
Format
(
nameIndex
,
alignmentIndex
,
primaryColorIndex
,
keys
.
length
)
?
new
Format
(
nameIndex
,
alignmentIndex
,
primaryColorIndex
,
fontSizeIndex
,
keys
.
length
)
:
null
;
:
null
;
}
}
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java
View file @
ce48a28a
...
@@ -47,7 +47,8 @@ public final class SsaDecoderTest {
...
@@ -47,7 +47,8 @@ public final class SsaDecoderTest {
private
static
final
String
INVALID_TIMECODES
=
"media/ssa/invalid_timecodes"
;
private
static
final
String
INVALID_TIMECODES
=
"media/ssa/invalid_timecodes"
;
private
static
final
String
INVALID_POSITIONS
=
"media/ssa/invalid_positioning"
;
private
static
final
String
INVALID_POSITIONS
=
"media/ssa/invalid_positioning"
;
private
static
final
String
POSITIONS_WITHOUT_PLAYRES
=
"media/ssa/positioning_without_playres"
;
private
static
final
String
POSITIONS_WITHOUT_PLAYRES
=
"media/ssa/positioning_without_playres"
;
private
static
final
String
COLORS
=
"media/ssa/colors"
;
private
static
final
String
STYLE_COLORS
=
"media/ssa/style_colors"
;
private
static
final
String
STYLE_FONT_SIZE
=
"media/ssa/style_font_size"
;
@Test
@Test
public
void
decodeEmpty
()
throws
IOException
{
public
void
decodeEmpty
()
throws
IOException
{
...
@@ -274,7 +275,7 @@ public final class SsaDecoderTest {
...
@@ -274,7 +275,7 @@ public final class SsaDecoderTest {
@Test
@Test
public
void
decodeColors
()
throws
IOException
{
public
void
decodeColors
()
throws
IOException
{
SsaDecoder
decoder
=
new
SsaDecoder
();
SsaDecoder
decoder
=
new
SsaDecoder
();
byte
[]
bytes
=
TestUtil
.
getByteArray
(
ApplicationProvider
.
getApplicationContext
(),
COLORS
);
byte
[]
bytes
=
TestUtil
.
getByteArray
(
ApplicationProvider
.
getApplicationContext
(),
STYLE_
COLORS
);
Subtitle
subtitle
=
decoder
.
decode
(
bytes
,
bytes
.
length
,
false
);
Subtitle
subtitle
=
decoder
.
decode
(
bytes
,
bytes
.
length
,
false
);
assertThat
(
subtitle
.
getEventTimeCount
()).
isEqualTo
(
14
);
assertThat
(
subtitle
.
getEventTimeCount
()).
isEqualTo
(
14
);
// &H000000FF (AABBGGRR) -> #FFFF0000 (AARRGGBB)
// &H000000FF (AABBGGRR) -> #FFFF0000 (AARRGGBB)
...
@@ -319,6 +320,22 @@ public final class SsaDecoderTest {
...
@@ -319,6 +320,22 @@ public final class SsaDecoderTest {
.
hasNoForegroundColorSpanBetween
(
0
,
seventhCueText
.
length
());
.
hasNoForegroundColorSpanBetween
(
0
,
seventhCueText
.
length
());
}
}
@Test
public
void
decodeFontSize
()
throws
IOException
{
SsaDecoder
decoder
=
new
SsaDecoder
();
byte
[]
bytes
=
TestUtil
.
getByteArray
(
ApplicationProvider
.
getApplicationContext
(),
STYLE_FONT_SIZE
);
Subtitle
subtitle
=
decoder
.
decode
(
bytes
,
bytes
.
length
,
false
);
assertThat
(
subtitle
.
getEventTimeCount
()).
isEqualTo
(
4
);
Cue
firstCue
=
Iterables
.
getOnlyElement
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
0
)));
assertThat
(
firstCue
.
textSize
).
isWithin
(
1.0
e
-
8
f
).
of
(
30
f
/
720
f
);
assertThat
(
firstCue
.
textSizeType
).
isEqualTo
(
Cue
.
TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING
);
Cue
secondCue
=
Iterables
.
getOnlyElement
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
2
)));
assertThat
(
secondCue
.
textSize
).
isWithin
(
1.0
e
-
8
f
).
of
(
72.2f
/
720
f
);
assertThat
(
secondCue
.
textSizeType
).
isEqualTo
(
Cue
.
TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING
);
}
private
static
void
assertTypicalCue1
(
Subtitle
subtitle
,
int
eventIndex
)
{
private
static
void
assertTypicalCue1
(
Subtitle
subtitle
,
int
eventIndex
)
{
assertThat
(
subtitle
.
getEventTime
(
eventIndex
)).
isEqualTo
(
0
);
assertThat
(
subtitle
.
getEventTime
(
eventIndex
)).
isEqualTo
(
0
);
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
eventIndex
)).
get
(
0
).
text
.
toString
())
assertThat
(
subtitle
.
getCues
(
subtitle
.
getEventTime
(
eventIndex
)).
get
(
0
).
text
.
toString
())
...
...
library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheWriterTest.java
View file @
ce48a28a
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.upstream.cache;
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.upstream.cache;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
CacheAsserts
.
assertCachedData
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
CacheAsserts
.
assertCachedData
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
static
java
.
lang
.
Math
.
min
;
import
static
org
.
junit
.
Assert
.
assertThrows
;
import
static
org
.
junit
.
Assert
.
assertThrows
;
import
android.net.Uri
;
import
android.net.Uri
;
...
@@ -36,65 +35,18 @@ import org.junit.After;
...
@@ -36,65 +35,18 @@ import org.junit.After;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.mockito.Answers
;
import
org.mockito.Mock
;
import
org.mockito.MockitoAnnotations
;
import
org.mockito.MockitoAnnotations
;
/** Unit tests for {@link CacheWriter}. */
/** Unit tests for {@link CacheWriter}. */
@RunWith
(
AndroidJUnit4
.
class
)
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
CacheWriterTest
{
public
final
class
CacheWriterTest
{
/**
* Abstract fake Cache implementation used by the test. This class must be public so Mockito can
* create a proxy for it.
*/
public
abstract
static
class
AbstractFakeCache
implements
Cache
{
// This array is set to alternating length of cached and not cached regions in tests:
// spansAndGaps = {<length of 1st cached region>, <length of 1st not cached region>,
// <length of 2nd cached region>, <length of 2nd not cached region>, ... }
// Ideally it should end with a cached region but it shouldn't matter for any code.
private
int
[]
spansAndGaps
;
private
long
contentLength
;
private
void
init
()
{
spansAndGaps
=
new
int
[]
{};
contentLength
=
C
.
LENGTH_UNSET
;
}
@Override
public
long
getCachedLength
(
String
key
,
long
position
,
long
length
)
{
if
(
length
==
C
.
LENGTH_UNSET
)
{
length
=
Long
.
MAX_VALUE
;
}
for
(
int
i
=
0
;
i
<
spansAndGaps
.
length
;
i
++)
{
int
spanOrGap
=
spansAndGaps
[
i
];
if
(
position
<
spanOrGap
)
{
long
left
=
min
(
spanOrGap
-
position
,
length
);
return
(
i
&
1
)
==
1
?
-
left
:
left
;
}
position
-=
spanOrGap
;
}
return
-
length
;
}
@Override
public
ContentMetadata
getContentMetadata
(
String
key
)
{
DefaultContentMetadata
metadata
=
new
DefaultContentMetadata
();
ContentMetadataMutations
mutations
=
new
ContentMetadataMutations
();
ContentMetadataMutations
.
setContentLength
(
mutations
,
contentLength
);
return
metadata
.
copyWithMutationsApplied
(
mutations
);
}
}
@Mock
(
answer
=
Answers
.
CALLS_REAL_METHODS
)
private
AbstractFakeCache
mockCache
;
private
File
tempFolder
;
private
File
tempFolder
;
private
SimpleCache
cache
;
private
SimpleCache
cache
;
@Before
@Before
public
void
setUp
()
throws
Exception
{
public
void
setUp
()
throws
Exception
{
MockitoAnnotations
.
initMocks
(
this
);
MockitoAnnotations
.
initMocks
(
this
);
mockCache
.
init
();
tempFolder
=
tempFolder
=
Util
.
createTempDirectory
(
ApplicationProvider
.
getApplicationContext
(),
"ExoPlayerTest"
);
Util
.
createTempDirectory
(
ApplicationProvider
.
getApplicationContext
(),
"ExoPlayerTest"
);
cache
=
cache
=
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
View file @
ce48a28a
...
@@ -145,12 +145,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -145,12 +145,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
* Parses a udta atom.
* Parses a udta atom.
*
*
* @param udtaAtom The udta (user data) atom to decode.
* @param udtaAtom The udta (user data) atom to decode.
* @param isQuickTime True for QuickTime media. False otherwise.
* @return A {@link Pair} containing the metadata from the meta child atom as first value (if
* @return A {@link Pair} containing the metadata from the meta child atom as first value (if
* any), and the metadata from the smta child atom as second value (if any).
* any), and the metadata from the smta child atom as second value (if any).
*/
*/
public
static
Pair
<
@NullableType
Metadata
,
@NullableType
Metadata
>
parseUdta
(
public
static
Pair
<
@NullableType
Metadata
,
@NullableType
Metadata
>
parseUdta
(
Atom
.
LeafAtom
udtaAtom
,
boolean
isQuickTime
)
{
Atom
.
LeafAtom
udtaAtom
)
{
ParsableByteArray
udtaData
=
udtaAtom
.
data
;
ParsableByteArray
udtaData
=
udtaAtom
.
data
;
udtaData
.
setPosition
(
Atom
.
HEADER_SIZE
);
udtaData
.
setPosition
(
Atom
.
HEADER_SIZE
);
@Nullable
Metadata
metaMetadata
=
null
;
@Nullable
Metadata
metaMetadata
=
null
;
...
@@ -159,8 +158,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -159,8 +158,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
int
atomPosition
=
udtaData
.
getPosition
();
int
atomPosition
=
udtaData
.
getPosition
();
int
atomSize
=
udtaData
.
readInt
();
int
atomSize
=
udtaData
.
readInt
();
int
atomType
=
udtaData
.
readInt
();
int
atomType
=
udtaData
.
readInt
();
// Meta boxes are regular boxes rather than full boxes in QuickTime. Ignore them for now.
if
(
atomType
==
Atom
.
TYPE_meta
)
{
if
(
atomType
==
Atom
.
TYPE_meta
&&
!
isQuickTime
)
{
udtaData
.
setPosition
(
atomPosition
);
udtaData
.
setPosition
(
atomPosition
);
metaMetadata
=
parseUdtaMeta
(
udtaData
,
atomPosition
+
atomSize
);
metaMetadata
=
parseUdtaMeta
(
udtaData
,
atomPosition
+
atomSize
);
}
else
if
(
atomType
==
Atom
.
TYPE_smta
)
{
}
else
if
(
atomType
==
Atom
.
TYPE_smta
)
{
...
@@ -228,6 +226,30 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -228,6 +226,30 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
}
}
/**
/**
* Possibly skips the version and flags fields (1+3 byte) of a full meta atom.
*
* <p>Atoms of type {@link Atom#TYPE_meta} are defined to be full atoms which have four additional
* bytes for a version and a flags field (see 4.2 'Object Structure' in ISO/IEC 14496-12:2005).
* QuickTime do not have such a full box structure. Since some of these files are encoded wrongly,
* we can't rely on the file type though. Instead we must check the 8 bytes after the common
* header bytes ourselves.
*
* @param meta The 8 or more bytes following the meta atom size and type.
*/
public
static
void
maybeSkipRemainingMetaAtomHeaderBytes
(
ParsableByteArray
meta
)
{
int
endPosition
=
meta
.
getPosition
();
// The next 8 bytes can be either:
// (iso) [1 byte version + 3 bytes flags][4 byte size of next atom]
// (qt) [4 byte size of next atom ][4 byte hdlr atom type ]
// In case of (iso) we need to skip the next 4 bytes.
meta
.
skipBytes
(
4
);
if
(
meta
.
readInt
()
!=
Atom
.
TYPE_hdlr
)
{
endPosition
+=
4
;
}
meta
.
setPosition
(
endPosition
);
}
/**
* Parses a trak atom (defined in ISO/IEC 14496-12).
* Parses a trak atom (defined in ISO/IEC 14496-12).
*
*
* @param trak Atom to decode.
* @param trak Atom to decode.
...
@@ -677,7 +699,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
...
@@ -677,7 +699,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
@Nullable
@Nullable
private
static
Metadata
parseUdtaMeta
(
ParsableByteArray
meta
,
int
limit
)
{
private
static
Metadata
parseUdtaMeta
(
ParsableByteArray
meta
,
int
limit
)
{
meta
.
skipBytes
(
Atom
.
FULL_HEADER_SIZE
);
meta
.
skipBytes
(
Atom
.
HEADER_SIZE
);
maybeSkipRemainingMetaAtomHeaderBytes
(
meta
);
while
(
meta
.
getPosition
()
<
limit
)
{
while
(
meta
.
getPosition
()
<
limit
)
{
int
atomPosition
=
meta
.
getPosition
();
int
atomPosition
=
meta
.
getPosition
();
int
atomSize
=
meta
.
readInt
();
int
atomSize
=
meta
.
readInt
();
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
View file @
ce48a28a
...
@@ -470,7 +470,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -470,7 +470,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
@Nullable
Atom
.
LeafAtom
udta
=
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_udta
);
@Nullable
Atom
.
LeafAtom
udta
=
moov
.
getLeafAtomOfType
(
Atom
.
TYPE_udta
);
if
(
udta
!=
null
)
{
if
(
udta
!=
null
)
{
Pair
<
@NullableType
Metadata
,
@NullableType
Metadata
>
udtaMetadata
=
Pair
<
@NullableType
Metadata
,
@NullableType
Metadata
>
udtaMetadata
=
AtomParsers
.
parseUdta
(
udta
,
isQuickTime
);
AtomParsers
.
parseUdta
(
udta
);
udtaMetaMetadata
=
udtaMetadata
.
first
;
udtaMetaMetadata
=
udtaMetadata
.
first
;
smtaMetadata
=
udtaMetadata
.
second
;
smtaMetadata
=
udtaMetadata
.
second
;
if
(
udtaMetaMetadata
!=
null
)
{
if
(
udtaMetaMetadata
!=
null
)
{
...
@@ -727,29 +727,12 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -727,29 +727,12 @@ public final class Mp4Extractor implements Extractor, SeekMap {
}
}
}
}
/**
* Possibly skips the version and flags fields (1+3 byte) of a full meta atom of the {@code
* input}.
*
* <p>Atoms of type {@link Atom#TYPE_meta} are defined to be full atoms which have four additional
* bytes for a version and a flags field (see 4.2 'Object Structure' in ISO/IEC 14496-12:2005).
* QuickTime do not have such a full box structure. Since some of these files are encoded wrongly,
* we can't rely on the file type though. Instead we must check the 8 bytes after the common
* header bytes ourselves.
*/
private
void
maybeSkipRemainingMetaAtomHeaderBytes
(
ExtractorInput
input
)
throws
IOException
{
private
void
maybeSkipRemainingMetaAtomHeaderBytes
(
ExtractorInput
input
)
throws
IOException
{
scratch
.
reset
(
8
);
scratch
.
reset
(
8
);
// Peek the next 8 bytes which can be either
// (iso) [1 byte version + 3 bytes flags][4 byte size of next atom]
// (qt) [4 byte size of next atom ][4 byte hdlr atom type ]
// In case of (iso) we need to skip the next 4 bytes.
input
.
peekFully
(
scratch
.
getData
(),
0
,
8
);
input
.
peekFully
(
scratch
.
getData
(),
0
,
8
);
scratch
.
skipBytes
(
4
);
AtomParsers
.
maybeSkipRemainingMetaAtomHeaderBytes
(
scratch
);
i
f
(
scratch
.
readInt
()
==
Atom
.
TYPE_hdlr
)
{
i
nput
.
skipFully
(
scratch
.
getPosition
());
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
}
else
{
input
.
skipFully
(
4
);
}
}
}
/** Processes an atom whose payload does not need to be parsed. */
/** Processes an atom whose payload does not need to be parsed. */
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
View file @
ce48a28a
...
@@ -913,10 +913,10 @@ public class PlayerControlView extends FrameLayout {
...
@@ -913,10 +913,10 @@ public class PlayerControlView extends FrameLayout {
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
boolean
isSeekable
=
window
.
isSeekable
;
boolean
isSeekable
=
window
.
isSeekable
;
enableSeeking
=
isSeekable
;
enableSeeking
=
isSeekable
;
enablePrevious
=
isSeekable
||
!
window
.
is
Dynamic
||
player
.
hasPrevious
();
enablePrevious
=
isSeekable
||
!
window
.
is
Live
()
||
player
.
hasPrevious
();
enableRewind
=
isSeekable
&&
controlDispatcher
.
isRewindEnabled
();
enableRewind
=
isSeekable
&&
controlDispatcher
.
isRewindEnabled
();
enableFastForward
=
isSeekable
&&
controlDispatcher
.
isFastForwardEnabled
();
enableFastForward
=
isSeekable
&&
controlDispatcher
.
isFastForwardEnabled
();
enableNext
=
window
.
isDynamic
||
player
.
hasNext
();
enableNext
=
(
window
.
isLive
()
&&
window
.
isDynamic
)
||
player
.
hasNext
();
}
}
}
}
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
View file @
ce48a28a
...
@@ -1227,10 +1227,11 @@ public class PlayerNotificationManager {
...
@@ -1227,10 +1227,11 @@ public class PlayerNotificationManager {
Timeline
timeline
=
player
.
getCurrentTimeline
();
Timeline
timeline
=
player
.
getCurrentTimeline
();
if
(!
timeline
.
isEmpty
()
&&
!
player
.
isPlayingAd
())
{
if
(!
timeline
.
isEmpty
()
&&
!
player
.
isPlayingAd
())
{
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
enablePrevious
=
window
.
isSeekable
||
!
window
.
isDynamic
||
player
.
hasPrevious
();
boolean
isSeekable
=
window
.
isSeekable
;
enableRewind
=
controlDispatcher
.
isRewindEnabled
();
enablePrevious
=
isSeekable
||
!
window
.
isLive
()
||
player
.
hasPrevious
();
enableFastForward
=
controlDispatcher
.
isFastForwardEnabled
();
enableRewind
=
isSeekable
&&
controlDispatcher
.
isRewindEnabled
();
enableNext
=
window
.
isDynamic
||
player
.
hasNext
();
enableFastForward
=
isSeekable
&&
controlDispatcher
.
isFastForwardEnabled
();
enableNext
=
(
window
.
isLive
()
&&
window
.
isDynamic
)
||
player
.
hasNext
();
}
}
List
<
String
>
stringActions
=
new
ArrayList
<>();
List
<
String
>
stringActions
=
new
ArrayList
<>();
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
View file @
ce48a28a
...
@@ -1141,10 +1141,10 @@ public class StyledPlayerControlView extends FrameLayout {
...
@@ -1141,10 +1141,10 @@ public class StyledPlayerControlView extends FrameLayout {
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
timeline
.
getWindow
(
player
.
getCurrentWindowIndex
(),
window
);
boolean
isSeekable
=
window
.
isSeekable
;
boolean
isSeekable
=
window
.
isSeekable
;
enableSeeking
=
isSeekable
;
enableSeeking
=
isSeekable
;
enablePrevious
=
isSeekable
||
!
window
.
is
Dynamic
||
player
.
hasPrevious
();
enablePrevious
=
isSeekable
||
!
window
.
is
Live
()
||
player
.
hasPrevious
();
enableRewind
=
isSeekable
&&
controlDispatcher
.
isRewindEnabled
();
enableRewind
=
isSeekable
&&
controlDispatcher
.
isRewindEnabled
();
enableFastForward
=
isSeekable
&&
controlDispatcher
.
isFastForwardEnabled
();
enableFastForward
=
isSeekable
&&
controlDispatcher
.
isFastForwardEnabled
();
enableNext
=
window
.
isDynamic
||
player
.
hasNext
();
enableNext
=
(
window
.
isLive
()
&&
window
.
isDynamic
)
||
player
.
hasNext
();
}
}
}
}
...
...
library/ui/src/main/res/layout/exo_styled_player_control_ffwd_button.xml
View file @
ce48a28a
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
android:addStatesFromChildren=
"true"
android:addStatesFromChildren=
"true"
style=
"@style/ExoStyledControls.Button.Center"
>
style=
"@style/ExoStyledControls.Button.Center"
>
<!-- View's don't have foreground until API 23 so we have to nest in a parent. -->
<!-- View's don't have foreground until API 23 so we have to nest in a parent. -->
<Button
android:id=
"@
+
id/exo_ffwd_with_amount"
<Button
android:id=
"@id/exo_ffwd_with_amount"
android:background=
"@drawable/exo_styled_controls_fastforward"
android:background=
"@drawable/exo_styled_controls_fastforward"
android:layout_marginLeft=
"0dp"
android:layout_marginLeft=
"0dp"
android:layout_marginRight=
"0dp"
android:layout_marginRight=
"0dp"
...
...
library/ui/src/main/res/layout/exo_styled_player_control_rewind_button.xml
View file @
ce48a28a
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
android:addStatesFromChildren=
"true"
android:addStatesFromChildren=
"true"
style=
"@style/ExoStyledControls.Button.Center"
>
style=
"@style/ExoStyledControls.Button.Center"
>
<!-- View's don't have foreground until API 23 so we have to nest in a parent. -->
<!-- View's don't have foreground until API 23 so we have to nest in a parent. -->
<Button
android:id=
"@
+
id/exo_rew_with_amount"
<Button
android:id=
"@id/exo_rew_with_amount"
android:background=
"@drawable/exo_styled_controls_rewind"
android:background=
"@drawable/exo_styled_controls_rewind"
android:layout_marginLeft=
"0dp"
android:layout_marginLeft=
"0dp"
android:layout_marginRight=
"0dp"
android:layout_marginRight=
"0dp"
...
...
library/ui/src/main/res/layout/exo_styled_player_control_view.xml
View file @
ce48a28a
...
@@ -15,13 +15,13 @@
...
@@ -15,13 +15,13 @@
-->
-->
<merge
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<merge
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<View
android:id=
"@
+
id/exo_controls_background"
<View
android:id=
"@id/exo_controls_background"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_height=
"match_parent"
android:layout_gravity=
"center"
android:layout_gravity=
"center"
android:background=
"@color/exo_black_opacity_60"
/>
android:background=
"@color/exo_black_opacity_60"
/>
<FrameLayout
android:id=
"@
+
id/exo_bottom_bar"
<FrameLayout
android:id=
"@id/exo_bottom_bar"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"@dimen/exo_styled_bottom_bar_height"
android:layout_height=
"@dimen/exo_styled_bottom_bar_height"
android:layout_marginTop=
"@dimen/exo_styled_bottom_bar_margin_top"
android:layout_marginTop=
"@dimen/exo_styled_bottom_bar_margin_top"
...
@@ -29,7 +29,7 @@
...
@@ -29,7 +29,7 @@
android:background=
"@color/exo_bottom_bar_background"
android:background=
"@color/exo_bottom_bar_background"
android:layoutDirection=
"ltr"
>
android:layoutDirection=
"ltr"
>
<LinearLayout
android:id=
"@
+
id/exo_time"
<LinearLayout
android:id=
"@id/exo_time"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:paddingStart=
"@dimen/exo_styled_bottom_bar_time_padding"
android:paddingStart=
"@dimen/exo_styled_bottom_bar_time_padding"
...
@@ -39,58 +39,58 @@
...
@@ -39,58 +39,58 @@
android:layout_gravity=
"center_vertical|start"
android:layout_gravity=
"center_vertical|start"
android:layoutDirection=
"ltr"
>
android:layoutDirection=
"ltr"
>
<TextView
android:id=
"@
+
id/exo_position"
<TextView
android:id=
"@id/exo_position"
style=
"@style/ExoStyledControls.TimeText.Position"
/>
style=
"@style/ExoStyledControls.TimeText.Position"
/>
<TextView
<TextView
style=
"@style/ExoStyledControls.TimeText.Separator"
/>
style=
"@style/ExoStyledControls.TimeText.Separator"
/>
<TextView
android:id=
"@
+
id/exo_duration"
<TextView
android:id=
"@id/exo_duration"
style=
"@style/ExoStyledControls.TimeText.Duration"
/>
style=
"@style/ExoStyledControls.TimeText.Duration"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id=
"@
+
id/exo_basic_controls"
<LinearLayout
android:id=
"@id/exo_basic_controls"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical|end"
android:layout_gravity=
"center_vertical|end"
android:layoutDirection=
"ltr"
>
android:layoutDirection=
"ltr"
>
<ImageButton
android:id=
"@
+
id/exo_vr"
<ImageButton
android:id=
"@id/exo_vr"
style=
"@style/ExoStyledControls.Button.Bottom.VR"
/>
style=
"@style/ExoStyledControls.Button.Bottom.VR"
/>
<ImageButton
android:id=
"@
+
id/exo_shuffle"
<ImageButton
android:id=
"@id/exo_shuffle"
style=
"@style/ExoStyledControls.Button.Bottom.Shuffle"
/>
style=
"@style/ExoStyledControls.Button.Bottom.Shuffle"
/>
<ImageButton
android:id=
"@
+
id/exo_repeat_toggle"
<ImageButton
android:id=
"@id/exo_repeat_toggle"
style=
"@style/ExoStyledControls.Button.Bottom.RepeatToggle"
/>
style=
"@style/ExoStyledControls.Button.Bottom.RepeatToggle"
/>
<ImageButton
android:id=
"@
+
id/exo_subtitle"
<ImageButton
android:id=
"@id/exo_subtitle"
style=
"@style/ExoStyledControls.Button.Bottom.CC"
/>
style=
"@style/ExoStyledControls.Button.Bottom.CC"
/>
<ImageButton
android:id=
"@
+
id/exo_settings"
<ImageButton
android:id=
"@id/exo_settings"
style=
"@style/ExoStyledControls.Button.Bottom.Settings"
/>
style=
"@style/ExoStyledControls.Button.Bottom.Settings"
/>
<ImageButton
android:id=
"@
+
id/exo_fullscreen"
<ImageButton
android:id=
"@id/exo_fullscreen"
style=
"@style/ExoStyledControls.Button.Bottom.FullScreen"
/>
style=
"@style/ExoStyledControls.Button.Bottom.FullScreen"
/>
<ImageButton
android:id=
"@
+
id/exo_overflow_show"
<ImageButton
android:id=
"@id/exo_overflow_show"
style=
"@style/ExoStyledControls.Button.Bottom.OverflowShow"
/>
style=
"@style/ExoStyledControls.Button.Bottom.OverflowShow"
/>
</LinearLayout>
</LinearLayout>
<HorizontalScrollView
android:id=
"@
+
id/exo_extra_controls_scroll_view"
<HorizontalScrollView
android:id=
"@id/exo_extra_controls_scroll_view"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center_vertical|end"
android:layout_gravity=
"center_vertical|end"
android:visibility=
"invisible"
>
android:visibility=
"invisible"
>
<LinearLayout
android:id=
"@
+
id/exo_extra_controls"
<LinearLayout
android:id=
"@id/exo_extra_controls"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layoutDirection=
"ltr"
>
android:layoutDirection=
"ltr"
>
<ImageButton
android:id=
"@
+
id/exo_overflow_hide"
<ImageButton
android:id=
"@id/exo_overflow_hide"
style=
"@style/ExoStyledControls.Button.Bottom.OverflowHide"
/>
style=
"@style/ExoStyledControls.Button.Bottom.OverflowHide"
/>
</LinearLayout>
</LinearLayout>
...
@@ -99,13 +99,13 @@
...
@@ -99,13 +99,13 @@
</FrameLayout>
</FrameLayout>
<View
android:id=
"@
+
id/exo_progress_placeholder"
<View
android:id=
"@id/exo_progress_placeholder"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"@dimen/exo_styled_progress_layout_height"
android:layout_height=
"@dimen/exo_styled_progress_layout_height"
android:layout_gravity=
"bottom"
android:layout_gravity=
"bottom"
android:layout_marginBottom=
"@dimen/exo_styled_progress_margin_bottom"
/>
android:layout_marginBottom=
"@dimen/exo_styled_progress_margin_bottom"
/>
<LinearLayout
android:id=
"@
+
id/exo_minimal_controls"
<LinearLayout
android:id=
"@id/exo_minimal_controls"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"bottom|end"
android:layout_gravity=
"bottom|end"
...
@@ -114,13 +114,13 @@
...
@@ -114,13 +114,13 @@
android:gravity=
"center_vertical"
android:gravity=
"center_vertical"
android:layoutDirection=
"ltr"
>
android:layoutDirection=
"ltr"
>
<ImageButton
android:id=
"@
+
id/exo_minimal_fullscreen"
<ImageButton
android:id=
"@id/exo_minimal_fullscreen"
style=
"@style/ExoStyledControls.Button.Bottom.FullScreen"
/>
style=
"@style/ExoStyledControls.Button.Bottom.FullScreen"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
<LinearLayout
android:id=
"@
+
id/exo_center_controls"
android:id=
"@id/exo_center_controls"
android:layout_width=
"wrap_content"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_gravity=
"center"
android:layout_gravity=
"center"
...
@@ -128,18 +128,17 @@
...
@@ -128,18 +128,17 @@
android:gravity=
"center"
android:gravity=
"center"
android:padding=
"@dimen/exo_styled_controls_padding"
>
android:padding=
"@dimen/exo_styled_controls_padding"
>
<ImageButton
android:id=
"@id/exo_prev"
<ImageButton
android:id=
"@+id/exo_prev"
style=
"@style/ExoStyledControls.Button.Center.Previous"
/>
style=
"@style/ExoStyledControls.Button.Center.Previous"
/>
<include
layout=
"@layout/exo_styled_player_control_rewind_button"
/>
<include
layout=
"@layout/exo_styled_player_control_rewind_button"
/>
<ImageButton
android:id=
"@
+
id/exo_play_pause"
<ImageButton
android:id=
"@id/exo_play_pause"
style=
"@style/ExoStyledControls.Button.Center.PlayPause"
/>
style=
"@style/ExoStyledControls.Button.Center.PlayPause"
/>
<include
layout=
"@layout/exo_styled_player_control_ffwd_button"
/>
<include
layout=
"@layout/exo_styled_player_control_ffwd_button"
/>
<ImageButton
android:id=
"@
+
id/exo_next"
<ImageButton
android:id=
"@id/exo_next"
style=
"@style/ExoStyledControls.Button.Center.Next"
/>
style=
"@style/ExoStyledControls.Button.Center.Next"
/>
</LinearLayout>
</LinearLayout>
...
...
library/ui/src/main/res/layout/exo_styled_settings_list_item.xml
View file @
ce48a28a
...
@@ -58,4 +58,5 @@
...
@@ -58,4 +58,5 @@
android:textDirection=
"locale"
android:textDirection=
"locale"
android:textSize=
"@dimen/exo_settings_sub_text_size"
/>
android:textSize=
"@dimen/exo_settings_sub_text_size"
/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
library/ui/src/main/res/layout/exo_styled_sub_settings_list_item.xml
View file @
ce48a28a
...
@@ -43,4 +43,5 @@
...
@@ -43,4 +43,5 @@
android:textColor=
"@color/exo_white"
android:textColor=
"@color/exo_white"
android:textDirection=
"locale"
android:textDirection=
"locale"
android:textSize=
"@dimen/exo_settings_main_text_size"
/>
android:textSize=
"@dimen/exo_settings_main_text_size"
/>
</LinearLayout>
</LinearLayout>
library/ui/src/main/res/values/ids.xml
View file @
ce48a28a
...
@@ -27,7 +27,9 @@
...
@@ -27,7 +27,9 @@
<item
name=
"exo_pause"
type=
"id"
/>
<item
name=
"exo_pause"
type=
"id"
/>
<item
name=
"exo_play_pause"
type=
"id"
/>
<item
name=
"exo_play_pause"
type=
"id"
/>
<item
name=
"exo_rew"
type=
"id"
/>
<item
name=
"exo_rew"
type=
"id"
/>
<item
name=
"exo_rew_with_amount"
type=
"id"
/>
<item
name=
"exo_ffwd"
type=
"id"
/>
<item
name=
"exo_ffwd"
type=
"id"
/>
<item
name=
"exo_ffwd_with_amount"
type=
"id"
/>
<item
name=
"exo_prev"
type=
"id"
/>
<item
name=
"exo_prev"
type=
"id"
/>
<item
name=
"exo_next"
type=
"id"
/>
<item
name=
"exo_next"
type=
"id"
/>
<item
name=
"exo_shuffle"
type=
"id"
/>
<item
name=
"exo_shuffle"
type=
"id"
/>
...
@@ -41,4 +43,17 @@
...
@@ -41,4 +43,17 @@
<item
name=
"exo_vr"
type=
"id"
/>
<item
name=
"exo_vr"
type=
"id"
/>
<item
name=
"exo_subtitle"
type=
"id"
/>
<item
name=
"exo_subtitle"
type=
"id"
/>
<item
name=
"exo_fullscreen"
type=
"id"
/>
<item
name=
"exo_fullscreen"
type=
"id"
/>
<item
name=
"exo_settings"
type=
"id"
/>
<item
name=
"exo_controls_background"
type=
"id"
/>
<item
name=
"exo_basic_controls"
type=
"id"
/>
<item
name=
"exo_center_controls"
type=
"id"
/>
<item
name=
"exo_bottom_bar"
type=
"id"
/>
<item
name=
"exo_time"
type=
"id"
/>
<item
name=
"exo_overflow_show"
type=
"id"
/>
<item
name=
"exo_overflow_hide"
type=
"id"
/>
<item
name=
"exo_extra_controls"
type=
"id"
/>
<item
name=
"exo_extra_controls_scroll_view"
type=
"id"
/>
<item
name=
"exo_minimal_fullscreen"
type=
"id"
/>
<item
name=
"exo_minimal_controls"
type=
"id"
/>
</resources>
</resources>
publish.gradle
View file @
ce48a28a
...
@@ -11,8 +11,10 @@
...
@@ -11,8 +11,10 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// See the License for the specific language governing permissions and
// limitations under the License.
// limitations under the License.
if
(
project
.
ext
.
has
(
"exoplayerPublishEnabled"
)
if
(
project
.
ext
.
has
(
"exoplayerPublishEnabled"
)
&&
project
.
ext
.
exoplayerPublishEnabled
)
{
&&
project
.
ext
.
exoplayerPublishEnabled
)
{
// For publishing to Bintray.
apply
plugin:
'bintray-release'
apply
plugin:
'bintray-release'
publish
{
publish
{
artifactId
=
releaseArtifact
artifactId
=
releaseArtifact
...
@@ -38,6 +40,47 @@ if (project.ext.has("exoplayerPublishEnabled")
...
@@ -38,6 +40,47 @@ if (project.ext.has("exoplayerPublishEnabled")
}
}
}
}
}
}
}
else
{
// For publishing to a Maven repository.
apply
plugin:
'maven-publish'
afterEvaluate
{
publishing
{
repositories
{
maven
{
url
=
findProperty
(
'mavenRepo'
)
?:
"${buildDir}/repo"
}
}
publications
{
release
(
MavenPublication
)
{
from
components
.
release
artifact
androidSourcesJar
groupId
=
'com.google.android.exoplayer'
artifactId
=
releaseArtifact
version
releaseVersion
pom
{
name
=
releaseArtifact
description
=
releaseDescription
licenses
{
license
{
name
=
'The Apache Software License, Version 2.0'
url
=
'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution
=
'repo'
}
}
developers
{
developer
{
name
=
'The Android Open Source Project'
}
}
scm
{
connection
=
'scm:git:https://github.com/google/ExoPlayer.git'
url
=
'https://github.com/google/ExoPlayer'
}
}
}
}
}
}
}
}
def
getBintrayRepo
()
{
def
getBintrayRepo
()
{
...
@@ -66,3 +109,8 @@ static void addLicense(File pom) {
...
@@ -66,3 +109,8 @@ static void addLicense(File pom) {
printer
.
print
(
xml
)
printer
.
print
(
xml
)
writer
.
close
()
writer
.
close
()
}
}
task
androidSourcesJar
(
type:
Jar
)
{
archiveClassifier
.
set
(
'sources'
)
from
android
.
sourceSets
.
main
.
java
.
srcDirs
}
testdata/src/test/assets/media/ssa/colors
→
testdata/src/test/assets/media/ssa/
style_
colors
View file @
ce48a28a
File moved
testdata/src/test/assets/media/ssa/style_font_size
0 → 100644
View file @
ce48a28a
[Script Info]
Title: SSA/ASS Test
Original Script: Arnold Szabo
Script Type: V4.00+
PlayResX: 1280
PlayResY: 720
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: FontSizeSmall ,Roboto,30, &H000000FF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,3,0,2,50,50,70,1
Style: FontSizeBig ,Roboto,72.2,&H000000FF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,3,0,2,50,50,70,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:00.95,0:00:03.11,FontSizeSmall ,Arnold,0,0,0,,First line with font size 30.
Dialogue: 0,0:00:08.50,0:00:11.50,FontSizeBig ,Arnold,0,0,0,,Second line with font size 72.2.
testutils/src/main/java/com/google/android/exoplayer2/testutil/HttpDataSourceTestEnv.java
View file @
ce48a28a
...
@@ -147,7 +147,6 @@ public class HttpDataSourceTestEnv extends ExternalResource {
...
@@ -147,7 +147,6 @@ public class HttpDataSourceTestEnv extends ExternalResource {
.
setName
(
name
)
.
setName
(
name
)
.
setUri
(
Uri
.
parse
(
server
.
url
(
resource
.
getPath
()).
toString
()))
.
setUri
(
Uri
.
parse
(
server
.
url
(
resource
.
getPath
()).
toString
()))
.
setExpectedBytes
(
resource
.
getData
())
.
setExpectedBytes
(
resource
.
getData
())
.
setEndOfInputExpected
(!
resource
.
resolvesToUnknownLength
())
.
build
();
.
build
();
}
}
}
}
testutils/src/main/java/com/google/android/exoplayer2/testutil/WebServerDispatcher.java
View file @
ce48a28a
...
@@ -33,6 +33,7 @@ import com.google.common.collect.Maps;
...
@@ -33,6 +33,7 @@ import com.google.common.collect.Maps;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.RetentionPolicy
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
import
java.util.regex.Matcher
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.regex.Pattern
;
...
@@ -277,21 +278,19 @@ public class WebServerDispatcher extends Dispatcher {
...
@@ -277,21 +278,19 @@ public class WebServerDispatcher extends Dispatcher {
if
(!
resource
.
supportsRangeRequests
()
||
rangeHeader
==
null
)
{
if
(!
resource
.
supportsRangeRequests
()
||
rangeHeader
==
null
)
{
switch
(
preferredContentCoding
)
{
switch
(
preferredContentCoding
)
{
case
"gzip"
:
case
"gzip"
:
setResponseBody
(
response
,
Util
.
gzip
(
resourceData
),
/* chunked= */
resource
.
resolvesToUnknownLength
);
response
response
.
setBody
(
new
Buffer
().
write
(
Util
.
gzip
(
resourceData
)))
.
setHeader
(
"Content-Encoding"
,
"gzip"
);
.
setHeader
(
"Content-Encoding"
,
"gzip"
);
break
;
break
;
case
"identity"
:
case
"identity"
:
setResponseBody
(
response
,
resourceData
,
/* chunked= */
resource
.
resolvesToUnknownLength
);
response
response
.
setBody
(
new
Buffer
().
write
(
resourceData
))
.
setHeader
(
"Content-Encoding"
,
"identity"
);
.
setHeader
(
"Content-Encoding"
,
"identity"
);
break
;
break
;
default
:
default
:
throw
new
IllegalStateException
(
"Unexpected content coding: "
+
preferredContentCoding
);
throw
new
IllegalStateException
(
"Unexpected content coding: "
+
preferredContentCoding
);
}
}
if
(
resource
.
resolvesToUnknownLength
())
{
response
.
setHeader
(
"Content-Length"
,
""
);
}
return
response
;
return
response
;
}
}
...
@@ -328,11 +327,11 @@ public class WebServerDispatcher extends Dispatcher {
...
@@ -328,11 +327,11 @@ public class WebServerDispatcher extends Dispatcher {
+
"-"
+
"-"
+
(
resourceData
.
length
-
1
)
+
(
resourceData
.
length
-
1
)
+
"/"
+
"/"
+
(
resource
.
resolvesToUnknownLength
()
?
"*"
:
resourceData
.
length
))
+
(
resource
.
resolvesToUnknownLength
()
?
"*"
:
resourceData
.
length
))
;
.
setBody
(
new
Buffer
().
write
(
resourceData
,
start
,
resourceData
.
length
-
start
));
setResponseBody
(
if
(
resource
.
resolvesToUnknownLength
())
{
response
,
response
.
setHeader
(
"Content-Length"
,
""
);
Arrays
.
copyOfRange
(
resourceData
,
start
,
resourceData
.
length
),
}
/* chunked= */
resource
.
resolvesToUnknownLength
);
return
response
;
return
response
;
}
}
...
@@ -345,7 +344,7 @@ public class WebServerDispatcher extends Dispatcher {
...
@@ -345,7 +344,7 @@ public class WebServerDispatcher extends Dispatcher {
}
}
int
end
=
min
(
range
.
second
+
1
,
resourceData
.
length
);
int
end
=
min
(
range
.
second
+
1
,
resourceData
.
length
);
re
turn
re
sponse
response
.
setResponseCode
(
206
)
.
setResponseCode
(
206
)
.
setHeader
(
.
setHeader
(
"Content-Range"
,
"Content-Range"
,
...
@@ -354,8 +353,26 @@ public class WebServerDispatcher extends Dispatcher {
...
@@ -354,8 +353,26 @@ public class WebServerDispatcher extends Dispatcher {
+
"-"
+
"-"
+
(
end
-
1
)
+
(
end
-
1
)
+
"/"
+
"/"
+
(
resource
.
resolvesToUnknownLength
()
?
"*"
:
resourceData
.
length
))
+
(
resource
.
resolvesToUnknownLength
()
?
"*"
:
resourceData
.
length
));
.
setBody
(
new
Buffer
().
write
(
resourceData
,
range
.
first
,
end
-
range
.
first
));
setResponseBody
(
response
,
Arrays
.
copyOfRange
(
resourceData
,
range
.
first
,
end
),
/* chunked= */
false
);
return
response
;
}
/**
* Populates a response with the specified body.
*
* @param response The response whose body should be populated.
* @param body The body data.
* @param chunked Whether to use chunked transfer encoding. Note that if set to {@code true}, the
* "Content-Length" header will not be set.
*/
private
static
void
setResponseBody
(
MockResponse
response
,
byte
[]
body
,
boolean
chunked
)
{
if
(
chunked
)
{
response
.
setChunkedBody
(
new
Buffer
().
write
(
body
),
/* maxChunkSize= */
Integer
.
MAX_VALUE
);
}
else
{
response
.
setBody
(
new
Buffer
().
write
(
body
));
}
}
}
/**
/**
...
...
testutils/src/test/java/com/google/android/exoplayer2/testutil/WebServerDispatcherTest.java
View file @
ce48a28a
...
@@ -257,7 +257,7 @@ public class WebServerDispatcherTest {
...
@@ -257,7 +257,7 @@ public class WebServerDispatcherTest {
try
(
Response
response
=
client
.
newCall
(
request
).
execute
())
{
try
(
Response
response
=
client
.
newCall
(
request
).
execute
())
{
assertThat
(
response
.
code
()).
isEqualTo
(
200
);
assertThat
(
response
.
code
()).
isEqualTo
(
200
);
assertThat
(
response
.
header
(
"Accept-Ranges"
)).
isEqualTo
(
"bytes"
);
assertThat
(
response
.
header
(
"Accept-Ranges"
)).
isEqualTo
(
"bytes"
);
assertThat
(
response
.
header
(
"Content-Length"
)).
is
Empty
();
assertThat
(
response
.
header
(
"Content-Length"
)).
is
Null
();
assertThat
(
response
.
header
(
"Content-Range"
)).
isNull
();
assertThat
(
response
.
header
(
"Content-Range"
)).
isNull
();
assertThat
(
response
.
body
().
contentLength
()).
isEqualTo
(-
1
);
assertThat
(
response
.
body
().
contentLength
()).
isEqualTo
(-
1
);
...
@@ -298,7 +298,7 @@ public class WebServerDispatcherTest {
...
@@ -298,7 +298,7 @@ public class WebServerDispatcherTest {
try
(
Response
response
=
client
.
newCall
(
request
).
execute
())
{
try
(
Response
response
=
client
.
newCall
(
request
).
execute
())
{
assertThat
(
response
.
code
()).
isEqualTo
(
206
);
assertThat
(
response
.
code
()).
isEqualTo
(
206
);
assertThat
(
response
.
header
(
"Accept-Ranges"
)).
isEqualTo
(
"bytes"
);
assertThat
(
response
.
header
(
"Accept-Ranges"
)).
isEqualTo
(
"bytes"
);
assertThat
(
response
.
header
(
"Content-Length"
)).
is
Empty
();
assertThat
(
response
.
header
(
"Content-Length"
)).
is
Null
();
assertThat
(
response
.
header
(
"Content-Range"
)).
isEqualTo
(
"bytes 5-19/*"
);
assertThat
(
response
.
header
(
"Content-Range"
)).
isEqualTo
(
"bytes 5-19/*"
);
assertThat
(
response
.
body
().
contentLength
()).
isEqualTo
(-
1
);
assertThat
(
response
.
body
().
contentLength
()).
isEqualTo
(-
1
);
...
...
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