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
6b0e1758
authored
Dec 01, 2018
by
Oliver Woodman
Committed by
GitHub
Dec 01, 2018
Browse files
Options
_('Browse Files')
Download
Plain Diff
Merge pull request #5164 from google/dev-v2-r2.9.2
r2.9.2
parents
b5beb326
a94fa330
Hide whitespace changes
Inline
Side-by-side
Showing
66 changed files
with
640 additions
and
389 deletions
CONTRIBUTING.md
RELEASENOTES.md
constants.gradle
demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/DemoUtil.java
demos/ima/src/main/res/values/strings.xml
extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java
extensions/ffmpeg/README.md
extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java
extensions/ima/build.gradle
extensions/ima/src/main/AndroidManifest.xml
extensions/ima/src/main/proguard-rules.txt
extensions/mediasession/build.gradle
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java
extensions/rtmp/build.gradle
extensions/rtmp/src/test/AndroidManifest.xml
extensions/rtmp/src/test/java/com/google/android/exoplayer2/ext/rtmp/DefaultDataSourceTest.java
library/core/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
library/core/src/main/java/com/google/android/exoplayer2/Timeline.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java
library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java
library/core/src/main/java/com/google/android/exoplayer2/source/ShuffleOrder.java
library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java
library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java
library/core/src/main/java/com/google/android/exoplayer2/trackselection/BaseTrackSelection.java
library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java
library/core/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java
library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
library/core/src/test/assets/ts/sample.ts.1.dump
library/core/src/test/assets/ts/sample.ts.2.dump
library/core/src/test/java/com/google/android/exoplayer2/DefaultLoadControlTest.java
library/core/src/test/java/com/google/android/exoplayer2/source/ShuffleOrderTest.java
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.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/PlayerEmsgHandler.java
library/dash/src/main/proguard-rules.txt
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
library/hls/src/main/proguard-rules.txt
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java
library/smoothstreaming/src/main/proguard-rules.txt
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/TouchTracker.java
library/ui/src/main/res/values/attrs.xml
testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java
CONTRIBUTING.md
View file @
6b0e1758
...
@@ -16,9 +16,8 @@ all of the information requested in the issue template.
...
@@ -16,9 +16,8 @@ all of the information requested in the issue template.
## Pull requests ##
## Pull requests ##
We will also consider high quality pull requests. These should normally merge
We will also consider high quality pull requests. These should normally merge
into the
`dev-vX`
branch with the highest major version number. Bug fixes may
into the
`dev-v2`
branch. Before a pull request can be accepted you must submit
be suitable for merging into older
`dev-vX`
branches. Before a pull request can
a Contributor License Agreement, as described below.
be accepted you must submit a Contributor License Agreement, as described below.
[
dev
]:
https://github.com/google/ExoPlayer/tree/dev
[
dev
]:
https://github.com/google/ExoPlayer/tree/dev
...
...
RELEASENOTES.md
View file @
6b0e1758
# Release notes #
# Release notes #
### 2.9.2 ###
*
HLS:
*
Fix issue causing unnecessary media playlist requests when playing live
streams (
[
#5059
](
https://github.com/google/ExoPlayer/issues/5059
)
).
*
Fix decoder re-instantiation issue for packed audio streams
(
[
#5063
](
https://github.com/google/ExoPlayer/issues/5063
)
).
*
MP4: Support Opus and FLAC in the MP4 container, and in DASH
(
[
#4883
](
https://github.com/google/ExoPlayer/issues/4883
)
).
*
DASH: Fix detecting the end of live events
(
[
#4780
](
https://github.com/google/ExoPlayer/issues/4780
)
).
*
Spherical video: Fall back to
`TYPE_ROTATION_VECTOR`
if
`TYPE_GAME_ROTATION_VECTOR`
is unavailable
(
[
#5119
](
https://github.com/google/ExoPlayer/issues/5119
)
).
*
Support seeking for a wider range of MPEG-TS streams
(
[
#5097
](
https://github.com/google/ExoPlayer/issues/5097
)
).
*
Include channel count in audio capabilities check
(
[
#4690
](
https://github.com/google/ExoPlayer/issues/4690
)
).
*
Fix issue with applying the
`show_buffering`
attribute in
`PlayerView`
(
[
#5139
](
https://github.com/google/ExoPlayer/issues/5139
)
).
*
Fix issue where null
`Metadata`
was output when it failed to decode
(
[
#5149
](
https://github.com/google/ExoPlayer/issues/5149
)
).
*
Fix playback of some invalid but playable MP4 streams by replacing assertions
with logged warnings in sample table parsing code
(
[
#5162
](
https://github.com/google/ExoPlayer/issues/5162
)
).
*
Fix UUID passed to
`MediaCrypto`
when using
`C.CLEARKEY_UUID`
before API 27.
### 2.9.1 ###
### 2.9.1 ###
*
Add convenience methods
`Player.next`
,
`Player.previous`
,
`Player.hasNext`
*
Add convenience methods
`Player.next`
,
`Player.previous`
,
`Player.hasNext`
...
@@ -20,7 +47,7 @@
...
@@ -20,7 +47,7 @@
*
DASH: Parse ProgramInformation element if present in the manifest.
*
DASH: Parse ProgramInformation element if present in the manifest.
*
HLS:
*
HLS:
*
Add constructor to
`DefaultHlsExtractorFactory`
for adding TS payload
*
Add constructor to
`DefaultHlsExtractorFactory`
for adding TS payload
reader factory flags
reader factory flags
.
*
Fix bug in segment sniffing
*
Fix bug in segment sniffing
(
[
#5039
](
https://github.com/google/ExoPlayer/issues/5039
)
).
(
[
#5039
](
https://github.com/google/ExoPlayer/issues/5039
)
).
(
[
#4861
](
https://github.com/google/ExoPlayer/issues/4861
)
).
(
[
#4861
](
https://github.com/google/ExoPlayer/issues/4861
)
).
...
...
constants.gradle
View file @
6b0e1758
...
@@ -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.9.
1
'
releaseVersion
=
'2.9.
2
'
releaseVersionCode
=
200900
1
releaseVersionCode
=
200900
2
// Important: ExoPlayer specifies a minSdkVersion of 14 because various
// Important: ExoPlayer specifies a minSdkVersion of 14 because various
// components provided by the library may be of use on older devices.
// components provided by the library may be of use on older devices.
// However, please note that the core media playback functionality provided
// However, please note that the core media playback functionality provided
...
...
demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/DemoUtil.java
View file @
6b0e1758
...
@@ -81,8 +81,6 @@ import java.util.List;
...
@@ -81,8 +81,6 @@ import java.util.List;
+
"hls/TearsOfSteel.m3u8"
,
"Tears of Steel (HLS)"
,
MIME_TYPE_HLS
));
+
"hls/TearsOfSteel.m3u8"
,
"Tears of Steel (HLS)"
,
MIME_TYPE_HLS
));
samples
.
add
(
new
Sample
(
"https://html5demos.com/assets/dizzy.mp4"
,
"Dizzy (MP4)"
,
samples
.
add
(
new
Sample
(
"https://html5demos.com/assets/dizzy.mp4"
,
"Dizzy (MP4)"
,
MIME_TYPE_VIDEO_MP4
));
MIME_TYPE_VIDEO_MP4
));
SAMPLES
=
Collections
.
unmodifiableList
(
samples
);
SAMPLES
=
Collections
.
unmodifiableList
(
samples
);
}
}
...
...
demos/ima/src/main/res/values/strings.xml
View file @
6b0e1758
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
<string
name=
"application_name"
>
Exo IMA Demo
</string>
<string
name=
"application_name"
>
Exo IMA Demo
</string>
<string
name=
"content_url"
>
<![CDATA[http
://rmcdn.2mdn.net/MotifFiles/html/1248596/android_1330378998288.mp4
]]>
</string>
<string
name=
"content_url"
>
<![CDATA[http
s://storage.googleapis.com/exoplayer-test-media-1/mkv/android-screens-lavf-56.36.100-aac-avc-main-1280x720.mkv
]]>
</string>
<string
name=
"ad_tag_url"
>
<![CDATA[https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=]]>
</string>
<string
name=
"ad_tag_url"
>
<![CDATA[https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=]]>
</string>
...
...
extensions/cronet/src/main/java/com/google/android/exoplayer2/ext/cronet/CronetDataSource.java
View file @
6b0e1758
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
com
.
google
.
android
.
exoplayer2
.
ext
.
cronet
;
package
com
.
google
.
android
.
exoplayer2
.
ext
.
cronet
;
import
android.net.Uri
;
import
android.net.Uri
;
import
android.support.annotation.Nullable
;
import
android.text.TextUtils
;
import
android.text.TextUtils
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
...
@@ -455,6 +456,18 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
...
@@ -455,6 +456,18 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
}
}
}
}
/** Returns current {@link UrlRequest}. May be null if the data source is not opened. */
@Nullable
protected
UrlRequest
getCurrentUrlRequest
()
{
return
currentUrlRequest
;
}
/** Returns current {@link UrlResponseInfo}. May be null if the data source is not opened. */
@Nullable
protected
UrlResponseInfo
getCurrentUrlResponseInfo
()
{
return
responseInfo
;
}
// Internal methods.
// Internal methods.
private
UrlRequest
.
Builder
buildRequestBuilder
(
DataSpec
dataSpec
)
throws
IOException
{
private
UrlRequest
.
Builder
buildRequestBuilder
(
DataSpec
dataSpec
)
throws
IOException
{
...
...
extensions/ffmpeg/README.md
View file @
6b0e1758
...
@@ -46,7 +46,7 @@ HOST_PLATFORM="linux-x86_64"
...
@@ -46,7 +46,7 @@ HOST_PLATFORM="linux-x86_64"
be supported. See the
[
Supported formats
][]
page for more details of the
be supported. See the
[
Supported formats
][]
page for more details of the
available flags.
available flags.
For example, to fetch and build for armeabi-v7a,
For example, to fetch and build
FFmpeg release 4.0
for armeabi-v7a,
arm64-v8a and x86 on Linux x86_64:
arm64-v8a and x86 on Linux x86_64:
```
```
...
@@ -71,7 +71,7 @@ COMMON_OPTIONS="\
...
@@ -71,7 +71,7 @@ COMMON_OPTIONS="\
" && \
" && \
cd "${FFMPEG_EXT_PATH}/jni" && \
cd "${FFMPEG_EXT_PATH}/jni" && \
(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 && \
cd ffmpeg &&
git checkout release/4.0 &&
\
./configure \
./configure \
--libdir=android-libs/armeabi-v7a \
--libdir=android-libs/armeabi-v7a \
--arch=arm \
--arch=arm \
...
...
extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegAudioRenderer.java
View file @
6b0e1758
...
@@ -145,12 +145,13 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
...
@@ -145,12 +145,13 @@ public final class FfmpegAudioRenderer extends SimpleDecoderAudioRenderer {
}
}
private
boolean
isOutputSupported
(
Format
inputFormat
)
{
private
boolean
isOutputSupported
(
Format
inputFormat
)
{
return
shouldUseFloatOutput
(
inputFormat
)
||
supportsOutputEncoding
(
C
.
ENCODING_PCM_16BIT
);
return
shouldUseFloatOutput
(
inputFormat
)
||
supportsOutput
(
inputFormat
.
channelCount
,
C
.
ENCODING_PCM_16BIT
);
}
}
private
boolean
shouldUseFloatOutput
(
Format
inputFormat
)
{
private
boolean
shouldUseFloatOutput
(
Format
inputFormat
)
{
Assertions
.
checkNotNull
(
inputFormat
.
sampleMimeType
);
Assertions
.
checkNotNull
(
inputFormat
.
sampleMimeType
);
if
(!
enableFloatOutput
||
!
supportsOutput
Encoding
(
C
.
ENCODING_PCM_FLOAT
))
{
if
(!
enableFloatOutput
||
!
supportsOutput
(
inputFormat
.
channelCount
,
C
.
ENCODING_PCM_FLOAT
))
{
return
false
;
return
false
;
}
}
switch
(
inputFormat
.
sampleMimeType
)
{
switch
(
inputFormat
.
sampleMimeType
)
{
...
...
extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/LibflacAudioRenderer.java
View file @
6b0e1758
...
@@ -53,7 +53,7 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
...
@@ -53,7 +53,7 @@ public class LibflacAudioRenderer extends SimpleDecoderAudioRenderer {
if
(!
FlacLibrary
.
isAvailable
()
if
(!
FlacLibrary
.
isAvailable
()
||
!
MimeTypes
.
AUDIO_FLAC
.
equalsIgnoreCase
(
format
.
sampleMimeType
))
{
||
!
MimeTypes
.
AUDIO_FLAC
.
equalsIgnoreCase
(
format
.
sampleMimeType
))
{
return
FORMAT_UNSUPPORTED_TYPE
;
return
FORMAT_UNSUPPORTED_TYPE
;
}
else
if
(!
supportsOutput
Encoding
(
C
.
ENCODING_PCM_16BIT
))
{
}
else
if
(!
supportsOutput
(
format
.
channelCount
,
C
.
ENCODING_PCM_16BIT
))
{
return
FORMAT_UNSUPPORTED_SUBTYPE
;
return
FORMAT_UNSUPPORTED_SUBTYPE
;
}
else
if
(!
supportsFormatDrm
(
drmSessionManager
,
format
.
drmInitData
))
{
}
else
if
(!
supportsFormatDrm
(
drmSessionManager
,
format
.
drmInitData
))
{
return
FORMAT_UNSUPPORTED_DRM
;
return
FORMAT_UNSUPPORTED_DRM
;
...
...
extensions/ima/build.gradle
View file @
6b0e1758
...
@@ -31,13 +31,13 @@ android {
...
@@ -31,13 +31,13 @@ android {
}
}
dependencies
{
dependencies
{
api
'com.google.ads.interactivemedia.v3:interactivemedia:3.
9.4
'
api
'com.google.ads.interactivemedia.v3:interactivemedia:3.
10.2
'
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
'com.google.android.gms:play-services-ads:1
5.0
.1'
implementation
'com.google.android.gms:play-services-ads:1
7.1
.1'
// These dependencies are necessary to force the supportLibraryVersion of
// These dependencies are necessary to force the supportLibraryVersion of
// com.android.support:support-v4 and com.android.support:customtabs to be
// com.android.support:support-v4 and com.android.support:customtabs to be
// used. Else older versions are used, for example via:
// used. Else older versions are used, for example via:
// com.google.android.gms:play-services-ads:1
5.0
.1
// com.google.android.gms:play-services-ads:1
7.1
.1
// |-- com.android.support:customtabs:26.1.0
// |-- com.android.support:customtabs:26.1.0
implementation
'com.android.support:support-v4:'
+
supportLibraryVersion
implementation
'com.android.support:support-v4:'
+
supportLibraryVersion
implementation
'com.android.support:customtabs:'
+
supportLibraryVersion
implementation
'com.android.support:customtabs:'
+
supportLibraryVersion
...
...
extensions/ima/src/main/AndroidManifest.xml
View file @
6b0e1758
...
@@ -15,6 +15,10 @@
...
@@ -15,6 +15,10 @@
-->
-->
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"com.google.android.exoplayer2.ext.ima"
>
package=
"com.google.android.exoplayer2.ext.ima"
>
<meta-data
android:name=
"com.google.android.gms.version"
<application>
android:value=
"@integer/google_play_services_version"
/>
<meta-data
android:name=
"com.google.android.gms.ads.AD_MANAGER_APP"
android:value=
"true"
/>
<meta-data
android:name=
"com.google.android.gms.version"
android:value=
"@integer/google_play_services_version"
/>
</application>
</manifest>
</manifest>
extensions/ima/src/main/proguard-rules.txt
deleted
100644 → 0
View file @
b5beb326
# Proguard rules specific to the IMA extension.
-keep class com.google.ads.interactivemedia.** { *; }
-keep interface com.google.ads.interactivemedia.** { *; }
-keep class com.google.obf.** { *; }
-keep interface com.google.obf.** { *; }
extensions/mediasession/build.gradle
View file @
6b0e1758
...
@@ -31,7 +31,7 @@ android {
...
@@ -31,7 +31,7 @@ android {
dependencies
{
dependencies
{
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
'com.android.support:support-media-compat:'
+
supportLibraryVersion
api
'com.android.support:support-media-compat:'
+
supportLibraryVersion
}
}
ext
{
ext
{
...
...
extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
View file @
6b0e1758
...
@@ -49,6 +49,11 @@ import java.util.Map;
...
@@ -49,6 +49,11 @@ import java.util.Map;
/**
/**
* Connects a {@link MediaSessionCompat} to a {@link Player}.
* Connects a {@link MediaSessionCompat} to a {@link Player}.
*
*
* <p>This connector does <em>not</em> call {@link MediaSessionCompat#setActive(boolean)}, and so
* application code is responsible for making the session active when desired. A session must be
* active for transport controls to be displayed (e.g. on the lock screen) and for it to receive
* media button events.
*
* <p>The connector listens for actions sent by the media session's controller and implements these
* <p>The connector listens for actions sent by the media session's controller and implements these
* actions by calling appropriate player methods. The playback state of the media session is
* actions by calling appropriate player methods. The playback state of the media session is
* automatically synced with the player. The connector can also be optionally extended by providing
* automatically synced with the player. The connector can also be optionally extended by providing
...
...
extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/LibopusAudioRenderer.java
View file @
6b0e1758
...
@@ -78,7 +78,7 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
...
@@ -78,7 +78,7 @@ public final class LibopusAudioRenderer extends SimpleDecoderAudioRenderer {
if
(!
OpusLibrary
.
isAvailable
()
if
(!
OpusLibrary
.
isAvailable
()
||
!
MimeTypes
.
AUDIO_OPUS
.
equalsIgnoreCase
(
format
.
sampleMimeType
))
{
||
!
MimeTypes
.
AUDIO_OPUS
.
equalsIgnoreCase
(
format
.
sampleMimeType
))
{
return
FORMAT_UNSUPPORTED_TYPE
;
return
FORMAT_UNSUPPORTED_TYPE
;
}
else
if
(!
supportsOutput
Encoding
(
C
.
ENCODING_PCM_16BIT
))
{
}
else
if
(!
supportsOutput
(
format
.
channelCount
,
C
.
ENCODING_PCM_16BIT
))
{
return
FORMAT_UNSUPPORTED_SUBTYPE
;
return
FORMAT_UNSUPPORTED_SUBTYPE
;
}
else
if
(!
supportsFormatDrm
(
drmSessionManager
,
format
.
drmInitData
))
{
}
else
if
(!
supportsFormatDrm
(
drmSessionManager
,
format
.
drmInitData
))
{
return
FORMAT_UNSUPPORTED_DRM
;
return
FORMAT_UNSUPPORTED_DRM
;
...
...
extensions/rtmp/build.gradle
View file @
6b0e1758
...
@@ -33,6 +33,8 @@ dependencies {
...
@@ -33,6 +33,8 @@ dependencies {
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
project
(
modulePrefix
+
'library-core'
)
implementation
'net.butterflytv.utils:rtmp-client:3.0.1'
implementation
'net.butterflytv.utils:rtmp-client:3.0.1'
implementation
'com.android.support:support-annotations:'
+
supportLibraryVersion
implementation
'com.android.support:support-annotations:'
+
supportLibraryVersion
testImplementation
'junit:junit:'
+
junitVersion
testImplementation
'org.robolectric:robolectric:'
+
robolectricVersion
}
}
ext
{
ext
{
...
...
extensions/rtmp/src/test/AndroidManifest.xml
0 → 100644
View file @
6b0e1758
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest
package=
"com.google.android.exoplayer2.ext.rtmp"
/>
extensions/rtmp/src/test/java/com/google/android/exoplayer2/ext/rtmp/DefaultDataSourceTest.java
0 → 100644
View file @
6b0e1758
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
ext
.
rtmp
;
import
android.net.Uri
;
import
com.google.android.exoplayer2.upstream.DataSpec
;
import
com.google.android.exoplayer2.upstream.DefaultDataSource
;
import
java.io.IOException
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.robolectric.RobolectricTestRunner
;
import
org.robolectric.RuntimeEnvironment
;
/** Unit test for {@link DefaultDataSource} with RTMP URIs. */
@RunWith
(
RobolectricTestRunner
.
class
)
public
final
class
DefaultDataSourceTest
{
@Test
public
void
openRtmpDataSpec_instantiatesRtmpDataSourceViaReflection
()
throws
IOException
{
DefaultDataSource
dataSource
=
new
DefaultDataSource
(
RuntimeEnvironment
.
application
,
"userAgent"
,
/* allowCrossProtocolRedirects= */
false
);
DataSpec
dataSpec
=
new
DataSpec
(
Uri
.
parse
(
"rtmp://test.com/stream"
));
try
{
dataSource
.
open
(
dataSpec
);
}
catch
(
UnsatisfiedLinkError
e
)
{
// RtmpDataSource was successfully instantiated (test run using Gradle).
}
catch
(
UnsupportedOperationException
e
)
{
// RtmpDataSource was successfully instantiated (test run using Blaze).
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/DefaultLoadControl.java
View file @
6b0e1758
...
@@ -79,6 +79,7 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -79,6 +79,7 @@ public class DefaultLoadControl implements LoadControl {
private
PriorityTaskManager
priorityTaskManager
;
private
PriorityTaskManager
priorityTaskManager
;
private
int
backBufferDurationMs
;
private
int
backBufferDurationMs
;
private
boolean
retainBackBufferFromKeyframe
;
private
boolean
retainBackBufferFromKeyframe
;
private
boolean
createDefaultLoadControlCalled
;
/** Constructs a new instance. */
/** Constructs a new instance. */
public
Builder
()
{
public
Builder
()
{
...
@@ -99,8 +100,10 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -99,8 +100,10 @@ public class DefaultLoadControl implements LoadControl {
*
*
* @param allocator The {@link DefaultAllocator}.
* @param allocator The {@link DefaultAllocator}.
* @return This builder, for convenience.
* @return This builder, for convenience.
* @throws IllegalStateException If {@link #createDefaultLoadControl()} has already been called.
*/
*/
public
Builder
setAllocator
(
DefaultAllocator
allocator
)
{
public
Builder
setAllocator
(
DefaultAllocator
allocator
)
{
Assertions
.
checkState
(!
createDefaultLoadControlCalled
);
this
.
allocator
=
allocator
;
this
.
allocator
=
allocator
;
return
this
;
return
this
;
}
}
...
@@ -118,12 +121,14 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -118,12 +121,14 @@ public class DefaultLoadControl implements LoadControl {
* for playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be
* for playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be
* caused by buffer depletion rather than a user action.
* caused by buffer depletion rather than a user action.
* @return This builder, for convenience.
* @return This builder, for convenience.
* @throws IllegalStateException If {@link #createDefaultLoadControl()} has already been called.
*/
*/
public
Builder
setBufferDurationsMs
(
public
Builder
setBufferDurationsMs
(
int
minBufferMs
,
int
minBufferMs
,
int
maxBufferMs
,
int
maxBufferMs
,
int
bufferForPlaybackMs
,
int
bufferForPlaybackMs
,
int
bufferForPlaybackAfterRebufferMs
)
{
int
bufferForPlaybackAfterRebufferMs
)
{
Assertions
.
checkState
(!
createDefaultLoadControlCalled
);
this
.
minBufferMs
=
minBufferMs
;
this
.
minBufferMs
=
minBufferMs
;
this
.
maxBufferMs
=
maxBufferMs
;
this
.
maxBufferMs
=
maxBufferMs
;
this
.
bufferForPlaybackMs
=
bufferForPlaybackMs
;
this
.
bufferForPlaybackMs
=
bufferForPlaybackMs
;
...
@@ -137,8 +142,10 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -137,8 +142,10 @@ public class DefaultLoadControl implements LoadControl {
*
*
* @param targetBufferBytes The target buffer size in bytes.
* @param targetBufferBytes The target buffer size in bytes.
* @return This builder, for convenience.
* @return This builder, for convenience.
* @throws IllegalStateException If {@link #createDefaultLoadControl()} has already been called.
*/
*/
public
Builder
setTargetBufferBytes
(
int
targetBufferBytes
)
{
public
Builder
setTargetBufferBytes
(
int
targetBufferBytes
)
{
Assertions
.
checkState
(!
createDefaultLoadControlCalled
);
this
.
targetBufferBytes
=
targetBufferBytes
;
this
.
targetBufferBytes
=
targetBufferBytes
;
return
this
;
return
this
;
}
}
...
@@ -150,8 +157,10 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -150,8 +157,10 @@ public class DefaultLoadControl implements LoadControl {
* @param prioritizeTimeOverSizeThresholds Whether the load control prioritizes buffer time
* @param prioritizeTimeOverSizeThresholds Whether the load control prioritizes buffer time
* constraints over buffer size constraints.
* constraints over buffer size constraints.
* @return This builder, for convenience.
* @return This builder, for convenience.
* @throws IllegalStateException If {@link #createDefaultLoadControl()} has already been called.
*/
*/
public
Builder
setPrioritizeTimeOverSizeThresholds
(
boolean
prioritizeTimeOverSizeThresholds
)
{
public
Builder
setPrioritizeTimeOverSizeThresholds
(
boolean
prioritizeTimeOverSizeThresholds
)
{
Assertions
.
checkState
(!
createDefaultLoadControlCalled
);
this
.
prioritizeTimeOverSizeThresholds
=
prioritizeTimeOverSizeThresholds
;
this
.
prioritizeTimeOverSizeThresholds
=
prioritizeTimeOverSizeThresholds
;
return
this
;
return
this
;
}
}
...
@@ -161,8 +170,10 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -161,8 +170,10 @@ public class DefaultLoadControl implements LoadControl {
*
*
* @param priorityTaskManager The {@link PriorityTaskManager} to use.
* @param priorityTaskManager The {@link PriorityTaskManager} to use.
* @return This builder, for convenience.
* @return This builder, for convenience.
* @throws IllegalStateException If {@link #createDefaultLoadControl()} has already been called.
*/
*/
public
Builder
setPriorityTaskManager
(
PriorityTaskManager
priorityTaskManager
)
{
public
Builder
setPriorityTaskManager
(
PriorityTaskManager
priorityTaskManager
)
{
Assertions
.
checkState
(!
createDefaultLoadControlCalled
);
this
.
priorityTaskManager
=
priorityTaskManager
;
this
.
priorityTaskManager
=
priorityTaskManager
;
return
this
;
return
this
;
}
}
...
@@ -175,8 +186,10 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -175,8 +186,10 @@ public class DefaultLoadControl implements LoadControl {
* @param retainBackBufferFromKeyframe Whether the back buffer is retained from the previous
* @param retainBackBufferFromKeyframe Whether the back buffer is retained from the previous
* keyframe.
* keyframe.
* @return This builder, for convenience.
* @return This builder, for convenience.
* @throws IllegalStateException If {@link #createDefaultLoadControl()} has already been called.
*/
*/
public
Builder
setBackBuffer
(
int
backBufferDurationMs
,
boolean
retainBackBufferFromKeyframe
)
{
public
Builder
setBackBuffer
(
int
backBufferDurationMs
,
boolean
retainBackBufferFromKeyframe
)
{
Assertions
.
checkState
(!
createDefaultLoadControlCalled
);
this
.
backBufferDurationMs
=
backBufferDurationMs
;
this
.
backBufferDurationMs
=
backBufferDurationMs
;
this
.
retainBackBufferFromKeyframe
=
retainBackBufferFromKeyframe
;
this
.
retainBackBufferFromKeyframe
=
retainBackBufferFromKeyframe
;
return
this
;
return
this
;
...
@@ -184,6 +197,7 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -184,6 +197,7 @@ public class DefaultLoadControl implements LoadControl {
/** Creates a {@link DefaultLoadControl}. */
/** Creates a {@link DefaultLoadControl}. */
public
DefaultLoadControl
createDefaultLoadControl
()
{
public
DefaultLoadControl
createDefaultLoadControl
()
{
createDefaultLoadControlCalled
=
true
;
if
(
allocator
==
null
)
{
if
(
allocator
==
null
)
{
allocator
=
new
DefaultAllocator
(
true
,
C
.
DEFAULT_BUFFER_SEGMENT_SIZE
);
allocator
=
new
DefaultAllocator
(
true
,
C
.
DEFAULT_BUFFER_SEGMENT_SIZE
);
}
}
...
@@ -371,7 +385,7 @@ public class DefaultLoadControl implements LoadControl {
...
@@ -371,7 +385,7 @@ public class DefaultLoadControl implements LoadControl {
}
}
if
(
bufferedDurationUs
<
minBufferUs
)
{
if
(
bufferedDurationUs
<
minBufferUs
)
{
isBuffering
=
prioritizeTimeOverSizeThresholds
||
!
targetBufferSizeReached
;
isBuffering
=
prioritizeTimeOverSizeThresholds
||
!
targetBufferSizeReached
;
}
else
if
(
bufferedDurationUs
>
maxBufferUs
||
targetBufferSizeReached
)
{
}
else
if
(
bufferedDurationUs
>
=
maxBufferUs
||
targetBufferSizeReached
)
{
isBuffering
=
false
;
isBuffering
=
false
;
}
// Else don't change the buffering state
}
// Else don't change the buffering state
if
(
priorityTaskManager
!=
null
&&
isBuffering
!=
wasBuffering
)
{
if
(
priorityTaskManager
!=
null
&&
isBuffering
!=
wasBuffering
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
View file @
6b0e1758
...
@@ -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.9.
1
"
;
public
static
final
String
VERSION
=
"2.9.
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.9.
1
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.9.
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.
...
@@ -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
=
200900
1
;
public
static
final
int
VERSION_INT
=
200900
2
;
/**
/**
* 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/Timeline.java
View file @
6b0e1758
...
@@ -139,9 +139,12 @@ public abstract class Timeline {
...
@@ -139,9 +139,12 @@ public abstract class Timeline {
*/
*/
public
boolean
isSeekable
;
public
boolean
isSeekable
;
/**
// TODO: Split this to better describe which parts of the window might change. For example it
* Whether this window may change when the timeline is updated.
// should be possible to individually determine whether the start and end positions of the
*/
// window may change relative to the underlying periods. For an example of where it's useful to
// know that the end position is fixed whilst the start position may still change, see:
// https://github.com/google/ExoPlayer/issues/4780.
/** Whether this window may change when the timeline is updated. */
public
boolean
isDynamic
;
public
boolean
isDynamic
;
/**
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioCapabilities.java
View file @
6b0e1758
...
@@ -29,11 +29,11 @@ import java.util.Arrays;
...
@@ -29,11 +29,11 @@ import java.util.Arrays;
@TargetApi
(
21
)
@TargetApi
(
21
)
public
final
class
AudioCapabilities
{
public
final
class
AudioCapabilities
{
/**
private
static
final
int
DEFAULT_MAX_CHANNEL_COUNT
=
8
;
* The minimum audio capabilities supported by all devices.
*/
/** The minimum audio capabilities supported by all devices.
*/
public
static
final
AudioCapabilities
DEFAULT_AUDIO_CAPABILITIES
=
public
static
final
AudioCapabilities
DEFAULT_AUDIO_CAPABILITIES
=
new
AudioCapabilities
(
new
int
[]
{
AudioFormat
.
ENCODING_PCM_16BIT
},
2
);
new
AudioCapabilities
(
new
int
[]
{
AudioFormat
.
ENCODING_PCM_16BIT
},
DEFAULT_MAX_CHANNEL_COUNT
);
/**
/**
* Returns the current audio capabilities for the device.
* Returns the current audio capabilities for the device.
...
@@ -52,8 +52,10 @@ public final class AudioCapabilities {
...
@@ -52,8 +52,10 @@ public final class AudioCapabilities {
if
(
intent
==
null
||
intent
.
getIntExtra
(
AudioManager
.
EXTRA_AUDIO_PLUG_STATE
,
0
)
==
0
)
{
if
(
intent
==
null
||
intent
.
getIntExtra
(
AudioManager
.
EXTRA_AUDIO_PLUG_STATE
,
0
)
==
0
)
{
return
DEFAULT_AUDIO_CAPABILITIES
;
return
DEFAULT_AUDIO_CAPABILITIES
;
}
}
return
new
AudioCapabilities
(
intent
.
getIntArrayExtra
(
AudioManager
.
EXTRA_ENCODINGS
),
return
new
AudioCapabilities
(
intent
.
getIntExtra
(
AudioManager
.
EXTRA_MAX_CHANNEL_COUNT
,
0
));
intent
.
getIntArrayExtra
(
AudioManager
.
EXTRA_ENCODINGS
),
intent
.
getIntExtra
(
AudioManager
.
EXTRA_MAX_CHANNEL_COUNT
,
/* defaultValue= */
DEFAULT_MAX_CHANNEL_COUNT
));
}
}
private
final
int
[]
supportedEncodings
;
private
final
int
[]
supportedEncodings
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
View file @
6b0e1758
...
@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio;
...
@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio;
import
android.media.AudioTrack
;
import
android.media.AudioTrack
;
import
android.support.annotation.Nullable
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
...
@@ -165,12 +166,13 @@ public interface AudioSink {
...
@@ -165,12 +166,13 @@ public interface AudioSink {
void
setListener
(
Listener
listener
);
void
setListener
(
Listener
listener
);
/**
/**
* Returns whether
it's possible to play audio in the specified encoding
.
* Returns whether
the sink supports the audio format
.
*
*
* @param encoding The audio encoding.
* @param channelCount The number of channels, or {@link Format#NO_VALUE} if not known.
* @return Whether it's possible to play audio in the specified encoding.
* @param encoding The audio encoding, or {@link Format#NO_VALUE} if not known.
* @return Whether the sink supports the audio format.
*/
*/
boolean
isEncodingSupported
(
@C
.
Encoding
int
encoding
);
boolean
supportsOutput
(
int
channelCount
,
@C
.
Encoding
int
encoding
);
/**
/**
* Returns the playback position in the stream starting at zero, in microseconds, or
* Returns the playback position in the stream starting at zero, in microseconds, or
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
View file @
6b0e1758
...
@@ -377,14 +377,18 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -377,14 +377,18 @@ public final class DefaultAudioSink implements AudioSink {
}
}
@Override
@Override
public
boolean
isEncodingSupported
(
@C
.
Encoding
int
encoding
)
{
public
boolean
supportsOutput
(
int
channelCount
,
@C
.
Encoding
int
encoding
)
{
if
(
Util
.
isEncodingLinearPcm
(
encoding
))
{
if
(
Util
.
isEncodingLinearPcm
(
encoding
))
{
// AudioTrack supports 16-bit integer PCM output in all platform API versions, and float
// AudioTrack supports 16-bit integer PCM output in all platform API versions, and float
// output from platform API version 21 only. Other integer PCM encodings are resampled by this
// output from platform API version 21 only. Other integer PCM encodings are resampled by this
// sink to 16-bit PCM.
// sink to 16-bit PCM. We assume that the audio framework will downsample any number of
// channels to the output device's required number of channels.
return
encoding
!=
C
.
ENCODING_PCM_FLOAT
||
Util
.
SDK_INT
>=
21
;
return
encoding
!=
C
.
ENCODING_PCM_FLOAT
||
Util
.
SDK_INT
>=
21
;
}
else
{
}
else
{
return
audioCapabilities
!=
null
&&
audioCapabilities
.
supportsEncoding
(
encoding
);
return
audioCapabilities
!=
null
&&
audioCapabilities
.
supportsEncoding
(
encoding
)
&&
(
channelCount
==
Format
.
NO_VALUE
||
channelCount
<=
audioCapabilities
.
getMaxChannelCount
());
}
}
}
}
...
@@ -415,7 +419,7 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -415,7 +419,7 @@ public final class DefaultAudioSink implements AudioSink {
isInputPcm
=
Util
.
isEncodingLinearPcm
(
inputEncoding
);
isInputPcm
=
Util
.
isEncodingLinearPcm
(
inputEncoding
);
shouldConvertHighResIntPcmToFloat
=
shouldConvertHighResIntPcmToFloat
=
enableConvertHighResIntPcmToFloat
enableConvertHighResIntPcmToFloat
&&
isEncodingSupported
(
C
.
ENCODING_PCM_32BIT
)
&&
supportsOutput
(
channelCount
,
C
.
ENCODING_PCM_32BIT
)
&&
Util
.
isEncodingHighResolutionIntegerPcm
(
inputEncoding
);
&&
Util
.
isEncodingHighResolutionIntegerPcm
(
inputEncoding
);
if
(
isInputPcm
)
{
if
(
isInputPcm
)
{
pcmFrameSize
=
Util
.
getPcmFrameSize
(
inputEncoding
,
channelCount
);
pcmFrameSize
=
Util
.
getPcmFrameSize
(
inputEncoding
,
channelCount
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
View file @
6b0e1758
...
@@ -272,12 +272,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -272,12 +272,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
}
int
tunnelingSupport
=
Util
.
SDK_INT
>=
21
?
TUNNELING_SUPPORTED
:
TUNNELING_NOT_SUPPORTED
;
int
tunnelingSupport
=
Util
.
SDK_INT
>=
21
?
TUNNELING_SUPPORTED
:
TUNNELING_NOT_SUPPORTED
;
boolean
supportsFormatDrm
=
supportsFormatDrm
(
drmSessionManager
,
format
.
drmInitData
);
boolean
supportsFormatDrm
=
supportsFormatDrm
(
drmSessionManager
,
format
.
drmInitData
);
if
(
supportsFormatDrm
&&
allowPassthrough
(
mimeType
)
if
(
supportsFormatDrm
&&
allowPassthrough
(
format
.
channelCount
,
mimeType
)
&&
mediaCodecSelector
.
getPassthroughDecoderInfo
()
!=
null
)
{
&&
mediaCodecSelector
.
getPassthroughDecoderInfo
()
!=
null
)
{
return
ADAPTIVE_NOT_SEAMLESS
|
tunnelingSupport
|
FORMAT_HANDLED
;
return
ADAPTIVE_NOT_SEAMLESS
|
tunnelingSupport
|
FORMAT_HANDLED
;
}
}
if
((
MimeTypes
.
AUDIO_RAW
.
equals
(
mimeType
)
&&
!
audioSink
.
isEncodingSupported
(
format
.
pcmEncoding
))
if
((
MimeTypes
.
AUDIO_RAW
.
equals
(
mimeType
)
||
!
audioSink
.
isEncodingSupported
(
C
.
ENCODING_PCM_16BIT
))
{
&&
!
audioSink
.
supportsOutput
(
format
.
channelCount
,
format
.
pcmEncoding
))
||
!
audioSink
.
supportsOutput
(
format
.
channelCount
,
C
.
ENCODING_PCM_16BIT
))
{
// Assume the decoder outputs 16-bit PCM, unless the input is raw.
// Assume the decoder outputs 16-bit PCM, unless the input is raw.
return
FORMAT_UNSUPPORTED_SUBTYPE
;
return
FORMAT_UNSUPPORTED_SUBTYPE
;
}
}
...
@@ -316,7 +318,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -316,7 +318,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
protected
List
<
MediaCodecInfo
>
getDecoderInfos
(
protected
List
<
MediaCodecInfo
>
getDecoderInfos
(
MediaCodecSelector
mediaCodecSelector
,
Format
format
,
boolean
requiresSecureDecoder
)
MediaCodecSelector
mediaCodecSelector
,
Format
format
,
boolean
requiresSecureDecoder
)
throws
DecoderQueryException
{
throws
DecoderQueryException
{
if
(
allowPassthrough
(
format
.
sampleMimeType
))
{
if
(
allowPassthrough
(
format
.
channelCount
,
format
.
sampleMimeType
))
{
MediaCodecInfo
passthroughDecoderInfo
=
mediaCodecSelector
.
getPassthroughDecoderInfo
();
MediaCodecInfo
passthroughDecoderInfo
=
mediaCodecSelector
.
getPassthroughDecoderInfo
();
if
(
passthroughDecoderInfo
!=
null
)
{
if
(
passthroughDecoderInfo
!=
null
)
{
return
Collections
.
singletonList
(
passthroughDecoderInfo
);
return
Collections
.
singletonList
(
passthroughDecoderInfo
);
...
@@ -330,12 +332,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -330,12 +332,13 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
* This implementation returns true if the {@link AudioSink} indicates that encoded audio output
* This implementation returns true if the {@link AudioSink} indicates that encoded audio output
* is supported.
* is supported.
*
*
* @param channelCount The number of channels in the input media, or {@link Format#NO_VALUE} if
* not known.
* @param mimeType The type of input media.
* @param mimeType The type of input media.
* @return Whether passthrough playback is supported.
* @return Whether passthrough playback is supported.
*/
*/
protected
boolean
allowPassthrough
(
String
mimeType
)
{
protected
boolean
allowPassthrough
(
int
channelCount
,
String
mimeType
)
{
@C
.
Encoding
int
encoding
=
MimeTypes
.
getEncoding
(
mimeType
);
return
audioSink
.
supportsOutput
(
channelCount
,
MimeTypes
.
getEncoding
(
mimeType
));
return
encoding
!=
C
.
ENCODING_INVALID
&&
audioSink
.
isEncodingSupported
(
encoding
);
}
}
@Override
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java
View file @
6b0e1758
...
@@ -249,13 +249,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
...
@@ -249,13 +249,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
DrmSessionManager
<
ExoMediaCrypto
>
drmSessionManager
,
Format
format
);
DrmSessionManager
<
ExoMediaCrypto
>
drmSessionManager
,
Format
format
);
/**
/**
* Returns whether the
audio sink can accept audio in the specified encoding
.
* Returns whether the
sink supports the audio format
.
*
*
* @param encoding The audio encoding.
* @see AudioSink#supportsOutput(int, int)
* @return Whether the audio sink can accept audio in the specified encoding.
*/
*/
protected
final
boolean
supportsOutput
Encoding
(
@C
.
Encoding
int
encoding
)
{
protected
final
boolean
supportsOutput
(
int
channelCount
,
@C
.
Encoding
int
encoding
)
{
return
audioSink
.
isEncodingSupported
(
encoding
);
return
audioSink
.
supportsOutput
(
channelCount
,
encoding
);
}
}
@Override
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/drm/FrameworkMediaDrm.java
View file @
6b0e1758
...
@@ -70,9 +70,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
...
@@ -70,9 +70,7 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
Assertions
.
checkNotNull
(
uuid
);
Assertions
.
checkNotNull
(
uuid
);
Assertions
.
checkArgument
(!
C
.
COMMON_PSSH_UUID
.
equals
(
uuid
),
"Use C.CLEARKEY_UUID instead"
);
Assertions
.
checkArgument
(!
C
.
COMMON_PSSH_UUID
.
equals
(
uuid
),
"Use C.CLEARKEY_UUID instead"
);
this
.
uuid
=
uuid
;
this
.
uuid
=
uuid
;
// ClearKey had to be accessed using the Common PSSH UUID prior to API level 27.
this
.
mediaDrm
=
new
MediaDrm
(
adjustUuid
(
uuid
));
this
.
mediaDrm
=
new
MediaDrm
(
Util
.
SDK_INT
<
27
&&
C
.
CLEARKEY_UUID
.
equals
(
uuid
)
?
C
.
COMMON_PSSH_UUID
:
uuid
);
if
(
C
.
WIDEVINE_UUID
.
equals
(
uuid
)
&&
needsForceWidevineL3Workaround
())
{
if
(
C
.
WIDEVINE_UUID
.
equals
(
uuid
)
&&
needsForceWidevineL3Workaround
())
{
forceWidevineL3
(
mediaDrm
);
forceWidevineL3
(
mediaDrm
);
}
}
...
@@ -152,7 +150,6 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
...
@@ -152,7 +150,6 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
@Override
@Override
public
byte
[]
provideKeyResponse
(
byte
[]
scope
,
byte
[]
response
)
public
byte
[]
provideKeyResponse
(
byte
[]
scope
,
byte
[]
response
)
throws
NotProvisionedException
,
DeniedByServerException
{
throws
NotProvisionedException
,
DeniedByServerException
{
if
(
C
.
CLEARKEY_UUID
.
equals
(
uuid
))
{
if
(
C
.
CLEARKEY_UUID
.
equals
(
uuid
))
{
response
=
ClearKeyUtil
.
adjustResponseData
(
response
);
response
=
ClearKeyUtil
.
adjustResponseData
(
response
);
}
}
...
@@ -212,8 +209,8 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
...
@@ -212,8 +209,8 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
// indicate that it required secure video decoders [Internal ref: b/11428937].
// indicate that it required secure video decoders [Internal ref: b/11428937].
boolean
forceAllowInsecureDecoderComponents
=
Util
.
SDK_INT
<
21
boolean
forceAllowInsecureDecoderComponents
=
Util
.
SDK_INT
<
21
&&
C
.
WIDEVINE_UUID
.
equals
(
uuid
)
&&
"L3"
.
equals
(
getPropertyString
(
"securityLevel"
));
&&
C
.
WIDEVINE_UUID
.
equals
(
uuid
)
&&
"L3"
.
equals
(
getPropertyString
(
"securityLevel"
));
return
new
FrameworkMediaCrypto
(
new
MediaCrypto
(
uuid
,
initData
),
return
new
FrameworkMediaCrypto
(
forceAllowInsecureDecoderComponents
);
new
MediaCrypto
(
adjustUuid
(
uuid
),
initData
),
forceAllowInsecureDecoderComponents
);
}
}
private
static
SchemeData
getSchemeData
(
UUID
uuid
,
List
<
SchemeData
>
schemeDatas
)
{
private
static
SchemeData
getSchemeData
(
UUID
uuid
,
List
<
SchemeData
>
schemeDatas
)
{
...
@@ -269,6 +266,11 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
...
@@ -269,6 +266,11 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
return
schemeDatas
.
get
(
0
);
return
schemeDatas
.
get
(
0
);
}
}
private
static
UUID
adjustUuid
(
UUID
uuid
)
{
// ClearKey had to be accessed using the Common PSSH UUID prior to API level 27.
return
Util
.
SDK_INT
<
27
&&
C
.
CLEARKEY_UUID
.
equals
(
uuid
)
?
C
.
COMMON_PSSH_UUID
:
uuid
;
}
private
static
byte
[]
adjustRequestInitData
(
UUID
uuid
,
byte
[]
initData
)
{
private
static
byte
[]
adjustRequestInitData
(
UUID
uuid
,
byte
[]
initData
)
{
// Prior to L the Widevine CDM required data to be extracted from the PSSH atom. Some Amazon
// Prior to L the Widevine CDM required data to be extracted from the PSSH atom. Some Amazon
// devices also required data to be extracted from the PSSH atom for PlayReady.
// devices also required data to be extracted from the PSSH atom for PlayReady.
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java
View file @
6b0e1758
...
@@ -42,37 +42,25 @@ public abstract class BinarySearchSeeker {
...
@@ -42,37 +42,25 @@ public abstract class BinarySearchSeeker {
protected
interface
TimestampSeeker
{
protected
interface
TimestampSeeker
{
/**
/**
* Searches for a given timestamp from the input.
* Searches a limited window of the provided input for a target timestamp. The size of the
* window is implementation specific, but should be small enough such that it's reasonable for
* multiple such reads to occur during a seek operation.
*
*
* <p>Given a target timestamp and an input stream, this seeker will try to read up to a range
* @param input The {@link ExtractorInput} from which data should be peeked.
* of {@code searchRangeBytes} bytes from that input, look for all available timestamps from all
* @param targetTimestamp The target timestamp.
* frames in that range, compare those with the target timestamp, and return one of the {@link
* @param outputFrameHolder If {@link TimestampSearchResult#TYPE_TARGET_TIMESTAMP_FOUND} is
* TimestampSearchResult}.
*
* @param input The {@link ExtractorInput} from which data should be read.
* @param targetTimestamp The target timestamp that we are looking for.
* @param outputFrameHolder If {@link TimestampSearchResult#RESULT_TARGET_TIMESTAMP_FOUND} is
* returned, this holder may be updated to hold the extracted frame that contains the target
* returned, this holder may be updated to hold the extracted frame that contains the target
* frame/sample associated with the target timestamp.
* frame/sample associated with the target timestamp.
* @return A {@link TimestampSearchResult}, that includes a {@link TimestampSearchResult#result}
* @return A {@link TimestampSearchResult} that describes the result of the search.
* value, and other necessary info:
* <ul>
* <li>{@link TimestampSearchResult#RESULT_NO_TIMESTAMP} is returned if there is no
* timestamp in the reading range.
* <li>{@link TimestampSearchResult#RESULT_POSITION_UNDERESTIMATED} is returned if all
* timestamps in the range are smaller than the target timestamp.
* <li>{@link TimestampSearchResult#RESULT_POSITION_OVERESTIMATED} is returned if all
* timestamps in the range are larger than the target timestamp.
* <li>{@link TimestampSearchResult#RESULT_TARGET_TIMESTAMP_FOUND} is returned if this
* seeker can find a timestamp that it deems close enough to the given target.
* </ul>
*
* @throws IOException If an error occurred reading from the input.
* @throws IOException If an error occurred reading from the input.
* @throws InterruptedException If the thread was interrupted.
* @throws InterruptedException If the thread was interrupted.
*/
*/
TimestampSearchResult
searchForTimestamp
(
TimestampSearchResult
searchForTimestamp
(
ExtractorInput
input
,
long
targetTimestamp
,
OutputFrameHolder
outputFrameHolder
)
ExtractorInput
input
,
long
targetTimestamp
,
OutputFrameHolder
outputFrameHolder
)
throws
IOException
,
InterruptedException
;
throws
IOException
,
InterruptedException
;
/** Called when a seek operation finishes. */
default
void
onSeekFinished
()
{}
}
}
/**
/**
...
@@ -231,22 +219,22 @@ public abstract class BinarySearchSeeker {
...
@@ -231,22 +219,22 @@ public abstract class BinarySearchSeeker {
timestampSeeker
.
searchForTimestamp
(
timestampSeeker
.
searchForTimestamp
(
input
,
seekOperationParams
.
getTargetTimePosition
(),
outputFrameHolder
);
input
,
seekOperationParams
.
getTargetTimePosition
(),
outputFrameHolder
);
switch
(
timestampSearchResult
.
result
)
{
switch
(
timestampSearchResult
.
type
)
{
case
TimestampSearchResult
.
RESULT
_POSITION_OVERESTIMATED
:
case
TimestampSearchResult
.
TYPE
_POSITION_OVERESTIMATED
:
seekOperationParams
.
updateSeekCeiling
(
seekOperationParams
.
updateSeekCeiling
(
timestampSearchResult
.
timestampToUpdate
,
timestampSearchResult
.
bytePositionToUpdate
);
timestampSearchResult
.
timestampToUpdate
,
timestampSearchResult
.
bytePositionToUpdate
);
break
;
break
;
case
TimestampSearchResult
.
RESULT
_POSITION_UNDERESTIMATED
:
case
TimestampSearchResult
.
TYPE
_POSITION_UNDERESTIMATED
:
seekOperationParams
.
updateSeekFloor
(
seekOperationParams
.
updateSeekFloor
(
timestampSearchResult
.
timestampToUpdate
,
timestampSearchResult
.
bytePositionToUpdate
);
timestampSearchResult
.
timestampToUpdate
,
timestampSearchResult
.
bytePositionToUpdate
);
break
;
break
;
case
TimestampSearchResult
.
RESULT
_TARGET_TIMESTAMP_FOUND
:
case
TimestampSearchResult
.
TYPE
_TARGET_TIMESTAMP_FOUND
:
markSeekOperationFinished
(
markSeekOperationFinished
(
/* foundTargetFrame= */
true
,
timestampSearchResult
.
bytePositionToUpdate
);
/* foundTargetFrame= */
true
,
timestampSearchResult
.
bytePositionToUpdate
);
skipInputUntilPosition
(
input
,
timestampSearchResult
.
bytePositionToUpdate
);
skipInputUntilPosition
(
input
,
timestampSearchResult
.
bytePositionToUpdate
);
return
seekToPosition
(
return
seekToPosition
(
input
,
timestampSearchResult
.
bytePositionToUpdate
,
seekPositionHolder
);
input
,
timestampSearchResult
.
bytePositionToUpdate
,
seekPositionHolder
);
case
TimestampSearchResult
.
RESULT
_NO_TIMESTAMP
:
case
TimestampSearchResult
.
TYPE
_NO_TIMESTAMP
:
// We can't find any timestamp in the search range from the search position.
// We can't find any timestamp in the search range from the search position.
// Give up, and just continue reading from the last search position in this case.
// Give up, and just continue reading from the last search position in this case.
markSeekOperationFinished
(
/* foundTargetFrame= */
false
,
searchPosition
);
markSeekOperationFinished
(
/* foundTargetFrame= */
false
,
searchPosition
);
...
@@ -270,6 +258,7 @@ public abstract class BinarySearchSeeker {
...
@@ -270,6 +258,7 @@ public abstract class BinarySearchSeeker {
protected
final
void
markSeekOperationFinished
(
boolean
foundTargetFrame
,
long
resultPosition
)
{
protected
final
void
markSeekOperationFinished
(
boolean
foundTargetFrame
,
long
resultPosition
)
{
seekOperationParams
=
null
;
seekOperationParams
=
null
;
timestampSeeker
.
onSeekFinished
();
onSeekOperationFinished
(
foundTargetFrame
,
resultPosition
);
onSeekOperationFinished
(
foundTargetFrame
,
resultPosition
);
}
}
...
@@ -433,45 +422,49 @@ public abstract class BinarySearchSeeker {
...
@@ -433,45 +422,49 @@ public abstract class BinarySearchSeeker {
*/
*/
public
static
final
class
TimestampSearchResult
{
public
static
final
class
TimestampSearchResult
{
public
static
final
int
RESULT_TARGET_TIMESTAMP_FOUND
=
0
;
/** The search found a timestamp that it deems close enough to the given target. */
public
static
final
int
RESULT_POSITION_OVERESTIMATED
=
-
1
;
public
static
final
int
TYPE_TARGET_TIMESTAMP_FOUND
=
0
;
public
static
final
int
RESULT_POSITION_UNDERESTIMATED
=
-
2
;
/** The search found only timestamps larger than the target timestamp. */
public
static
final
int
RESULT_NO_TIMESTAMP
=
-
3
;
public
static
final
int
TYPE_POSITION_OVERESTIMATED
=
-
1
;
/** The search found only timestamps smaller than the target timestamp. */
public
static
final
int
TYPE_POSITION_UNDERESTIMATED
=
-
2
;
/** The search didn't find any timestamps. */
public
static
final
int
TYPE_NO_TIMESTAMP
=
-
3
;
@Documented
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
@IntDef
({
RESULT
_TARGET_TIMESTAMP_FOUND
,
TYPE
_TARGET_TIMESTAMP_FOUND
,
RESULT
_POSITION_OVERESTIMATED
,
TYPE
_POSITION_OVERESTIMATED
,
RESULT
_POSITION_UNDERESTIMATED
,
TYPE
_POSITION_UNDERESTIMATED
,
RESULT
_NO_TIMESTAMP
TYPE
_NO_TIMESTAMP
})
})
@interface
SearchResult
{}
@interface
Type
{}
public
static
final
TimestampSearchResult
NO_TIMESTAMP_IN_RANGE_RESULT
=
public
static
final
TimestampSearchResult
NO_TIMESTAMP_IN_RANGE_RESULT
=
new
TimestampSearchResult
(
RESULT
_NO_TIMESTAMP
,
C
.
TIME_UNSET
,
C
.
POSITION_UNSET
);
new
TimestampSearchResult
(
TYPE
_NO_TIMESTAMP
,
C
.
TIME_UNSET
,
C
.
POSITION_UNSET
);
/**
@see TimestampSeeker
*/
/**
The type of the result.
*/
private
final
@SearchResult
int
result
;
@Type
private
final
int
type
;
/**
/**
* When {@
code result} is {@link #RESULT
_POSITION_OVERESTIMATED}, the {@link
* When {@
link #type} is {@link #TYPE
_POSITION_OVERESTIMATED}, the {@link
* SeekOperationParams#ceilingTimePosition} should be updated with this value. When {@
code
* SeekOperationParams#ceilingTimePosition} should be updated with this value. When {@
link
*
result} is {@link #RESULT
_POSITION_UNDERESTIMATED}, the {@link
*
#type} is {@link #TYPE
_POSITION_UNDERESTIMATED}, the {@link
* SeekOperationParams#floorTimePosition} should be updated with this value.
* SeekOperationParams#floorTimePosition} should be updated with this value.
*/
*/
private
final
long
timestampToUpdate
;
private
final
long
timestampToUpdate
;
/**
/**
* When {@
code result} is {@link #RESULT
_POSITION_OVERESTIMATED}, the {@link
* When {@
link #type} is {@link #TYPE
_POSITION_OVERESTIMATED}, the {@link
* SeekOperationParams#ceilingBytePosition} should be updated with this value. When {@
code
* SeekOperationParams#ceilingBytePosition} should be updated with this value. When {@
link
*
result} is {@link #RESULT
_POSITION_UNDERESTIMATED}, the {@link
*
#type} is {@link #TYPE
_POSITION_UNDERESTIMATED}, the {@link
* SeekOperationParams#floorBytePosition} should be updated with this value.
* SeekOperationParams#floorBytePosition} should be updated with this value.
*/
*/
private
final
long
bytePositionToUpdate
;
private
final
long
bytePositionToUpdate
;
private
TimestampSearchResult
(
private
TimestampSearchResult
(
@
SearchResult
int
result
,
long
timestampToUpdate
,
long
bytePositionToUpdate
)
{
@
Type
int
type
,
long
timestampToUpdate
,
long
bytePositionToUpdate
)
{
this
.
result
=
result
;
this
.
type
=
type
;
this
.
timestampToUpdate
=
timestampToUpdate
;
this
.
timestampToUpdate
=
timestampToUpdate
;
this
.
bytePositionToUpdate
=
bytePositionToUpdate
;
this
.
bytePositionToUpdate
=
bytePositionToUpdate
;
}
}
...
@@ -484,7 +477,7 @@ public abstract class BinarySearchSeeker {
...
@@ -484,7 +477,7 @@ public abstract class BinarySearchSeeker {
public
static
TimestampSearchResult
overestimatedResult
(
public
static
TimestampSearchResult
overestimatedResult
(
long
newCeilingTimestamp
,
long
newCeilingBytePosition
)
{
long
newCeilingTimestamp
,
long
newCeilingBytePosition
)
{
return
new
TimestampSearchResult
(
return
new
TimestampSearchResult
(
RESULT
_POSITION_OVERESTIMATED
,
newCeilingTimestamp
,
newCeilingBytePosition
);
TYPE
_POSITION_OVERESTIMATED
,
newCeilingTimestamp
,
newCeilingBytePosition
);
}
}
/**
/**
...
@@ -495,11 +488,11 @@ public abstract class BinarySearchSeeker {
...
@@ -495,11 +488,11 @@ public abstract class BinarySearchSeeker {
public
static
TimestampSearchResult
underestimatedResult
(
public
static
TimestampSearchResult
underestimatedResult
(
long
newFloorTimestamp
,
long
newCeilingBytePosition
)
{
long
newFloorTimestamp
,
long
newCeilingBytePosition
)
{
return
new
TimestampSearchResult
(
return
new
TimestampSearchResult
(
RESULT
_POSITION_UNDERESTIMATED
,
newFloorTimestamp
,
newCeilingBytePosition
);
TYPE
_POSITION_UNDERESTIMATED
,
newFloorTimestamp
,
newCeilingBytePosition
);
}
}
/**
/**
* Returns a result to signal that the target timestamp has been found at
the
{@code
* Returns a result to signal that the target timestamp has been found at {@code
* resultBytePosition}, and the seek operation can stop.
* resultBytePosition}, and the seek operation can stop.
*
*
* <p>Note that when this value is returned from {@link
* <p>Note that when this value is returned from {@link
...
@@ -508,7 +501,7 @@ public abstract class BinarySearchSeeker {
...
@@ -508,7 +501,7 @@ public abstract class BinarySearchSeeker {
*/
*/
public
static
TimestampSearchResult
targetFoundResult
(
long
resultBytePosition
)
{
public
static
TimestampSearchResult
targetFoundResult
(
long
resultBytePosition
)
{
return
new
TimestampSearchResult
(
return
new
TimestampSearchResult
(
RESULT
_TARGET_TIMESTAMP_FOUND
,
C
.
TIME_UNSET
,
resultBytePosition
);
TYPE
_TARGET_TIMESTAMP_FOUND
,
C
.
TIME_UNSET
,
resultBytePosition
);
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java
View file @
6b0e1758
...
@@ -145,6 +145,10 @@ import java.util.List;
...
@@ -145,6 +145,10 @@ import java.util.List;
public
static
final
int
TYPE_alac
=
Util
.
getIntegerCodeForString
(
"alac"
);
public
static
final
int
TYPE_alac
=
Util
.
getIntegerCodeForString
(
"alac"
);
public
static
final
int
TYPE_alaw
=
Util
.
getIntegerCodeForString
(
"alaw"
);
public
static
final
int
TYPE_alaw
=
Util
.
getIntegerCodeForString
(
"alaw"
);
public
static
final
int
TYPE_ulaw
=
Util
.
getIntegerCodeForString
(
"ulaw"
);
public
static
final
int
TYPE_ulaw
=
Util
.
getIntegerCodeForString
(
"ulaw"
);
public
static
final
int
TYPE_Opus
=
Util
.
getIntegerCodeForString
(
"Opus"
);
public
static
final
int
TYPE_dOps
=
Util
.
getIntegerCodeForString
(
"dOps"
);
public
static
final
int
TYPE_fLaC
=
Util
.
getIntegerCodeForString
(
"fLaC"
);
public
static
final
int
TYPE_dfLa
=
Util
.
getIntegerCodeForString
(
"dfLa"
);
public
final
int
type
;
public
final
int
type
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
View file @
6b0e1758
...
@@ -58,6 +58,9 @@ import java.util.List;
...
@@ -58,6 +58,9 @@ import java.util.List;
*/
*/
private
static
final
int
MAX_GAPLESS_TRIM_SIZE_SAMPLES
=
3
;
private
static
final
int
MAX_GAPLESS_TRIM_SIZE_SAMPLES
=
3
;
/** The magic signature for an Opus Identification header, as defined in RFC-7845. */
private
static
final
byte
[]
opusMagic
=
Util
.
getUtf8Bytes
(
"OpusHead"
);
/**
/**
* Parses a trak atom (defined in 14496-12).
* Parses a trak atom (defined in 14496-12).
*
*
...
@@ -233,8 +236,6 @@ import java.util.List;
...
@@ -233,8 +236,6 @@ import java.util.List;
sizes
=
Arrays
.
copyOf
(
sizes
,
sampleCount
);
sizes
=
Arrays
.
copyOf
(
sizes
,
sampleCount
);
timestamps
=
Arrays
.
copyOf
(
timestamps
,
sampleCount
);
timestamps
=
Arrays
.
copyOf
(
timestamps
,
sampleCount
);
flags
=
Arrays
.
copyOf
(
flags
,
sampleCount
);
flags
=
Arrays
.
copyOf
(
flags
,
sampleCount
);
remainingSamplesAtTimestampOffset
=
0
;
remainingTimestampOffsetChanges
=
0
;
break
;
break
;
}
}
...
@@ -290,23 +291,38 @@ import java.util.List;
...
@@ -290,23 +291,38 @@ import java.util.List;
}
}
duration
=
timestampTimeUnits
+
timestampOffset
;
duration
=
timestampTimeUnits
+
timestampOffset
;
Assertions
.
checkArgument
(
remainingSamplesAtTimestampOffset
==
0
);
// If the stbl's child boxes are not consistent the container is malformed, but the stream may
// Remove trailing ctts entries with 0-valued sample counts.
// still be playable.
boolean
isCttsValid
=
true
;
while
(
remainingTimestampOffsetChanges
>
0
)
{
while
(
remainingTimestampOffsetChanges
>
0
)
{
Assertions
.
checkArgument
(
ctts
.
readUnsignedIntToInt
()
==
0
);
if
(
ctts
.
readUnsignedIntToInt
()
!=
0
)
{
isCttsValid
=
false
;
break
;
}
ctts
.
readInt
();
// Ignore offset.
ctts
.
readInt
();
// Ignore offset.
remainingTimestampOffsetChanges
--;
remainingTimestampOffsetChanges
--;
}
}
if
(
remainingSynchronizationSamples
!=
0
// If the stbl's child boxes are not consistent the container is malformed, but the stream may
||
remainingSamplesAtTimestampDelta
!=
0
// still be playable.
||
remainingSamplesInChunk
!=
0
if
(
remainingSynchronizationSamples
!=
0
||
remainingSamplesAtTimestampDelta
!=
0
||
remainingTimestampDeltaChanges
!=
0
||
remainingSamplesInChunk
!=
0
||
remainingTimestampDeltaChanges
!=
0
)
{
||
remainingSamplesAtTimestampOffset
!=
0
Log
.
w
(
TAG
,
"Inconsistent stbl box for track "
+
track
.
id
||
!
isCttsValid
)
{
+
": remainingSynchronizationSamples "
+
remainingSynchronizationSamples
Log
.
w
(
+
", remainingSamplesAtTimestampDelta "
+
remainingSamplesAtTimestampDelta
TAG
,
+
", remainingSamplesInChunk "
+
remainingSamplesInChunk
"Inconsistent stbl box for track "
+
", remainingTimestampDeltaChanges "
+
remainingTimestampDeltaChanges
);
+
track
.
id
+
": remainingSynchronizationSamples "
+
remainingSynchronizationSamples
+
", remainingSamplesAtTimestampDelta "
+
remainingSamplesAtTimestampDelta
+
", remainingSamplesInChunk "
+
remainingSamplesInChunk
+
", remainingTimestampDeltaChanges "
+
remainingTimestampDeltaChanges
+
", remainingSamplesAtTimestampOffset "
+
remainingSamplesAtTimestampOffset
+
(!
isCttsValid
?
", ctts invalid"
:
""
));
}
}
}
else
{
}
else
{
long
[]
chunkOffsetsBytes
=
new
long
[
chunkIterator
.
length
];
long
[]
chunkOffsetsBytes
=
new
long
[
chunkIterator
.
length
];
...
@@ -679,7 +695,9 @@ import java.util.List;
...
@@ -679,7 +695,9 @@ import java.util.List;
||
childAtomType
==
Atom
.
TYPE__mp3
||
childAtomType
==
Atom
.
TYPE__mp3
||
childAtomType
==
Atom
.
TYPE_alac
||
childAtomType
==
Atom
.
TYPE_alac
||
childAtomType
==
Atom
.
TYPE_alaw
||
childAtomType
==
Atom
.
TYPE_alaw
||
childAtomType
==
Atom
.
TYPE_ulaw
)
{
||
childAtomType
==
Atom
.
TYPE_ulaw
||
childAtomType
==
Atom
.
TYPE_Opus
||
childAtomType
==
Atom
.
TYPE_fLaC
)
{
parseAudioSampleEntry
(
stsd
,
childAtomType
,
childStartPosition
,
childAtomSize
,
trackId
,
parseAudioSampleEntry
(
stsd
,
childAtomType
,
childStartPosition
,
childAtomSize
,
trackId
,
language
,
isQuickTime
,
drmInitData
,
out
,
i
);
language
,
isQuickTime
,
drmInitData
,
out
,
i
);
}
else
if
(
childAtomType
==
Atom
.
TYPE_TTML
||
childAtomType
==
Atom
.
TYPE_tx3g
}
else
if
(
childAtomType
==
Atom
.
TYPE_TTML
||
childAtomType
==
Atom
.
TYPE_tx3g
...
@@ -976,6 +994,10 @@ import java.util.List;
...
@@ -976,6 +994,10 @@ import java.util.List;
mimeType
=
MimeTypes
.
AUDIO_ALAW
;
mimeType
=
MimeTypes
.
AUDIO_ALAW
;
}
else
if
(
atomType
==
Atom
.
TYPE_ulaw
)
{
}
else
if
(
atomType
==
Atom
.
TYPE_ulaw
)
{
mimeType
=
MimeTypes
.
AUDIO_MLAW
;
mimeType
=
MimeTypes
.
AUDIO_MLAW
;
}
else
if
(
atomType
==
Atom
.
TYPE_Opus
)
{
mimeType
=
MimeTypes
.
AUDIO_OPUS
;
}
else
if
(
atomType
==
Atom
.
TYPE_fLaC
)
{
mimeType
=
MimeTypes
.
AUDIO_FLAC
;
}
}
byte
[]
initializationData
=
null
;
byte
[]
initializationData
=
null
;
...
@@ -1016,7 +1038,20 @@ import java.util.List;
...
@@ -1016,7 +1038,20 @@ import java.util.List;
}
else
if
(
childAtomType
==
Atom
.
TYPE_alac
)
{
}
else
if
(
childAtomType
==
Atom
.
TYPE_alac
)
{
initializationData
=
new
byte
[
childAtomSize
];
initializationData
=
new
byte
[
childAtomSize
];
parent
.
setPosition
(
childPosition
);
parent
.
setPosition
(
childPosition
);
parent
.
readBytes
(
initializationData
,
0
,
childAtomSize
);
parent
.
readBytes
(
initializationData
,
/* offset= */
0
,
childAtomSize
);
}
else
if
(
childAtomType
==
Atom
.
TYPE_dOps
)
{
// Build an Opus Identification Header (defined in RFC-7845) by concatenating the Opus Magic
// Signature and the body of the dOps atom.
int
childAtomBodySize
=
childAtomSize
-
Atom
.
HEADER_SIZE
;
initializationData
=
new
byte
[
opusMagic
.
length
+
childAtomBodySize
];
System
.
arraycopy
(
opusMagic
,
0
,
initializationData
,
0
,
opusMagic
.
length
);
parent
.
setPosition
(
childPosition
+
Atom
.
HEADER_SIZE
);
parent
.
readBytes
(
initializationData
,
opusMagic
.
length
,
childAtomBodySize
);
}
else
if
(
childAtomSize
==
Atom
.
TYPE_dfLa
)
{
int
childAtomBodySize
=
childAtomSize
-
Atom
.
FULL_HEADER_SIZE
;
initializationData
=
new
byte
[
childAtomBodySize
];
parent
.
setPosition
(
childPosition
+
Atom
.
FULL_HEADER_SIZE
);
parent
.
readBytes
(
initializationData
,
/* offset= */
0
,
childAtomBodySize
);
}
}
childPosition
+=
childAtomSize
;
childPosition
+=
childAtomSize
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java
View file @
6b0e1758
...
@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
...
@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
/**
/**
...
@@ -53,10 +54,9 @@ import java.io.IOException;
...
@@ -53,10 +54,9 @@ import java.io.IOException;
/**
/**
* A seeker that looks for a given SCR timestamp at a given position in a PS stream.
* A seeker that looks for a given SCR timestamp at a given position in a PS stream.
*
*
* <p>Given a SCR timestamp, and a position within a PS stream, this seeker will try to read a
* <p>Given a SCR timestamp, and a position within a PS stream, this seeker will peek up to {@link
* range of up to {@link #TIMESTAMP_SEARCH_BYTES} bytes from that stream position, look for all
* #TIMESTAMP_SEARCH_BYTES} bytes from that stream position, look for all packs in that range, and
* packs in that range, and then compare the SCR timestamps (if available) of these packets vs the
* then compare the SCR timestamps (if available) of these packets to the target timestamp.
* target timestamp.
*/
*/
private
static
final
class
PsScrSeeker
implements
TimestampSeeker
{
private
static
final
class
PsScrSeeker
implements
TimestampSeeker
{
...
@@ -65,7 +65,7 @@ import java.io.IOException;
...
@@ -65,7 +65,7 @@ import java.io.IOException;
private
PsScrSeeker
(
TimestampAdjuster
scrTimestampAdjuster
)
{
private
PsScrSeeker
(
TimestampAdjuster
scrTimestampAdjuster
)
{
this
.
scrTimestampAdjuster
=
scrTimestampAdjuster
;
this
.
scrTimestampAdjuster
=
scrTimestampAdjuster
;
packetBuffer
=
new
ParsableByteArray
(
TIMESTAMP_SEARCH_BYTES
);
packetBuffer
=
new
ParsableByteArray
();
}
}
@Override
@Override
...
@@ -73,14 +73,19 @@ import java.io.IOException;
...
@@ -73,14 +73,19 @@ import java.io.IOException;
ExtractorInput
input
,
long
targetTimestamp
,
OutputFrameHolder
outputFrameHolder
)
ExtractorInput
input
,
long
targetTimestamp
,
OutputFrameHolder
outputFrameHolder
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
long
inputPosition
=
input
.
getPosition
();
long
inputPosition
=
input
.
getPosition
();
int
bytesTo
Read
=
int
bytesTo
Search
=
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
input
.
getLength
()
-
inputPosition
);
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
input
.
getLength
()
-
input
.
getPosition
());
packetBuffer
.
reset
(
bytesTo
Read
);
packetBuffer
.
reset
(
bytesTo
Search
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesTo
Read
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesTo
Search
);
return
searchForScrValueInBuffer
(
packetBuffer
,
targetTimestamp
,
inputPosition
);
return
searchForScrValueInBuffer
(
packetBuffer
,
targetTimestamp
,
inputPosition
);
}
}
@Override
public
void
onSeekFinished
()
{
packetBuffer
.
reset
(
Util
.
EMPTY_BYTE_ARRAY
);
}
private
TimestampSearchResult
searchForScrValueInBuffer
(
private
TimestampSearchResult
searchForScrValueInBuffer
(
ParsableByteArray
packetBuffer
,
long
targetScrTimeUs
,
long
bufferStartOffset
)
{
ParsableByteArray
packetBuffer
,
long
targetScrTimeUs
,
long
bufferStartOffset
)
{
int
startOfLastPacketPosition
=
C
.
POSITION_UNSET
;
int
startOfLastPacketPosition
=
C
.
POSITION_UNSET
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java
View file @
6b0e1758
...
@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.ExtractorInput;
...
@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.ExtractorInput;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
/**
/**
...
@@ -38,7 +39,7 @@ import java.io.IOException;
...
@@ -38,7 +39,7 @@ import java.io.IOException;
*/
*/
/* package */
final
class
PsDurationReader
{
/* package */
final
class
PsDurationReader
{
private
static
final
int
DURATION_READ
_BYTES
=
20000
;
private
static
final
int
TIMESTAMP_SEARCH
_BYTES
=
20000
;
private
final
TimestampAdjuster
scrTimestampAdjuster
;
private
final
TimestampAdjuster
scrTimestampAdjuster
;
private
final
ParsableByteArray
packetBuffer
;
private
final
ParsableByteArray
packetBuffer
;
...
@@ -56,7 +57,7 @@ import java.io.IOException;
...
@@ -56,7 +57,7 @@ import java.io.IOException;
firstScrValue
=
C
.
TIME_UNSET
;
firstScrValue
=
C
.
TIME_UNSET
;
lastScrValue
=
C
.
TIME_UNSET
;
lastScrValue
=
C
.
TIME_UNSET
;
durationUs
=
C
.
TIME_UNSET
;
durationUs
=
C
.
TIME_UNSET
;
packetBuffer
=
new
ParsableByteArray
(
DURATION_READ_BYTES
);
packetBuffer
=
new
ParsableByteArray
();
}
}
/** Returns true if a PS duration has been read. */
/** Returns true if a PS duration has been read. */
...
@@ -129,6 +130,7 @@ import java.io.IOException;
...
@@ -129,6 +130,7 @@ import java.io.IOException;
}
}
private
int
finishReadDuration
(
ExtractorInput
input
)
{
private
int
finishReadDuration
(
ExtractorInput
input
)
{
packetBuffer
.
reset
(
Util
.
EMPTY_BYTE_ARRAY
);
isDurationRead
=
true
;
isDurationRead
=
true
;
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
return
Extractor
.
RESULT_CONTINUE
;
return
Extractor
.
RESULT_CONTINUE
;
...
@@ -136,16 +138,16 @@ import java.io.IOException;
...
@@ -136,16 +138,16 @@ import java.io.IOException;
private
int
readFirstScrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
)
private
int
readFirstScrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
if
(
input
.
getPosition
()
!=
0
)
{
int
bytesToSearch
=
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
input
.
getLength
());
seekPositionHolder
.
position
=
0
;
int
searchStartPosition
=
0
;
if
(
input
.
getPosition
()
!=
searchStartPosition
)
{
seekPositionHolder
.
position
=
searchStartPosition
;
return
Extractor
.
RESULT_SEEK
;
return
Extractor
.
RESULT_SEEK
;
}
}
int
bytesToRead
=
(
int
)
Math
.
min
(
DURATION_READ_BYTES
,
input
.
getLength
()
);
packetBuffer
.
reset
(
bytesToSearch
);
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToRead
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToSearch
);
packetBuffer
.
setPosition
(
0
);
packetBuffer
.
setLimit
(
bytesToRead
);
firstScrValue
=
readFirstScrValueFromBuffer
(
packetBuffer
);
firstScrValue
=
readFirstScrValueFromBuffer
(
packetBuffer
);
isFirstScrValueRead
=
true
;
isFirstScrValueRead
=
true
;
...
@@ -172,17 +174,17 @@ import java.io.IOException;
...
@@ -172,17 +174,17 @@ import java.io.IOException;
private
int
readLastScrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
)
private
int
readLastScrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
int
bytesToRead
=
(
int
)
Math
.
min
(
DURATION_READ_BYTES
,
input
.
getLength
());
long
inputLength
=
input
.
getLength
();
long
bufferStartStreamPosition
=
input
.
getLength
()
-
bytesToRead
;
int
bytesToSearch
=
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
inputLength
);
if
(
input
.
getPosition
()
!=
bufferStartStreamPosition
)
{
long
searchStartPosition
=
inputLength
-
bytesToSearch
;
seekPositionHolder
.
position
=
bufferStartStreamPosition
;
if
(
input
.
getPosition
()
!=
searchStartPosition
)
{
seekPositionHolder
.
position
=
searchStartPosition
;
return
Extractor
.
RESULT_SEEK
;
return
Extractor
.
RESULT_SEEK
;
}
}
packetBuffer
.
reset
(
bytesToSearch
);
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToRead
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToSearch
);
packetBuffer
.
setPosition
(
0
);
packetBuffer
.
setLimit
(
bytesToRead
);
lastScrValue
=
readLastScrValueFromBuffer
(
packetBuffer
);
lastScrValue
=
readLastScrValueFromBuffer
(
packetBuffer
);
isLastScrValueRead
=
true
;
isLastScrValueRead
=
true
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java
View file @
6b0e1758
...
@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
...
@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.extractor.BinarySearchSeeker;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.extractor.ExtractorInput
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
/**
/**
...
@@ -33,10 +34,8 @@ import java.io.IOException;
...
@@ -33,10 +34,8 @@ import java.io.IOException;
/* package */
final
class
TsBinarySearchSeeker
extends
BinarySearchSeeker
{
/* package */
final
class
TsBinarySearchSeeker
extends
BinarySearchSeeker
{
private
static
final
long
SEEK_TOLERANCE_US
=
100_000
;
private
static
final
long
SEEK_TOLERANCE_US
=
100_000
;
private
static
final
int
MINIMUM_SEARCH_RANGE_BYTES
=
TsExtractor
.
TS_PACKET_SIZE
*
5
;
private
static
final
int
MINIMUM_SEARCH_RANGE_BYTES
=
5
*
TsExtractor
.
TS_PACKET_SIZE
;
private
static
final
int
TIMESTAMP_SEARCH_PACKETS
=
200
;
private
static
final
int
TIMESTAMP_SEARCH_BYTES
=
600
*
TsExtractor
.
TS_PACKET_SIZE
;
private
static
final
int
TIMESTAMP_SEARCH_BYTES
=
TsExtractor
.
TS_PACKET_SIZE
*
TIMESTAMP_SEARCH_PACKETS
;
public
TsBinarySearchSeeker
(
public
TsBinarySearchSeeker
(
TimestampAdjuster
pcrTimestampAdjuster
,
long
streamDurationUs
,
long
inputLength
,
int
pcrPid
)
{
TimestampAdjuster
pcrTimestampAdjuster
,
long
streamDurationUs
,
long
inputLength
,
int
pcrPid
)
{
...
@@ -56,10 +55,10 @@ import java.io.IOException;
...
@@ -56,10 +55,10 @@ import java.io.IOException;
* A {@link TimestampSeeker} implementation that looks for a given PCR timestamp at a given
* A {@link TimestampSeeker} implementation that looks for a given PCR timestamp at a given
* position in a TS stream.
* position in a TS stream.
*
*
* <p>Given a PCR timestamp, and a position within a TS stream, this seeker will
try to read up to
* <p>Given a PCR timestamp, and a position within a TS stream, this seeker will
peek up to {@link
*
{@link #TIMESTAMP_SEARCH_PACKETS} TS packets from that stream position, look for all packet
*
#TIMESTAMP_SEARCH_BYTES} from that stream position, look for all packets with PID equal to
*
with PID equals to PCR_PID, and then compare the PCR timestamps (if available) of these packets
*
PCR_PID, and then compare the PCR timestamps (if available) of these packets to the target
*
vs the target
timestamp.
* timestamp.
*/
*/
private
static
final
class
TsPcrSeeker
implements
TimestampSeeker
{
private
static
final
class
TsPcrSeeker
implements
TimestampSeeker
{
...
@@ -70,7 +69,7 @@ import java.io.IOException;
...
@@ -70,7 +69,7 @@ import java.io.IOException;
public
TsPcrSeeker
(
int
pcrPid
,
TimestampAdjuster
pcrTimestampAdjuster
)
{
public
TsPcrSeeker
(
int
pcrPid
,
TimestampAdjuster
pcrTimestampAdjuster
)
{
this
.
pcrPid
=
pcrPid
;
this
.
pcrPid
=
pcrPid
;
this
.
pcrTimestampAdjuster
=
pcrTimestampAdjuster
;
this
.
pcrTimestampAdjuster
=
pcrTimestampAdjuster
;
packetBuffer
=
new
ParsableByteArray
(
TIMESTAMP_SEARCH_BYTES
);
packetBuffer
=
new
ParsableByteArray
();
}
}
@Override
@Override
...
@@ -78,10 +77,10 @@ import java.io.IOException;
...
@@ -78,10 +77,10 @@ import java.io.IOException;
ExtractorInput
input
,
long
targetTimestamp
,
OutputFrameHolder
outputFrameHolder
)
ExtractorInput
input
,
long
targetTimestamp
,
OutputFrameHolder
outputFrameHolder
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
long
inputPosition
=
input
.
getPosition
();
long
inputPosition
=
input
.
getPosition
();
int
bytesTo
Read
=
int
bytesTo
Search
=
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
input
.
getLength
()
-
inputPosition
);
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
input
.
getLength
()
-
input
.
getPosition
());
packetBuffer
.
reset
(
bytesTo
Read
);
packetBuffer
.
reset
(
bytesTo
Search
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesTo
Read
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesTo
Search
);
return
searchForPcrValueInBuffer
(
packetBuffer
,
targetTimestamp
,
inputPosition
);
return
searchForPcrValueInBuffer
(
packetBuffer
,
targetTimestamp
,
inputPosition
);
}
}
...
@@ -133,5 +132,10 @@ import java.io.IOException;
...
@@ -133,5 +132,10 @@ import java.io.IOException;
return
TimestampSearchResult
.
NO_TIMESTAMP_IN_RANGE_RESULT
;
return
TimestampSearchResult
.
NO_TIMESTAMP_IN_RANGE_RESULT
;
}
}
}
}
@Override
public
void
onSeekFinished
()
{
packetBuffer
.
reset
(
Util
.
EMPTY_BYTE_ARRAY
);
}
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java
View file @
6b0e1758
...
@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.ExtractorInput;
...
@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.extractor.ExtractorInput;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.extractor.PositionHolder
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
/**
/**
...
@@ -35,8 +36,7 @@ import java.io.IOException;
...
@@ -35,8 +36,7 @@ import java.io.IOException;
*/
*/
/* package */
final
class
TsDurationReader
{
/* package */
final
class
TsDurationReader
{
private
static
final
int
DURATION_READ_PACKETS
=
200
;
private
static
final
int
TIMESTAMP_SEARCH_BYTES
=
600
*
TsExtractor
.
TS_PACKET_SIZE
;
private
static
final
int
DURATION_READ_BYTES
=
TsExtractor
.
TS_PACKET_SIZE
*
DURATION_READ_PACKETS
;
private
final
TimestampAdjuster
pcrTimestampAdjuster
;
private
final
TimestampAdjuster
pcrTimestampAdjuster
;
private
final
ParsableByteArray
packetBuffer
;
private
final
ParsableByteArray
packetBuffer
;
...
@@ -54,7 +54,7 @@ import java.io.IOException;
...
@@ -54,7 +54,7 @@ import java.io.IOException;
firstPcrValue
=
C
.
TIME_UNSET
;
firstPcrValue
=
C
.
TIME_UNSET
;
lastPcrValue
=
C
.
TIME_UNSET
;
lastPcrValue
=
C
.
TIME_UNSET
;
durationUs
=
C
.
TIME_UNSET
;
durationUs
=
C
.
TIME_UNSET
;
packetBuffer
=
new
ParsableByteArray
(
DURATION_READ_BYTES
);
packetBuffer
=
new
ParsableByteArray
();
}
}
/** Returns true if a TS duration has been read. */
/** Returns true if a TS duration has been read. */
...
@@ -117,6 +117,7 @@ import java.io.IOException;
...
@@ -117,6 +117,7 @@ import java.io.IOException;
}
}
private
int
finishReadDuration
(
ExtractorInput
input
)
{
private
int
finishReadDuration
(
ExtractorInput
input
)
{
packetBuffer
.
reset
(
Util
.
EMPTY_BYTE_ARRAY
);
isDurationRead
=
true
;
isDurationRead
=
true
;
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
return
Extractor
.
RESULT_CONTINUE
;
return
Extractor
.
RESULT_CONTINUE
;
...
@@ -124,16 +125,16 @@ import java.io.IOException;
...
@@ -124,16 +125,16 @@ import java.io.IOException;
private
int
readFirstPcrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
,
int
pcrPid
)
private
int
readFirstPcrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
,
int
pcrPid
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
if
(
input
.
getPosition
()
!=
0
)
{
int
bytesToSearch
=
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
input
.
getLength
());
seekPositionHolder
.
position
=
0
;
int
searchStartPosition
=
0
;
if
(
input
.
getPosition
()
!=
searchStartPosition
)
{
seekPositionHolder
.
position
=
searchStartPosition
;
return
Extractor
.
RESULT_SEEK
;
return
Extractor
.
RESULT_SEEK
;
}
}
int
bytesToRead
=
(
int
)
Math
.
min
(
DURATION_READ_BYTES
,
input
.
getLength
()
);
packetBuffer
.
reset
(
bytesToSearch
);
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToRead
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToSearch
);
packetBuffer
.
setPosition
(
0
);
packetBuffer
.
setLimit
(
bytesToRead
);
firstPcrValue
=
readFirstPcrValueFromBuffer
(
packetBuffer
,
pcrPid
);
firstPcrValue
=
readFirstPcrValueFromBuffer
(
packetBuffer
,
pcrPid
);
isFirstPcrValueRead
=
true
;
isFirstPcrValueRead
=
true
;
...
@@ -159,17 +160,17 @@ import java.io.IOException;
...
@@ -159,17 +160,17 @@ import java.io.IOException;
private
int
readLastPcrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
,
int
pcrPid
)
private
int
readLastPcrValue
(
ExtractorInput
input
,
PositionHolder
seekPositionHolder
,
int
pcrPid
)
throws
IOException
,
InterruptedException
{
throws
IOException
,
InterruptedException
{
int
bytesToRead
=
(
int
)
Math
.
min
(
DURATION_READ_BYTES
,
input
.
getLength
());
long
inputLength
=
input
.
getLength
();
long
bufferStartStreamPosition
=
input
.
getLength
()
-
bytesToRead
;
int
bytesToSearch
=
(
int
)
Math
.
min
(
TIMESTAMP_SEARCH_BYTES
,
inputLength
);
if
(
input
.
getPosition
()
!=
bufferStartStreamPosition
)
{
long
searchStartPosition
=
inputLength
-
bytesToSearch
;
seekPositionHolder
.
position
=
bufferStartStreamPosition
;
if
(
input
.
getPosition
()
!=
searchStartPosition
)
{
seekPositionHolder
.
position
=
searchStartPosition
;
return
Extractor
.
RESULT_SEEK
;
return
Extractor
.
RESULT_SEEK
;
}
}
packetBuffer
.
reset
(
bytesToSearch
);
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToRead
);
input
.
peekFully
(
packetBuffer
.
data
,
/* offset= */
0
,
bytesToSearch
);
packetBuffer
.
setPosition
(
0
);
packetBuffer
.
setLimit
(
bytesToRead
);
lastPcrValue
=
readLastPcrValueFromBuffer
(
packetBuffer
,
pcrPid
);
lastPcrValue
=
readLastPcrValueFromBuffer
(
packetBuffer
,
pcrPid
);
isLastPcrValueRead
=
true
;
isLastPcrValueRead
=
true
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java
View file @
6b0e1758
...
@@ -129,9 +129,12 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
...
@@ -129,9 +129,12 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
buffer
.
subsampleOffsetUs
=
formatHolder
.
format
.
subsampleOffsetUs
;
buffer
.
subsampleOffsetUs
=
formatHolder
.
format
.
subsampleOffsetUs
;
buffer
.
flip
();
buffer
.
flip
();
int
index
=
(
pendingMetadataIndex
+
pendingMetadataCount
)
%
MAX_PENDING_METADATA_COUNT
;
int
index
=
(
pendingMetadataIndex
+
pendingMetadataCount
)
%
MAX_PENDING_METADATA_COUNT
;
pendingMetadata
[
index
]
=
decoder
.
decode
(
buffer
);
Metadata
metadata
=
decoder
.
decode
(
buffer
);
pendingMetadataTimestamps
[
index
]
=
buffer
.
timeUs
;
if
(
metadata
!=
null
)
{
pendingMetadataCount
++;
pendingMetadata
[
index
]
=
metadata
;
pendingMetadataTimestamps
[
index
]
=
buffer
.
timeUs
;
pendingMetadataCount
++;
}
}
}
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java
View file @
6b0e1758
...
@@ -365,6 +365,9 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -365,6 +365,9 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
public
final
synchronized
void
moveMediaSource
(
public
final
synchronized
void
moveMediaSource
(
int
currentIndex
,
int
newIndex
,
@Nullable
Runnable
actionOnCompletion
)
{
int
currentIndex
,
int
newIndex
,
@Nullable
Runnable
actionOnCompletion
)
{
if
(
currentIndex
==
newIndex
)
{
if
(
currentIndex
==
newIndex
)
{
if
(
actionOnCompletion
!=
null
)
{
actionOnCompletion
.
run
();
}
return
;
return
;
}
}
mediaSourcesPublic
.
add
(
newIndex
,
mediaSourcesPublic
.
remove
(
currentIndex
));
mediaSourcesPublic
.
add
(
newIndex
,
mediaSourcesPublic
.
remove
(
currentIndex
));
...
@@ -570,9 +573,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -570,9 +573,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
if
(
fromIndex
==
0
&&
toIndex
==
shuffleOrder
.
getLength
())
{
if
(
fromIndex
==
0
&&
toIndex
==
shuffleOrder
.
getLength
())
{
shuffleOrder
=
shuffleOrder
.
cloneAndClear
();
shuffleOrder
=
shuffleOrder
.
cloneAndClear
();
}
else
{
}
else
{
for
(
int
index
=
toIndex
-
1
;
index
>=
fromIndex
;
index
--)
{
shuffleOrder
=
shuffleOrder
.
cloneAndRemove
(
fromIndex
,
toIndex
);
shuffleOrder
=
shuffleOrder
.
cloneAndRemove
(
index
);
}
}
}
for
(
int
index
=
toIndex
-
1
;
index
>=
fromIndex
;
index
--)
{
for
(
int
index
=
toIndex
-
1
;
index
>=
fromIndex
;
index
--)
{
removeMediaSourceInternal
(
index
);
removeMediaSourceInternal
(
index
);
...
@@ -581,7 +582,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
...
@@ -581,7 +582,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
break
;
break
;
case
MSG_MOVE:
case
MSG_MOVE:
MessageData
<
Integer
>
moveMessage
=
(
MessageData
<
Integer
>)
Util
.
castNonNull
(
message
);
MessageData
<
Integer
>
moveMessage
=
(
MessageData
<
Integer
>)
Util
.
castNonNull
(
message
);
shuffleOrder
=
shuffleOrder
.
cloneAndRemove
(
moveMessage
.
index
);
shuffleOrder
=
shuffleOrder
.
cloneAndRemove
(
moveMessage
.
index
,
moveMessage
.
index
+
1
);
shuffleOrder
=
shuffleOrder
.
cloneAndInsert
(
moveMessage
.
customData
,
1
);
shuffleOrder
=
shuffleOrder
.
cloneAndInsert
(
moveMessage
.
customData
,
1
);
moveMediaSourceInternal
(
moveMessage
.
index
,
moveMessage
.
customData
);
moveMediaSourceInternal
(
moveMessage
.
index
,
moveMessage
.
customData
);
scheduleListenerNotification
(
moveMessage
.
actionOnCompletion
);
scheduleListenerNotification
(
moveMessage
.
actionOnCompletion
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java
View file @
6b0e1758
...
@@ -30,10 +30,8 @@ import java.io.EOFException;
...
@@ -30,10 +30,8 @@ import java.io.EOFException;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
/**
/** A queue of media samples. */
* A queue of media samples.
public
class
SampleQueue
implements
TrackOutput
{
*/
public
final
class
SampleQueue
implements
TrackOutput
{
/**
/**
* A listener for changes to the upstream format.
* A listener for changes to the upstream format.
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ShuffleOrder.java
View file @
6b0e1758
...
@@ -55,6 +55,17 @@ public interface ShuffleOrder {
...
@@ -55,6 +55,17 @@ public interface ShuffleOrder {
this
(
length
,
new
Random
(
randomSeed
));
this
(
length
,
new
Random
(
randomSeed
));
}
}
/**
* Creates an instance with a specified shuffle order and the specified random seed. The random
* seed is used for {@link #cloneAndInsert(int, int)} invocations.
*
* @param shuffledIndices The shuffled indices to use as order.
* @param randomSeed A random seed.
*/
public
DefaultShuffleOrder
(
int
[]
shuffledIndices
,
long
randomSeed
)
{
this
(
Arrays
.
copyOf
(
shuffledIndices
,
shuffledIndices
.
length
),
new
Random
(
randomSeed
));
}
private
DefaultShuffleOrder
(
int
length
,
Random
random
)
{
private
DefaultShuffleOrder
(
int
length
,
Random
random
)
{
this
(
createShuffledList
(
length
,
random
),
random
);
this
(
createShuffledList
(
length
,
random
),
random
);
}
}
...
@@ -124,15 +135,16 @@ public interface ShuffleOrder {
...
@@ -124,15 +135,16 @@ public interface ShuffleOrder {
}
}
@Override
@Override
public
ShuffleOrder
cloneAndRemove
(
int
removalIndex
)
{
public
ShuffleOrder
cloneAndRemove
(
int
indexFrom
,
int
indexToExclusive
)
{
int
[]
newShuffled
=
new
int
[
shuffled
.
length
-
1
];
int
numberOfElementsToRemove
=
indexToExclusive
-
indexFrom
;
boolean
foundRemovedElement
=
false
;
int
[]
newShuffled
=
new
int
[
shuffled
.
length
-
numberOfElementsToRemove
];
int
foundElementsCount
=
0
;
for
(
int
i
=
0
;
i
<
shuffled
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
shuffled
.
length
;
i
++)
{
if
(
shuffled
[
i
]
==
removalIndex
)
{
if
(
shuffled
[
i
]
>=
indexFrom
&&
shuffled
[
i
]
<
indexToExclusive
)
{
found
RemovedElement
=
true
;
found
ElementsCount
++
;
}
else
{
}
else
{
newShuffled
[
foundRemovedElement
?
i
-
1
:
i
]
=
shuffled
[
i
]
>
removalIndex
newShuffled
[
i
-
foundElementsCount
]
=
?
shuffled
[
i
]
-
1
:
shuffled
[
i
];
shuffled
[
i
]
>=
indexFrom
?
shuffled
[
i
]
-
numberOfElementsToRemove
:
shuffled
[
i
];
}
}
}
}
return
new
DefaultShuffleOrder
(
newShuffled
,
new
Random
(
random
.
nextLong
()));
return
new
DefaultShuffleOrder
(
newShuffled
,
new
Random
(
random
.
nextLong
()));
...
@@ -202,8 +214,8 @@ public interface ShuffleOrder {
...
@@ -202,8 +214,8 @@ public interface ShuffleOrder {
}
}
@Override
@Override
public
ShuffleOrder
cloneAndRemove
(
int
removalIndex
)
{
public
ShuffleOrder
cloneAndRemove
(
int
indexFrom
,
int
indexToExclusive
)
{
return
new
UnshuffledShuffleOrder
(
length
-
1
);
return
new
UnshuffledShuffleOrder
(
length
-
indexToExclusive
+
indexFrom
);
}
}
@Override
@Override
...
@@ -257,12 +269,14 @@ public interface ShuffleOrder {
...
@@ -257,12 +269,14 @@ public interface ShuffleOrder {
ShuffleOrder
cloneAndInsert
(
int
insertionIndex
,
int
insertionCount
);
ShuffleOrder
cloneAndInsert
(
int
insertionIndex
,
int
insertionCount
);
/**
/**
* Returns a copy of the shuffle order with
one element
removed.
* Returns a copy of the shuffle order with
a range of elements
removed.
*
*
* @param removalIndex The index of the element in the unshuffled order which is to be removed.
* @param indexFrom The starting index in the unshuffled order of the range to remove.
* @return A copy of this {@link ShuffleOrder} without the removed element.
* @param indexToExclusive The smallest index (must be greater or equal to {@code indexFrom}) that
* will not be removed.
* @return A copy of this {@link ShuffleOrder} without the elements in the removed range.
*/
*/
ShuffleOrder
cloneAndRemove
(
int
removalIndex
);
ShuffleOrder
cloneAndRemove
(
int
indexFrom
,
int
indexToExclusive
);
/** Returns a copy of the shuffle order with all elements removed. */
/** Returns a copy of the shuffle order with all elements removed. */
ShuffleOrder
cloneAndClear
();
ShuffleOrder
cloneAndClear
();
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java
View file @
6b0e1758
...
@@ -33,6 +33,7 @@ import com.google.android.exoplayer2.text.SubtitleInputBuffer;
...
@@ -33,6 +33,7 @@ import com.google.android.exoplayer2.text.SubtitleInputBuffer;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
/**
/**
...
@@ -451,7 +452,7 @@ public final class Cea608Decoder extends CeaDecoder {
...
@@ -451,7 +452,7 @@ public final class Cea608Decoder extends CeaDecoder {
switch
(
cc2
)
{
switch
(
cc2
)
{
case
CTRL_ERASE_DISPLAYED_MEMORY:
case
CTRL_ERASE_DISPLAYED_MEMORY:
cues
=
null
;
cues
=
Collections
.
emptyList
()
;
if
(
captionMode
==
CC_MODE_ROLL_UP
||
captionMode
==
CC_MODE_PAINT_ON
)
{
if
(
captionMode
==
CC_MODE_ROLL_UP
||
captionMode
==
CC_MODE_PAINT_ON
)
{
resetCueBuilders
();
resetCueBuilders
();
}
}
...
@@ -506,7 +507,7 @@ public final class Cea608Decoder extends CeaDecoder {
...
@@ -506,7 +507,7 @@ public final class Cea608Decoder extends CeaDecoder {
if
(
oldCaptionMode
==
CC_MODE_PAINT_ON
||
captionMode
==
CC_MODE_ROLL_UP
if
(
oldCaptionMode
==
CC_MODE_PAINT_ON
||
captionMode
==
CC_MODE_ROLL_UP
||
captionMode
==
CC_MODE_UNKNOWN
)
{
||
captionMode
==
CC_MODE_UNKNOWN
)
{
// When switching from paint-on or to roll-up or unknown, we also need to clear the caption.
// When switching from paint-on or to roll-up or unknown, we also need to clear the caption.
cues
=
null
;
cues
=
Collections
.
emptyList
()
;
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoder.java
View file @
6b0e1758
...
@@ -110,7 +110,7 @@ public final class WebvttDecoder extends SimpleSubtitleDecoder {
...
@@ -110,7 +110,7 @@ public final class WebvttDecoder extends SimpleSubtitleDecoder {
foundEvent
=
EVENT_END_OF_FILE
;
foundEvent
=
EVENT_END_OF_FILE
;
}
else
if
(
STYLE_START
.
equals
(
line
))
{
}
else
if
(
STYLE_START
.
equals
(
line
))
{
foundEvent
=
EVENT_STYLE_BLOCK
;
foundEvent
=
EVENT_STYLE_BLOCK
;
}
else
if
(
COMMENT_START
.
startsWith
(
line
))
{
}
else
if
(
line
.
startsWith
(
COMMENT_START
))
{
foundEvent
=
EVENT_COMMENT
;
foundEvent
=
EVENT_COMMENT
;
}
else
{
}
else
{
foundEvent
=
EVENT_CUE
;
foundEvent
=
EVENT_CUE
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/trackselection/BaseTrackSelection.java
View file @
6b0e1758
...
@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.Format;
...
@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.Format;
import
com.google.android.exoplayer2.source.TrackGroup
;
import
com.google.android.exoplayer2.source.TrackGroup
;
import
com.google.android.exoplayer2.source.chunk.MediaChunk
;
import
com.google.android.exoplayer2.source.chunk.MediaChunk
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Comparator
;
import
java.util.Comparator
;
import
java.util.List
;
import
java.util.List
;
...
@@ -160,7 +161,10 @@ public abstract class BaseTrackSelection implements TrackSelection {
...
@@ -160,7 +161,10 @@ public abstract class BaseTrackSelection implements TrackSelection {
if
(!
canBlacklist
)
{
if
(!
canBlacklist
)
{
return
false
;
return
false
;
}
}
blacklistUntilTimes
[
index
]
=
Math
.
max
(
blacklistUntilTimes
[
index
],
nowMs
+
blacklistDurationMs
);
blacklistUntilTimes
[
index
]
=
Math
.
max
(
blacklistUntilTimes
[
index
],
Util
.
addWithOverflowDefault
(
nowMs
,
blacklistDurationMs
,
Long
.
MAX_VALUE
));
return
true
;
return
true
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java
View file @
6b0e1758
...
@@ -207,7 +207,7 @@ public final class MimeTypes {
...
@@ -207,7 +207,7 @@ public final class MimeTypes {
if
(
codec
==
null
)
{
if
(
codec
==
null
)
{
return
null
;
return
null
;
}
}
codec
=
codec
.
trim
(
);
codec
=
Util
.
toLowerInvariant
(
codec
.
trim
()
);
if
(
codec
.
startsWith
(
"avc1"
)
||
codec
.
startsWith
(
"avc3"
))
{
if
(
codec
.
startsWith
(
"avc1"
)
||
codec
.
startsWith
(
"avc3"
))
{
return
MimeTypes
.
VIDEO_H264
;
return
MimeTypes
.
VIDEO_H264
;
}
else
if
(
codec
.
startsWith
(
"hev1"
)
||
codec
.
startsWith
(
"hvc1"
))
{
}
else
if
(
codec
.
startsWith
(
"hev1"
)
||
codec
.
startsWith
(
"hvc1"
))
{
...
@@ -245,6 +245,8 @@ public final class MimeTypes {
...
@@ -245,6 +245,8 @@ public final class MimeTypes {
return
MimeTypes
.
AUDIO_OPUS
;
return
MimeTypes
.
AUDIO_OPUS
;
}
else
if
(
codec
.
startsWith
(
"vorbis"
))
{
}
else
if
(
codec
.
startsWith
(
"vorbis"
))
{
return
MimeTypes
.
AUDIO_VORBIS
;
return
MimeTypes
.
AUDIO_VORBIS
;
}
else
if
(
codec
.
startsWith
(
"flac"
))
{
return
MimeTypes
.
AUDIO_FLAC
;
}
else
{
}
else
{
return
getCustomMimeTypeForCodec
(
codec
);
return
getCustomMimeTypeForCodec
(
codec
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java
View file @
6b0e1758
...
@@ -67,6 +67,12 @@ public final class ParsableByteArray {
...
@@ -67,6 +67,12 @@ public final class ParsableByteArray {
this
.
limit
=
limit
;
this
.
limit
=
limit
;
}
}
/** Sets the position and limit to zero. */
public
void
reset
()
{
position
=
0
;
limit
=
0
;
}
/**
/**
* Resets the position to zero and the limit to the specified value. If the limit exceeds the
* Resets the position to zero and the limit to the specified value. If the limit exceeds the
* capacity, {@code data} is replaced with a new array of sufficient size.
* capacity, {@code data} is replaced with a new array of sufficient size.
...
@@ -78,6 +84,16 @@ public final class ParsableByteArray {
...
@@ -78,6 +84,16 @@ public final class ParsableByteArray {
}
}
/**
/**
* Updates the instance to wrap {@code data}, and resets the position to zero and the limit to
* {@code data.length}.
*
* @param data The array to wrap.
*/
public
void
reset
(
byte
[]
data
)
{
reset
(
data
,
data
.
length
);
}
/**
* Updates the instance to wrap {@code data}, and resets the position to zero.
* Updates the instance to wrap {@code data}, and resets the position to zero.
*
*
* @param data The array to wrap.
* @param data The array to wrap.
...
@@ -90,14 +106,6 @@ public final class ParsableByteArray {
...
@@ -90,14 +106,6 @@ public final class ParsableByteArray {
}
}
/**
/**
* Sets the position and limit to zero.
*/
public
void
reset
()
{
position
=
0
;
limit
=
0
;
}
/**
* Returns the number of bytes yet to be read.
* Returns the number of bytes yet to be read.
*/
*/
public
int
bytesLeft
()
{
public
int
bytesLeft
()
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/RepeatModeUtil.java
View file @
6b0e1758
...
@@ -26,6 +26,7 @@ import java.lang.annotation.RetentionPolicy;
...
@@ -26,6 +26,7 @@ import java.lang.annotation.RetentionPolicy;
*/
*/
public
final
class
RepeatModeUtil
{
public
final
class
RepeatModeUtil
{
// LINT.IfChange
/**
/**
* Set of repeat toggle modes. Can be combined using bit-wise operations. Possible flag values are
* Set of repeat toggle modes. Can be combined using bit-wise operations. Possible flag values are
* {@link #REPEAT_TOGGLE_MODE_NONE}, {@link #REPEAT_TOGGLE_MODE_ONE} and {@link
* {@link #REPEAT_TOGGLE_MODE_NONE}, {@link #REPEAT_TOGGLE_MODE_ONE} and {@link
...
@@ -47,6 +48,7 @@ public final class RepeatModeUtil {
...
@@ -47,6 +48,7 @@ public final class RepeatModeUtil {
public
static
final
int
REPEAT_TOGGLE_MODE_ONE
=
1
;
public
static
final
int
REPEAT_TOGGLE_MODE_ONE
=
1
;
/** "Repeat All" button enabled. */
/** "Repeat All" button enabled. */
public
static
final
int
REPEAT_TOGGLE_MODE_ALL
=
1
<<
1
;
// 2
public
static
final
int
REPEAT_TOGGLE_MODE_ALL
=
1
<<
1
;
// 2
// LINT.ThenChange(../../../../../../../../../ui/src/main/res/values/attrs.xml)
private
RepeatModeUtil
()
{
private
RepeatModeUtil
()
{
// Prevent instantiation.
// Prevent instantiation.
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
View file @
6b0e1758
...
@@ -1329,6 +1329,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1329,6 +1329,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
case
"A7010a48"
:
case
"A7010a48"
:
case
"A7020a48"
:
case
"A7020a48"
:
case
"AquaPowerM"
:
case
"AquaPowerM"
:
case
"ASUS_X00AD_2"
:
case
"Aura_Note_2"
:
case
"Aura_Note_2"
:
case
"BLACK-1X"
:
case
"BLACK-1X"
:
case
"BRAVIA_ATV2"
:
case
"BRAVIA_ATV2"
:
...
@@ -1369,6 +1370,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1369,6 +1370,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
case
"HWBLN-H"
:
case
"HWBLN-H"
:
case
"HWCAM-H"
:
case
"HWCAM-H"
:
case
"HWVNS-H"
:
case
"HWVNS-H"
:
case
"i9031"
:
case
"iball8735_9806"
:
case
"iball8735_9806"
:
case
"Infinix-X572"
:
case
"Infinix-X572"
:
case
"iris60"
:
case
"iris60"
:
...
@@ -1376,6 +1378,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1376,6 +1378,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
case
"j2xlteins"
:
case
"j2xlteins"
:
case
"JGZ"
:
case
"JGZ"
:
case
"K50a40"
:
case
"K50a40"
:
case
"kate"
:
case
"le_x6"
:
case
"le_x6"
:
case
"LS-5017"
:
case
"LS-5017"
:
case
"M5c"
:
case
"M5c"
:
...
...
library/core/src/test/assets/ts/sample.ts.1.dump
View file @
6b0e1758
...
@@ -26,10 +26,14 @@ track 256:
...
@@ -26,10 +26,14 @@ track 256:
drmInitData = -
drmInitData = -
initializationData:
initializationData:
data = length 22, hash CE183139
data = length 22, hash CE183139
total output bytes =
24315
total output bytes =
45026
sample count =
1
sample count =
2
sample 0:
sample 0:
time = 55611
time = 55610
flags = 1
data = length 20711, hash 34341E8
sample 1:
time = 88977
flags = 0
flags = 0
data = length 18112, hash EC44B35B
data = length 18112, hash EC44B35B
track 257:
track 257:
...
@@ -57,19 +61,19 @@ track 257:
...
@@ -57,19 +61,19 @@ track 257:
total output bytes = 5015
total output bytes = 5015
sample count = 4
sample count = 4
sample 0:
sample 0:
time =
11333
time =
44699
flags = 1
flags = 1
data = length 1253, hash 727FD1C6
data = length 1253, hash 727FD1C6
sample 1:
sample 1:
time =
37455
time =
70821
flags = 1
flags = 1
data = length 1254, hash 73FB07B8
data = length 1254, hash 73FB07B8
sample 2:
sample 2:
time =
63578
time =
96944
flags = 1
flags = 1
data = length 1254, hash 73FB07B8
data = length 1254, hash 73FB07B8
sample 3:
sample 3:
time =
89700
time =
123066
flags = 1
flags = 1
data = length 1254, hash 73FB07B8
data = length 1254, hash 73FB07B8
track 8448:
track 8448:
...
...
library/core/src/test/assets/ts/sample.ts.2.dump
View file @
6b0e1758
...
@@ -26,10 +26,14 @@ track 256:
...
@@ -26,10 +26,14 @@ track 256:
drmInitData = -
drmInitData = -
initializationData:
initializationData:
data = length 22, hash CE183139
data = length 22, hash CE183139
total output bytes =
24315
total output bytes =
45026
sample count =
1
sample count =
2
sample 0:
sample 0:
time = 77855
time = 77854
flags = 1
data = length 20711, hash 34341E8
sample 1:
time = 111221
flags = 0
flags = 0
data = length 18112, hash EC44B35B
data = length 18112, hash EC44B35B
track 257:
track 257:
...
@@ -57,19 +61,19 @@ track 257:
...
@@ -57,19 +61,19 @@ track 257:
total output bytes = 5015
total output bytes = 5015
sample count = 4
sample count = 4
sample 0:
sample 0:
time =
33577
time =
66943
flags = 1
flags = 1
data = length 1253, hash 727FD1C6
data = length 1253, hash 727FD1C6
sample 1:
sample 1:
time =
59699
time =
93065
flags = 1
flags = 1
data = length 1254, hash 73FB07B8
data = length 1254, hash 73FB07B8
sample 2:
sample 2:
time =
85822
time =
119188
flags = 1
flags = 1
data = length 1254, hash 73FB07B8
data = length 1254, hash 73FB07B8
sample 3:
sample 3:
time = 1
11944
time = 1
45310
flags = 1
flags = 1
data = length 1254, hash 73FB07B8
data = length 1254, hash 73FB07B8
track 8448:
track 8448:
...
...
library/core/src/test/java/com/google/android/exoplayer2/DefaultLoadControlTest.java
View file @
6b0e1758
...
@@ -48,15 +48,15 @@ public class DefaultLoadControlTest {
...
@@ -48,15 +48,15 @@ public class DefaultLoadControlTest {
createDefaultLoadControl
();
createDefaultLoadControl
();
assertThat
(
loadControl
.
shouldContinueLoading
(
/* bufferedDurationUs= */
0
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
/* bufferedDurationUs= */
0
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
-
1
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
+
1
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
SPEED
)).
isFalse
();
}
}
@Test
@Test
public
void
testShouldNotContinueLoadingOnceBufferingStopped_untilBelowMinBuffer
()
{
public
void
testShouldNotContinueLoadingOnceBufferingStopped_untilBelowMinBuffer
()
{
createDefaultLoadControl
();
createDefaultLoadControl
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
+
1
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
-
1
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
-
1
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
-
1
,
SPEED
)).
isTrue
();
}
}
...
@@ -69,7 +69,7 @@ public class DefaultLoadControlTest {
...
@@ -69,7 +69,7 @@ public class DefaultLoadControlTest {
assertThat
(
loadControl
.
shouldContinueLoading
(
/* bufferedDurationUs= */
0
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
/* bufferedDurationUs= */
0
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
-
1
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
-
1
,
SPEED
)).
isTrue
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
+
1
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
SPEED
)).
isFalse
();
}
}
@Test
@Test
...
@@ -82,7 +82,7 @@ public class DefaultLoadControlTest {
...
@@ -82,7 +82,7 @@ public class DefaultLoadControlTest {
assertThat
(
loadControl
.
shouldContinueLoading
(
/* bufferedDurationUs= */
0
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
/* bufferedDurationUs= */
0
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MIN_BUFFER_US
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
+
1
,
SPEED
)).
isFalse
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
SPEED
)).
isFalse
();
}
}
@Test
@Test
...
@@ -100,7 +100,7 @@ public class DefaultLoadControlTest {
...
@@ -100,7 +100,7 @@ public class DefaultLoadControlTest {
public
void
testShouldNotContinueLoadingWithMaxBufferReached_inFastPlayback
()
{
public
void
testShouldNotContinueLoadingWithMaxBufferReached_inFastPlayback
()
{
createDefaultLoadControl
();
createDefaultLoadControl
();
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
+
1
,
/* playbackSpeed= */
100
f
))
assertThat
(
loadControl
.
shouldContinueLoading
(
MAX_BUFFER_US
,
/* playbackSpeed= */
100
f
))
.
isFalse
();
.
isFalse
();
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/source/ShuffleOrderTest.java
View file @
6b0e1758
...
@@ -45,10 +45,32 @@ public final class ShuffleOrderTest {
...
@@ -45,10 +45,32 @@ public final class ShuffleOrderTest {
testCloneAndInsert
(
new
DefaultShuffleOrder
(
initialLength
,
RANDOM_SEED
),
insertionPoint
,
5
);
testCloneAndInsert
(
new
DefaultShuffleOrder
(
initialLength
,
RANDOM_SEED
),
insertionPoint
,
5
);
}
}
}
}
testCloneAndRemove
(
new
DefaultShuffleOrder
(
5
,
RANDOM_SEED
),
0
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
5
,
RANDOM_SEED
),
0
,
1
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
5
,
RANDOM_SEED
),
2
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
5
,
RANDOM_SEED
),
2
,
3
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
5
,
RANDOM_SEED
),
4
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
5
,
RANDOM_SEED
),
4
,
5
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1
,
RANDOM_SEED
),
0
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1
,
RANDOM_SEED
),
0
,
1
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1000
,
RANDOM_SEED
),
0
,
1000
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1000
,
RANDOM_SEED
),
0
,
999
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1000
,
RANDOM_SEED
),
0
,
500
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1000
,
RANDOM_SEED
),
100
,
600
);
testCloneAndRemove
(
new
DefaultShuffleOrder
(
1000
,
RANDOM_SEED
),
500
,
1000
);
}
@Test
public
void
testDefaultShuffleOrderSideloaded
()
{
int
[]
shuffledIndices
=
new
int
[]
{
2
,
1
,
0
,
4
,
3
};
ShuffleOrder
shuffleOrder
=
new
DefaultShuffleOrder
(
shuffledIndices
,
RANDOM_SEED
);
assertThat
(
shuffleOrder
.
getFirstIndex
()).
isEqualTo
(
2
);
assertThat
(
shuffleOrder
.
getLastIndex
()).
isEqualTo
(
3
);
for
(
int
i
=
0
;
i
<
4
;
i
++)
{
assertThat
(
shuffleOrder
.
getNextIndex
(
shuffledIndices
[
i
])).
isEqualTo
(
shuffledIndices
[
i
+
1
]);
}
assertThat
(
shuffleOrder
.
getNextIndex
(
3
)).
isEqualTo
(
C
.
INDEX_UNSET
);
for
(
int
i
=
4
;
i
>
0
;
i
--)
{
assertThat
(
shuffleOrder
.
getPreviousIndex
(
shuffledIndices
[
i
]))
.
isEqualTo
(
shuffledIndices
[
i
-
1
]);
}
assertThat
(
shuffleOrder
.
getPreviousIndex
(
2
)).
isEqualTo
(
C
.
INDEX_UNSET
);
}
}
@Test
@Test
...
@@ -63,10 +85,15 @@ public final class ShuffleOrderTest {
...
@@ -63,10 +85,15 @@ public final class ShuffleOrderTest {
testCloneAndInsert
(
new
UnshuffledShuffleOrder
(
initialLength
),
insertionPoint
,
5
);
testCloneAndInsert
(
new
UnshuffledShuffleOrder
(
initialLength
),
insertionPoint
,
5
);
}
}
}
}
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
5
),
0
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
5
),
0
,
1
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
5
),
2
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
5
),
2
,
3
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
5
),
4
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
5
),
4
,
5
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1
),
0
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1
),
0
,
1
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1000
),
0
,
1000
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1000
),
0
,
999
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1000
),
0
,
500
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1000
),
100
,
600
);
testCloneAndRemove
(
new
UnshuffledShuffleOrder
(
1000
),
500
,
1000
);
}
}
@Test
@Test
...
@@ -120,22 +147,24 @@ public final class ShuffleOrderTest {
...
@@ -120,22 +147,24 @@ public final class ShuffleOrderTest {
}
}
}
}
private
static
void
testCloneAndRemove
(
ShuffleOrder
shuffleOrder
,
int
position
)
{
private
static
void
testCloneAndRemove
(
ShuffleOrder
newOrder
=
shuffleOrder
.
cloneAndRemove
(
position
);
ShuffleOrder
shuffleOrder
,
int
indexFrom
,
int
indexToExclusive
)
{
assertShuffleOrderCorrectness
(
newOrder
,
shuffleOrder
.
getLength
()
-
1
);
int
numberOfElementsToRemove
=
indexToExclusive
-
indexFrom
;
ShuffleOrder
newOrder
=
shuffleOrder
.
cloneAndRemove
(
indexFrom
,
indexToExclusive
);
assertShuffleOrderCorrectness
(
newOrder
,
shuffleOrder
.
getLength
()
-
numberOfElementsToRemove
);
// Assert all elements still have the relative same order
// Assert all elements still have the relative same order
for
(
int
i
=
0
;
i
<
shuffleOrder
.
getLength
();
i
++)
{
for
(
int
i
=
0
;
i
<
shuffleOrder
.
getLength
();
i
++)
{
if
(
i
==
position
)
{
if
(
i
>=
indexFrom
&&
i
<
indexToExclusive
)
{
continue
;
continue
;
}
}
int
expectedNextIndex
=
shuffleOrder
.
getNextIndex
(
i
);
int
expectedNextIndex
=
shuffleOrder
.
getNextIndex
(
i
);
if
(
expectedNextIndex
==
position
)
{
while
(
expectedNextIndex
>=
indexFrom
&&
expectedNextIndex
<
indexToExclusive
)
{
expectedNextIndex
=
shuffleOrder
.
getNextIndex
(
expectedNextIndex
);
expectedNextIndex
=
shuffleOrder
.
getNextIndex
(
expectedNextIndex
);
}
}
if
(
expectedNextIndex
!=
C
.
INDEX_UNSET
&&
expectedNextIndex
>=
position
)
{
if
(
expectedNextIndex
!=
C
.
INDEX_UNSET
&&
expectedNextIndex
>=
indexFrom
)
{
expectedNextIndex
--
;
expectedNextIndex
-=
numberOfElementsToRemove
;
}
}
int
newNextIndex
=
newOrder
.
getNextIndex
(
i
<
position
?
i
:
i
-
1
);
int
newNextIndex
=
newOrder
.
getNextIndex
(
i
<
indexFrom
?
i
:
i
-
numberOfElementsToRemove
);
assertThat
(
newNextIndex
).
isEqualTo
(
expectedNextIndex
);
assertThat
(
newNextIndex
).
isEqualTo
(
expectedNextIndex
);
}
}
}
}
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
View file @
6b0e1758
...
@@ -376,7 +376,6 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -376,7 +376,6 @@ public final class DashMediaSource extends BaseMediaSource {
private
int
staleManifestReloadAttempt
;
private
int
staleManifestReloadAttempt
;
private
long
expiredManifestPublishTimeUs
;
private
long
expiredManifestPublishTimeUs
;
private
boolean
dynamicMediaPresentationEnded
;
private
int
firstPeriodId
;
private
int
firstPeriodId
;
...
@@ -679,7 +678,6 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -679,7 +678,6 @@ public final class DashMediaSource extends BaseMediaSource {
elapsedRealtimeOffsetMs
=
0
;
elapsedRealtimeOffsetMs
=
0
;
staleManifestReloadAttempt
=
0
;
staleManifestReloadAttempt
=
0
;
expiredManifestPublishTimeUs
=
C
.
TIME_UNSET
;
expiredManifestPublishTimeUs
=
C
.
TIME_UNSET
;
dynamicMediaPresentationEnded
=
false
;
firstPeriodId
=
0
;
firstPeriodId
=
0
;
periodsById
.
clear
();
periodsById
.
clear
();
}
}
...
@@ -691,10 +689,6 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -691,10 +689,6 @@ public final class DashMediaSource extends BaseMediaSource {
startLoadingManifest
();
startLoadingManifest
();
}
}
/* package */
void
onDashLiveMediaPresentationEndSignalEncountered
()
{
this
.
dynamicMediaPresentationEnded
=
true
;
}
/* package */
void
onDashManifestPublishTimeExpired
(
long
expiredManifestPublishTimeUs
)
{
/* package */
void
onDashManifestPublishTimeExpired
(
long
expiredManifestPublishTimeUs
)
{
if
(
this
.
expiredManifestPublishTimeUs
==
C
.
TIME_UNSET
if
(
this
.
expiredManifestPublishTimeUs
==
C
.
TIME_UNSET
||
this
.
expiredManifestPublishTimeUs
<
expiredManifestPublishTimeUs
)
{
||
this
.
expiredManifestPublishTimeUs
<
expiredManifestPublishTimeUs
)
{
...
@@ -734,9 +728,8 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -734,9 +728,8 @@ public final class DashMediaSource extends BaseMediaSource {
// behind.
// behind.
Log
.
w
(
TAG
,
"Loaded out of sync manifest"
);
Log
.
w
(
TAG
,
"Loaded out of sync manifest"
);
isManifestStale
=
true
;
isManifestStale
=
true
;
}
else
if
(
dynamicMediaPresentationEnded
}
else
if
(
expiredManifestPublishTimeUs
!=
C
.
TIME_UNSET
||
(
expiredManifestPublishTimeUs
!=
C
.
TIME_UNSET
&&
newManifest
.
publishTimeMs
*
1000
<=
expiredManifestPublishTimeUs
)
{
&&
newManifest
.
publishTimeMs
*
1000
<=
expiredManifestPublishTimeUs
))
{
// If we receive a dynamic manifest that's older than expected (i.e. its publish time has
// If we receive a dynamic manifest that's older than expected (i.e. its publish time has
// expired, or it's dynamic and we know the presentation has ended), then this manifest is
// expired, or it's dynamic and we know the presentation has ended), then this manifest is
// stale.
// stale.
...
@@ -745,8 +738,6 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -745,8 +738,6 @@ public final class DashMediaSource extends BaseMediaSource {
"Loaded stale dynamic manifest: "
"Loaded stale dynamic manifest: "
+
newManifest
.
publishTimeMs
+
newManifest
.
publishTimeMs
+
", "
+
", "
+
dynamicMediaPresentationEnded
+
", "
+
expiredManifestPublishTimeUs
);
+
expiredManifestPublishTimeUs
);
isManifestStale
=
true
;
isManifestStale
=
true
;
}
}
...
@@ -763,7 +754,6 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -763,7 +754,6 @@ public final class DashMediaSource extends BaseMediaSource {
staleManifestReloadAttempt
=
0
;
staleManifestReloadAttempt
=
0
;
}
}
manifest
=
newManifest
;
manifest
=
newManifest
;
manifestLoadPending
&=
manifest
.
dynamic
;
manifestLoadPending
&=
manifest
.
dynamic
;
manifestLoadStartTimestampMs
=
elapsedRealtimeMs
-
loadDurationMs
;
manifestLoadStartTimestampMs
=
elapsedRealtimeMs
-
loadDurationMs
;
...
@@ -1170,12 +1160,16 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1170,12 +1160,16 @@ public final class DashMediaSource extends BaseMediaSource {
long
windowDefaultStartPositionUs
=
getAdjustedWindowDefaultStartPositionUs
(
long
windowDefaultStartPositionUs
=
getAdjustedWindowDefaultStartPositionUs
(
defaultPositionProjectionUs
);
defaultPositionProjectionUs
);
Object
tag
=
setTag
?
windowTag
:
null
;
Object
tag
=
setTag
?
windowTag
:
null
;
boolean
isDynamic
=
manifest
.
dynamic
&&
manifest
.
minUpdatePeriodMs
!=
C
.
TIME_UNSET
&&
manifest
.
durationMs
==
C
.
TIME_UNSET
;
return
window
.
set
(
return
window
.
set
(
tag
,
tag
,
presentationStartTimeMs
,
presentationStartTimeMs
,
windowStartTimeMs
,
windowStartTimeMs
,
/* isSeekable= */
true
,
/* isSeekable= */
true
,
manifest
.
d
ynamic
,
isD
ynamic
,
windowDefaultStartPositionUs
,
windowDefaultStartPositionUs
,
windowDurationUs
,
windowDurationUs
,
/* firstPeriodIndex= */
0
,
/* firstPeriodIndex= */
0
,
...
@@ -1253,11 +1247,6 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1253,11 +1247,6 @@ public final class DashMediaSource extends BaseMediaSource {
public
void
onDashManifestPublishTimeExpired
(
long
expiredManifestPublishTimeUs
)
{
public
void
onDashManifestPublishTimeExpired
(
long
expiredManifestPublishTimeUs
)
{
DashMediaSource
.
this
.
onDashManifestPublishTimeExpired
(
expiredManifestPublishTimeUs
);
DashMediaSource
.
this
.
onDashManifestPublishTimeExpired
(
expiredManifestPublishTimeUs
);
}
}
@Override
public
void
onDashLiveMediaPresentationEndSignalEncountered
()
{
DashMediaSource
.
this
.
onDashLiveMediaPresentationEndSignalEncountered
();
}
}
}
private
final
class
ManifestCallback
implements
Loader
.
Callback
<
ParsingLoadable
<
DashManifest
>>
{
private
final
class
ManifestCallback
implements
Loader
.
Callback
<
ParsingLoadable
<
DashManifest
>>
{
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
View file @
6b0e1758
...
@@ -318,9 +318,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -318,9 +318,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
}
}
}
}
long
periodDurationUs
=
representationHolder
.
periodDurationUs
;
boolean
periodEnded
=
periodDurationUs
!=
C
.
TIME_UNSET
;
if
(
representationHolder
.
getSegmentCount
()
==
0
)
{
if
(
representationHolder
.
getSegmentCount
()
==
0
)
{
// The index doesn't define any segments.
// The index doesn't define any segments.
out
.
endOfStream
=
!
manifest
.
dynamic
||
(
periodIndex
<
manifest
.
getPeriodCount
()
-
1
)
;
out
.
endOfStream
=
periodEnded
;
return
;
return
;
}
}
...
@@ -343,17 +346,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
...
@@ -343,17 +346,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
fatalError
=
new
BehindLiveWindowException
();
fatalError
=
new
BehindLiveWindowException
();
return
;
return
;
}
}
if
(
segmentNum
>
lastAvailableSegmentNum
if
(
segmentNum
>
lastAvailableSegmentNum
||
(
missingLastSegment
&&
segmentNum
>=
lastAvailableSegmentNum
))
{
||
(
missingLastSegment
&&
segmentNum
>=
lastAvailableSegmentNum
))
{
// The segment is beyond the end of the period. We know the period will not be extended if the
// The segment is beyond the end of the period.
// manifest is static, or if there's a period after this one.
out
.
endOfStream
=
periodEnded
;
out
.
endOfStream
=
!
manifest
.
dynamic
||
(
periodIndex
<
manifest
.
getPeriodCount
()
-
1
);
return
;
return
;
}
}
long
periodDurationUs
=
representationHolder
.
periodDurationUs
;
if
(
periodEnded
&&
representationHolder
.
getSegmentStartTimeUs
(
segmentNum
)
>=
periodDurationUs
)
{
if
(
periodDurationUs
!=
C
.
TIME_UNSET
&&
representationHolder
.
getSegmentStartTimeUs
(
segmentNum
)
>=
periodDurationUs
)
{
// The period duration clips the period to a position before the segment.
// The period duration clips the period to a position before the segment.
out
.
endOfStream
=
true
;
out
.
endOfStream
=
true
;
return
;
return
;
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/PlayerEmsgHandler.java
View file @
6b0e1758
...
@@ -60,8 +60,7 @@ import java.util.TreeMap;
...
@@ -60,8 +60,7 @@ import java.util.TreeMap;
*/
*/
public
final
class
PlayerEmsgHandler
implements
Handler
.
Callback
{
public
final
class
PlayerEmsgHandler
implements
Handler
.
Callback
{
private
static
final
int
EMSG_MEDIA_PRESENTATION_ENDED
=
1
;
private
static
final
int
EMSG_MANIFEST_EXPIRED
=
1
;
private
static
final
int
EMSG_MANIFEST_EXPIRED
=
2
;
/** Callbacks for player emsg events encountered during DASH live stream. */
/** Callbacks for player emsg events encountered during DASH live stream. */
public
interface
PlayerEmsgCallback
{
public
interface
PlayerEmsgCallback
{
...
@@ -75,9 +74,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -75,9 +74,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
* @param expiredManifestPublishTimeUs The manifest publish time that has been expired.
* @param expiredManifestPublishTimeUs The manifest publish time that has been expired.
*/
*/
void
onDashManifestPublishTimeExpired
(
long
expiredManifestPublishTimeUs
);
void
onDashManifestPublishTimeExpired
(
long
expiredManifestPublishTimeUs
);
/** Called when a media presentation end signal is encountered during live stream. * */
void
onDashLiveMediaPresentationEndSignalEncountered
();
}
}
private
final
Allocator
allocator
;
private
final
Allocator
allocator
;
...
@@ -88,7 +84,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -88,7 +84,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
private
DashManifest
manifest
;
private
DashManifest
manifest
;
private
boolean
dynamicMediaPresentationEnded
;
private
long
expiredManifestPublishTimeUs
;
private
long
expiredManifestPublishTimeUs
;
private
long
lastLoadedChunkEndTimeUs
;
private
long
lastLoadedChunkEndTimeUs
;
private
long
lastLoadedChunkEndTimeBeforeRefreshUs
;
private
long
lastLoadedChunkEndTimeBeforeRefreshUs
;
...
@@ -134,21 +129,15 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -134,21 +129,15 @@ public final class PlayerEmsgHandler implements Handler.Callback {
return
true
;
return
true
;
}
}
boolean
manifestRefreshNeeded
=
false
;
boolean
manifestRefreshNeeded
=
false
;
if
(
dynamicMediaPresentationEnded
)
{
// Find the smallest publishTime (greater than or equal to the current manifest's publish time)
// The manifest we have is dynamic, but we know a non-dynamic one representing the final state
// that has a corresponding expiry time.
// should be available.
Map
.
Entry
<
Long
,
Long
>
expiredEntry
=
ceilingExpiryEntryForPublishTime
(
manifest
.
publishTimeMs
);
manifestRefreshNeeded
=
true
;
if
(
expiredEntry
!=
null
)
{
}
else
{
long
expiredPointUs
=
expiredEntry
.
getValue
();
// Find the smallest publishTime (greater than or equal to the current manifest's publish
if
(
expiredPointUs
<
presentationPositionUs
)
{
// time) that has a corresponding expiry time.
expiredManifestPublishTimeUs
=
expiredEntry
.
getKey
();
Map
.
Entry
<
Long
,
Long
>
expiredEntry
=
ceilingExpiryEntryForPublishTime
(
manifest
.
publishTimeMs
);
notifyManifestPublishTimeExpired
();
if
(
expiredEntry
!=
null
)
{
manifestRefreshNeeded
=
true
;
long
expiredPointUs
=
expiredEntry
.
getValue
();
if
(
expiredPointUs
<
presentationPositionUs
)
{
expiredManifestPublishTimeUs
=
expiredEntry
.
getKey
();
notifyManifestPublishTimeExpired
();
manifestRefreshNeeded
=
true
;
}
}
}
}
}
if
(
manifestRefreshNeeded
)
{
if
(
manifestRefreshNeeded
)
{
...
@@ -221,9 +210,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -221,9 +210,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
return
true
;
return
true
;
}
}
switch
(
message
.
what
)
{
switch
(
message
.
what
)
{
case
(
EMSG_MEDIA_PRESENTATION_ENDED
):
handleMediaPresentationEndedMessageEncountered
();
return
true
;
case
(
EMSG_MANIFEST_EXPIRED
):
case
(
EMSG_MANIFEST_EXPIRED
):
ManifestExpiryEventInfo
messageObj
=
(
ManifestExpiryEventInfo
)
message
.
obj
;
ManifestExpiryEventInfo
messageObj
=
(
ManifestExpiryEventInfo
)
message
.
obj
;
handleManifestExpiredMessage
(
handleManifestExpiredMessage
(
...
@@ -248,11 +234,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -248,11 +234,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
}
}
}
}
private
void
handleMediaPresentationEndedMessageEncountered
()
{
dynamicMediaPresentationEnded
=
true
;
notifySourceMediaPresentationEnded
();
}
private
@Nullable
Map
.
Entry
<
Long
,
Long
>
ceilingExpiryEntryForPublishTime
(
long
publishTimeMs
)
{
private
@Nullable
Map
.
Entry
<
Long
,
Long
>
ceilingExpiryEntryForPublishTime
(
long
publishTimeMs
)
{
return
manifestPublishTimeToExpiryTimeUs
.
ceilingEntry
(
publishTimeMs
);
return
manifestPublishTimeToExpiryTimeUs
.
ceilingEntry
(
publishTimeMs
);
}
}
...
@@ -273,10 +254,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -273,10 +254,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
playerEmsgCallback
.
onDashManifestPublishTimeExpired
(
expiredManifestPublishTimeUs
);
playerEmsgCallback
.
onDashManifestPublishTimeExpired
(
expiredManifestPublishTimeUs
);
}
}
private
void
notifySourceMediaPresentationEnded
()
{
playerEmsgCallback
.
onDashLiveMediaPresentationEndSignalEncountered
();
}
/** Requests DASH media manifest to be refreshed if necessary. */
/** Requests DASH media manifest to be refreshed if necessary. */
private
void
maybeNotifyDashManifestRefreshNeeded
()
{
private
void
maybeNotifyDashManifestRefreshNeeded
()
{
if
(
lastLoadedChunkEndTimeBeforeRefreshUs
!=
C
.
TIME_UNSET
if
(
lastLoadedChunkEndTimeBeforeRefreshUs
!=
C
.
TIME_UNSET
...
@@ -298,12 +275,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -298,12 +275,6 @@ public final class PlayerEmsgHandler implements Handler.Callback {
}
}
}
}
private
static
boolean
isMessageSignalingMediaPresentationEnded
(
EventMessage
eventMessage
)
{
// According to section 4.5.2.1 DASH-IF IOP, if both presentation time delta and event duration
// are zero, the media presentation is ended.
return
eventMessage
.
presentationTimeUs
==
0
&&
eventMessage
.
durationMs
==
0
;
}
/** Handles emsg messages for a specific track for the player. */
/** Handles emsg messages for a specific track for the player. */
public
final
class
PlayerTrackEmsgHandler
implements
TrackOutput
{
public
final
class
PlayerTrackEmsgHandler
implements
TrackOutput
{
...
@@ -413,16 +384,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
...
@@ -413,16 +384,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
if
(
manifestPublishTimeMsInEmsg
==
C
.
TIME_UNSET
)
{
if
(
manifestPublishTimeMsInEmsg
==
C
.
TIME_UNSET
)
{
return
;
return
;
}
}
onManifestExpiredMessageEncountered
(
eventTimeUs
,
manifestPublishTimeMsInEmsg
);
if
(
isMessageSignalingMediaPresentationEnded
(
eventMessage
))
{
onMediaPresentationEndedMessageEncountered
();
}
else
{
onManifestExpiredMessageEncountered
(
eventTimeUs
,
manifestPublishTimeMsInEmsg
);
}
}
private
void
onMediaPresentationEndedMessageEncountered
()
{
handler
.
sendMessage
(
handler
.
obtainMessage
(
EMSG_MEDIA_PRESENTATION_ENDED
));
}
}
private
void
onManifestExpiredMessageEncountered
(
private
void
onManifestExpiredMessageEncountered
(
...
...
library/dash/src/main/proguard-rules.txt
deleted
100644 → 0
View file @
b5beb326
# Proguard rules specific to the dash module.
# Constructors accessed via reflection in SegmentDownloadAction
-dontnote com.google.android.exoplayer2.source.dash.offline.DashDownloadAction
-keepclassmembers class com.google.android.exoplayer2.source.dash.offline.DashDownloadAction {
static ** DESERIALIZER;
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java
View file @
6b0e1758
...
@@ -262,7 +262,8 @@ import java.util.List;
...
@@ -262,7 +262,8 @@ import java.util.List;
// Retry when playlist is refreshed.
// Retry when playlist is refreshed.
return
;
return
;
}
}
HlsMediaPlaylist
mediaPlaylist
=
playlistTracker
.
getPlaylistSnapshot
(
selectedUrl
);
HlsMediaPlaylist
mediaPlaylist
=
playlistTracker
.
getPlaylistSnapshot
(
selectedUrl
,
/* isForPlayback= */
true
);
independentSegments
=
mediaPlaylist
.
hasIndependentSegments
;
independentSegments
=
mediaPlaylist
.
hasIndependentSegments
;
updateLiveEdgeTimeUs
(
mediaPlaylist
);
updateLiveEdgeTimeUs
(
mediaPlaylist
);
...
@@ -279,7 +280,7 @@ import java.util.List;
...
@@ -279,7 +280,7 @@ import java.util.List;
// behind the live window.
// behind the live window.
selectedVariantIndex
=
oldVariantIndex
;
selectedVariantIndex
=
oldVariantIndex
;
selectedUrl
=
variants
[
selectedVariantIndex
];
selectedUrl
=
variants
[
selectedVariantIndex
];
mediaPlaylist
=
playlistTracker
.
getPlaylistSnapshot
(
selectedUrl
);
mediaPlaylist
=
playlistTracker
.
getPlaylistSnapshot
(
selectedUrl
,
/* isForPlayback= */
true
);
startOfPlaylistInPeriodUs
=
startOfPlaylistInPeriodUs
=
mediaPlaylist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
mediaPlaylist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
chunkMediaSequence
=
previous
.
getNextChunkIndex
();
chunkMediaSequence
=
previous
.
getNextChunkIndex
();
...
@@ -435,7 +436,8 @@ import java.util.List;
...
@@ -435,7 +436,8 @@ import java.util.List;
chunkIterators
[
i
]
=
MediaChunkIterator
.
EMPTY
;
chunkIterators
[
i
]
=
MediaChunkIterator
.
EMPTY
;
continue
;
continue
;
}
}
HlsMediaPlaylist
playlist
=
playlistTracker
.
getPlaylistSnapshot
(
variantUrl
);
HlsMediaPlaylist
playlist
=
playlistTracker
.
getPlaylistSnapshot
(
variantUrl
,
/* isForPlayback= */
false
);
long
startOfPlaylistInPeriodUs
=
long
startOfPlaylistInPeriodUs
=
playlist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
playlist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
boolean
switchingVariant
=
variantIndex
!=
oldVariantIndex
;
boolean
switchingVariant
=
variantIndex
!=
oldVariantIndex
;
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java
View file @
6b0e1758
...
@@ -32,6 +32,7 @@ import com.google.android.exoplayer2.upstream.DataSpec;
...
@@ -32,6 +32,7 @@ import com.google.android.exoplayer2.upstream.DataSpec;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.ParsableByteArray
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.TimestampAdjuster
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.EOFException
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.concurrent.atomic.AtomicInteger
;
...
@@ -41,8 +42,7 @@ import java.util.concurrent.atomic.AtomicInteger;
...
@@ -41,8 +42,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
*/
/* package */
final
class
HlsMediaChunk
extends
MediaChunk
{
/* package */
final
class
HlsMediaChunk
extends
MediaChunk
{
public
static
final
String
PRIV_TIMESTAMP_FRAME_OWNER
=
private
static
final
String
PRIV_TIMESTAMP_FRAME_OWNER
=
"com.apple.streaming.transportStreamTimestamp"
;
"com.apple.streaming.transportStreamTimestamp"
;
private
static
final
AtomicInteger
uidSource
=
new
AtomicInteger
();
private
static
final
AtomicInteger
uidSource
=
new
AtomicInteger
();
...
@@ -313,8 +313,10 @@ import java.util.concurrent.atomic.AtomicInteger;
...
@@ -313,8 +313,10 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
*/
private
long
peekId3PrivTimestamp
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
private
long
peekId3PrivTimestamp
(
ExtractorInput
input
)
throws
IOException
,
InterruptedException
{
input
.
resetPeekPosition
();
input
.
resetPeekPosition
();
if
(
input
.
getLength
()
<
Id3Decoder
.
ID3_HEADER_LENGTH
try
{
||
!
input
.
peekFully
(
id3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
,
true
))
{
input
.
peekFully
(
id3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
}
catch
(
EOFException
e
)
{
// The input isn't long enough for there to be any ID3 data.
return
C
.
TIME_UNSET
;
return
C
.
TIME_UNSET
;
}
}
id3Data
.
reset
(
Id3Decoder
.
ID3_HEADER_LENGTH
);
id3Data
.
reset
(
Id3Decoder
.
ID3_HEADER_LENGTH
);
...
@@ -330,9 +332,7 @@ import java.util.concurrent.atomic.AtomicInteger;
...
@@ -330,9 +332,7 @@ import java.util.concurrent.atomic.AtomicInteger;
id3Data
.
reset
(
requiredCapacity
);
id3Data
.
reset
(
requiredCapacity
);
System
.
arraycopy
(
data
,
0
,
id3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
System
.
arraycopy
(
data
,
0
,
id3Data
.
data
,
0
,
Id3Decoder
.
ID3_HEADER_LENGTH
);
}
}
if
(!
input
.
peekFully
(
id3Data
.
data
,
Id3Decoder
.
ID3_HEADER_LENGTH
,
id3Size
,
true
))
{
input
.
peekFully
(
id3Data
.
data
,
Id3Decoder
.
ID3_HEADER_LENGTH
,
id3Size
);
return
C
.
TIME_UNSET
;
}
Metadata
metadata
=
id3Decoder
.
decode
(
id3Data
.
data
,
id3Size
);
Metadata
metadata
=
id3Decoder
.
decode
(
id3Data
.
data
,
id3Size
);
if
(
metadata
==
null
)
{
if
(
metadata
==
null
)
{
return
C
.
TIME_UNSET
;
return
C
.
TIME_UNSET
;
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java
View file @
6b0e1758
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
;
import
android.os.Handler
;
import
android.os.Handler
;
import
android.support.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.FormatHolder
;
import
com.google.android.exoplayer2.FormatHolder
;
...
@@ -24,6 +25,8 @@ import com.google.android.exoplayer2.extractor.DummyTrackOutput;
...
@@ -24,6 +25,8 @@ import com.google.android.exoplayer2.extractor.DummyTrackOutput;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.ExtractorOutput
;
import
com.google.android.exoplayer2.extractor.SeekMap
;
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.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.id3.PrivFrame
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher
;
import
com.google.android.exoplayer2.source.SampleQueue
;
import
com.google.android.exoplayer2.source.SampleQueue
;
import
com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener
;
import
com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener
;
...
@@ -791,7 +794,7 @@ import java.util.List;
...
@@ -791,7 +794,7 @@ import java.util.List;
return
createDummyTrackOutput
(
id
,
type
);
return
createDummyTrackOutput
(
id
,
type
);
}
}
}
}
SampleQueue
trackOutput
=
new
SampleQueue
(
allocator
);
SampleQueue
trackOutput
=
new
PrivTimestampStripping
SampleQueue
(
allocator
);
trackOutput
.
setSampleOffsetUs
(
sampleOffsetUs
);
trackOutput
.
setSampleOffsetUs
(
sampleOffsetUs
);
trackOutput
.
sourceId
(
chunkUid
);
trackOutput
.
sourceId
(
chunkUid
);
trackOutput
.
setUpstreamFormatChangeListener
(
this
);
trackOutput
.
setUpstreamFormatChangeListener
(
this
);
...
@@ -1126,4 +1129,53 @@ import java.util.List;
...
@@ -1126,4 +1129,53 @@ import java.util.List;
Log
.
w
(
TAG
,
"Unmapped track with id "
+
id
+
" of type "
+
type
);
Log
.
w
(
TAG
,
"Unmapped track with id "
+
id
+
" of type "
+
type
);
return
new
DummyTrackOutput
();
return
new
DummyTrackOutput
();
}
}
private
static
final
class
PrivTimestampStrippingSampleQueue
extends
SampleQueue
{
public
PrivTimestampStrippingSampleQueue
(
Allocator
allocator
)
{
super
(
allocator
);
}
@Override
public
void
format
(
Format
format
)
{
super
.
format
(
format
.
copyWithMetadata
(
getAdjustedMetadata
(
format
.
metadata
)));
}
/**
* Strips the private timestamp frame from metadata, if present. See:
* https://github.com/google/ExoPlayer/issues/5063
*/
@Nullable
private
Metadata
getAdjustedMetadata
(
@Nullable
Metadata
metadata
)
{
if
(
metadata
==
null
)
{
return
null
;
}
int
length
=
metadata
.
length
();
int
transportStreamTimestampMetadataIndex
=
C
.
INDEX_UNSET
;
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
Metadata
.
Entry
metadataEntry
=
metadata
.
get
(
i
);
if
(
metadataEntry
instanceof
PrivFrame
)
{
PrivFrame
privFrame
=
(
PrivFrame
)
metadataEntry
;
if
(
HlsMediaChunk
.
PRIV_TIMESTAMP_FRAME_OWNER
.
equals
(
privFrame
.
owner
))
{
transportStreamTimestampMetadataIndex
=
i
;
break
;
}
}
}
if
(
transportStreamTimestampMetadataIndex
==
C
.
INDEX_UNSET
)
{
return
metadata
;
}
if
(
length
==
1
)
{
return
null
;
}
Metadata
.
Entry
[]
newMetadataEntries
=
new
Metadata
.
Entry
[
length
-
1
];
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
if
(
i
!=
transportStreamTimestampMetadataIndex
)
{
int
newIndex
=
i
<
transportStreamTimestampMetadataIndex
?
i
:
i
-
1
;
newMetadataEntries
[
newIndex
]
=
metadata
.
get
(
i
);
}
}
return
new
Metadata
(
newMetadataEntries
);
}
}
}
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java
View file @
6b0e1758
...
@@ -162,9 +162,9 @@ public final class DefaultHlsPlaylistTracker
...
@@ -162,9 +162,9 @@ public final class DefaultHlsPlaylistTracker
}
}
@Override
@Override
public
HlsMediaPlaylist
getPlaylistSnapshot
(
HlsUrl
url
)
{
public
HlsMediaPlaylist
getPlaylistSnapshot
(
HlsUrl
url
,
boolean
isForPlayback
)
{
HlsMediaPlaylist
snapshot
=
playlistBundles
.
get
(
url
).
getPlaylistSnapshot
();
HlsMediaPlaylist
snapshot
=
playlistBundles
.
get
(
url
).
getPlaylistSnapshot
();
if
(
snapshot
!=
null
)
{
if
(
snapshot
!=
null
&&
isForPlayback
)
{
maybeSetPrimaryUrl
(
url
);
maybeSetPrimaryUrl
(
url
);
}
}
return
snapshot
;
return
snapshot
;
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java
View file @
6b0e1758
...
@@ -167,11 +167,13 @@ public interface HlsPlaylistTracker {
...
@@ -167,11 +167,13 @@ public interface HlsPlaylistTracker {
* HlsUrl}.
* HlsUrl}.
*
*
* @param url The {@link HlsUrl} corresponding to the requested media playlist.
* @param url The {@link HlsUrl} corresponding to the requested media playlist.
* @param isForPlayback Whether the caller might use the snapshot to request media segments for
* playback. If true, the primary playlist may be updated to the one requested.
* @return The most recent snapshot of the playlist referenced by the provided {@link HlsUrl}. May
* @return The most recent snapshot of the playlist referenced by the provided {@link HlsUrl}. May
* be null if no snapshot has been loaded yet.
* be null if no snapshot has been loaded yet.
*/
*/
@Nullable
@Nullable
HlsMediaPlaylist
getPlaylistSnapshot
(
HlsUrl
url
);
HlsMediaPlaylist
getPlaylistSnapshot
(
HlsUrl
url
,
boolean
isForPlayback
);
/**
/**
* Returns the start time of the first loaded primary playlist, or {@link C#TIME_UNSET} if no
* Returns the start time of the first loaded primary playlist, or {@link C#TIME_UNSET} if no
...
...
library/hls/src/main/proguard-rules.txt
deleted
100644 → 0
View file @
b5beb326
# Proguard rules specific to the hls module.
# Constructors accessed via reflection in SegmentDownloadAction
-dontnote com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction
-keepclassmembers class com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction {
static ** DESERIALIZER;
}
library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/manifest/SsManifestParser.java
View file @
6b0e1758
...
@@ -378,8 +378,12 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
...
@@ -378,8 +378,12 @@ public class SsManifestParser implements ParsingLoadable.Parser<SsManifest> {
DrmInitData
drmInitData
=
new
DrmInitData
(
new
SchemeData
(
protectionElement
.
uuid
,
DrmInitData
drmInitData
=
new
DrmInitData
(
new
SchemeData
(
protectionElement
.
uuid
,
MimeTypes
.
VIDEO_MP4
,
protectionElement
.
data
));
MimeTypes
.
VIDEO_MP4
,
protectionElement
.
data
));
for
(
StreamElement
streamElement
:
streamElementArray
)
{
for
(
StreamElement
streamElement
:
streamElementArray
)
{
for
(
int
i
=
0
;
i
<
streamElement
.
formats
.
length
;
i
++)
{
int
type
=
streamElement
.
type
;
streamElement
.
formats
[
i
]
=
streamElement
.
formats
[
i
].
copyWithDrmInitData
(
drmInitData
);
if
(
type
==
C
.
TRACK_TYPE_VIDEO
||
type
==
C
.
TRACK_TYPE_AUDIO
)
{
Format
[]
formats
=
streamElement
.
formats
;
for
(
int
i
=
0
;
i
<
formats
.
length
;
i
++)
{
formats
[
i
]
=
formats
[
i
].
copyWithDrmInitData
(
drmInitData
);
}
}
}
}
}
}
}
...
...
library/smoothstreaming/src/main/proguard-rules.txt
deleted
100644 → 0
View file @
b5beb326
# Proguard rules specific to the smoothstreaming module.
# Constructors accessed via reflection in SegmentDownloadAction
-dontnote com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction
-keepclassmembers class com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction {
static ** DESERIALIZER;
}
library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
View file @
6b0e1758
...
@@ -241,11 +241,7 @@ import java.util.List;
...
@@ -241,11 +241,7 @@ import java.util.List;
*/
*/
public
class
PlayerView
extends
FrameLayout
{
public
class
PlayerView
extends
FrameLayout
{
private
static
final
int
SURFACE_TYPE_NONE
=
0
;
// LINT.IfChange
private
static
final
int
SURFACE_TYPE_SURFACE_VIEW
=
1
;
private
static
final
int
SURFACE_TYPE_TEXTURE_VIEW
=
2
;
private
static
final
int
SURFACE_TYPE_MONO360_VIEW
=
3
;
/**
/**
* Determines when the buffering view is shown. One of {@link #SHOW_BUFFERING_NEVER}, {@link
* Determines when the buffering view is shown. One of {@link #SHOW_BUFFERING_NEVER}, {@link
* #SHOW_BUFFERING_WHEN_PLAYING} or {@link #SHOW_BUFFERING_ALWAYS}.
* #SHOW_BUFFERING_WHEN_PLAYING} or {@link #SHOW_BUFFERING_ALWAYS}.
...
@@ -266,6 +262,14 @@ public class PlayerView extends FrameLayout {
...
@@ -266,6 +262,14 @@ public class PlayerView extends FrameLayout {
* buffering} state.
* buffering} state.
*/
*/
public
static
final
int
SHOW_BUFFERING_ALWAYS
=
2
;
public
static
final
int
SHOW_BUFFERING_ALWAYS
=
2
;
// LINT.ThenChange(../../../../../../res/values/attrs.xml)
// LINT.IfChange
private
static
final
int
SURFACE_TYPE_NONE
=
0
;
private
static
final
int
SURFACE_TYPE_SURFACE_VIEW
=
1
;
private
static
final
int
SURFACE_TYPE_TEXTURE_VIEW
=
2
;
private
static
final
int
SURFACE_TYPE_MONO360_VIEW
=
3
;
// LINT.ThenChange(../../../../../../res/values/attrs.xml)
private
final
AspectRatioFrameLayout
contentFrame
;
private
final
AspectRatioFrameLayout
contentFrame
;
private
final
View
shutterView
;
private
final
View
shutterView
;
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/SphericalSurfaceView.java
View file @
6b0e1758
...
@@ -104,12 +104,18 @@ public final class SphericalSurfaceView extends GLSurfaceView {
...
@@ -104,12 +104,18 @@ public final class SphericalSurfaceView extends GLSurfaceView {
// Configure sensors and touch.
// Configure sensors and touch.
sensorManager
=
sensorManager
=
(
SensorManager
)
Assertions
.
checkNotNull
(
context
.
getSystemService
(
Context
.
SENSOR_SERVICE
));
(
SensorManager
)
Assertions
.
checkNotNull
(
context
.
getSystemService
(
Context
.
SENSOR_SERVICE
));
// TYPE_GAME_ROTATION_VECTOR is the easiest sensor since it handles all the complex math for
Sensor
orientationSensor
=
null
;
// fusion. It's used instead of TYPE_ROTATION_VECTOR since the latter uses the magnetometer on
if
(
Util
.
SDK_INT
>=
18
)
{
// devices. When used indoors, the magnetometer can take some time to settle depending on the
// TYPE_GAME_ROTATION_VECTOR is the easiest sensor since it handles all the complex math for
// device and amount of metal in the environment.
// fusion. It's used instead of TYPE_ROTATION_VECTOR since the latter uses the magnetometer on
int
type
=
Util
.
SDK_INT
>=
18
?
Sensor
.
TYPE_GAME_ROTATION_VECTOR
:
Sensor
.
TYPE_ROTATION_VECTOR
;
// devices. When used indoors, the magnetometer can take some time to settle depending on the
orientationSensor
=
sensorManager
.
getDefaultSensor
(
type
);
// device and amount of metal in the environment.
orientationSensor
=
sensorManager
.
getDefaultSensor
(
Sensor
.
TYPE_GAME_ROTATION_VECTOR
);
}
if
(
orientationSensor
==
null
)
{
orientationSensor
=
sensorManager
.
getDefaultSensor
(
Sensor
.
TYPE_ROTATION_VECTOR
);
}
this
.
orientationSensor
=
orientationSensor
;
scene
=
new
SceneRenderer
();
scene
=
new
SceneRenderer
();
renderer
=
new
Renderer
(
scene
);
renderer
=
new
Renderer
(
scene
);
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/spherical/TouchTracker.java
View file @
6b0e1758
...
@@ -44,11 +44,10 @@ import android.view.View;
...
@@ -44,11 +44,10 @@ import android.view.View;
* a nicer UI. An even more advanced UI would reproject the user's touch point into 3D and drag the
* a nicer UI. An even more advanced UI would reproject the user's touch point into 3D and drag the
* Mesh as the user moves their finger. However, that requires quaternion interpolation.
* Mesh as the user moves their finger. However, that requires quaternion interpolation.
*/
*/
// @VisibleForTesting
/* package */
class
TouchTracker
extends
GestureDetector
.
SimpleOnGestureListener
/*package*/
class
TouchTracker
extends
GestureDetector
.
SimpleOnGestureListener
implements
View
.
OnTouchListener
{
implements
View
.
OnTouchListener
{
/*
package
*/
interface
Listener
{
/*
package
*/
interface
Listener
{
void
onScrollChange
(
PointF
scrollOffsetDegrees
);
void
onScrollChange
(
PointF
scrollOffsetDegrees
);
}
}
...
...
library/ui/src/main/res/values/attrs.xml
View file @
6b0e1758
...
@@ -53,8 +53,8 @@
...
@@ -53,8 +53,8 @@
<attr
name=
"auto_show"
format=
"boolean"
/>
<attr
name=
"auto_show"
format=
"boolean"
/>
<attr
name=
"show_buffering"
format=
"enum"
>
<attr
name=
"show_buffering"
format=
"enum"
>
<enum
name=
"never"
value=
"0"
/>
<enum
name=
"never"
value=
"0"
/>
<enum
name=
"
always
"
value=
"1"
/>
<enum
name=
"
when_playing
"
value=
"1"
/>
<enum
name=
"
when_playing
"
value=
"2"
/>
<enum
name=
"
always
"
value=
"2"
/>
</attr>
</attr>
<attr
name=
"keep_content_on_player_reset"
format=
"boolean"
/>
<attr
name=
"keep_content_on_player_reset"
format=
"boolean"
/>
<attr
name=
"resize_mode"
/>
<attr
name=
"resize_mode"
/>
...
...
testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeShuffleOrder.java
View file @
6b0e1758
...
@@ -61,8 +61,8 @@ public final class FakeShuffleOrder implements ShuffleOrder {
...
@@ -61,8 +61,8 @@ public final class FakeShuffleOrder implements ShuffleOrder {
}
}
@Override
@Override
public
ShuffleOrder
cloneAndRemove
(
int
removalIndex
)
{
public
ShuffleOrder
cloneAndRemove
(
int
indexFrom
,
int
indexToExclusive
)
{
return
new
FakeShuffleOrder
(
length
-
1
);
return
new
FakeShuffleOrder
(
length
-
indexToExclusive
+
indexFrom
);
}
}
@Override
@Override
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment