Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
NotesChapter
ExoPlayer
提交
4b1e0fa9
E
ExoPlayer
项目概览
NotesChapter
/
ExoPlayer
与 Fork 源项目一致
从无法访问的项目Fork
通知
6
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
ExoPlayer
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
4b1e0fa9
编写于
2月 13, 2021
作者:
O
Oliver Woodman
提交者:
GitHub
2月 13, 2021
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #8582 from google/dev-v2-r2.13.1
r2.13.1
上级
b1000940
5807d2e0
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
327 addition
and
122 deletion
+327
-122
RELEASENOTES.md
RELEASENOTES.md
+28
-0
constants.gradle
constants.gradle
+2
-2
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java
...va/com/google/android/exoplayer2/ext/ima/AdTagLoader.java
+12
-1
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java
...a/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java
+10
-0
library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
...a/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
+3
-3
library/common/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java
...google/android/exoplayer2/source/ads/AdPlaybackState.java
+3
-2
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
.../com/google/android/exoplayer2/ExoPlayerImplInternal.java
+6
-9
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
...com/google/android/exoplayer2/audio/DefaultAudioSink.java
+30
-12
library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java
...ogle/android/exoplayer2/drm/DefaultDrmSessionManager.java
+8
-6
library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManagerProvider.java
...roid/exoplayer2/drm/DefaultDrmSessionManagerProvider.java
+29
-2
library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java
.../google/android/exoplayer2/source/ads/AdsMediaSource.java
+22
-2
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
...est/java/com/google/android/exoplayer2/ExoPlayerTest.java
+38
-0
library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioSinkTest.java
...google/android/exoplayer2/audio/DefaultAudioSinkTest.java
+14
-0
library/core/src/test/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManagerTest.java
.../android/exoplayer2/drm/DefaultDrmSessionManagerTest.java
+26
-0
library/core/src/test/java/com/google/android/exoplayer2/source/DefaultDrmSessionManagerProviderTest.java
...oplayer2/source/DefaultDrmSessionManagerProviderTest.java
+35
-0
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
...oogle/android/exoplayer2/source/dash/DashMediaSource.java
+59
-79
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Period.java
...oogle/android/exoplayer2/source/dash/manifest/Period.java
+1
-3
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SpeedProvider.java
.../google/android/exoplayer2/transformer/SpeedProvider.java
+1
-1
未找到文件。
RELEASENOTES.md
浏览文件 @
4b1e0fa9
# Release notes
# Release notes
### 2.13.1 (2021-02-12)
*
Live streaming:
*
Fix playback issue for HLS live streams without program date time
information (
[
#8560
](
https://github.com/google/ExoPlayer/issues/8560
)
).
*
Fix playback issue for multi-period DASH live streams
(
[
#8537
](
https://github.com/google/ExoPlayer/issues/8537
)
).
*
Fix playback failures when playing live streams with video tunneling
enabled (
[
#8570
](
https://github.com/google/ExoPlayer/issues/8570
)
).
*
IMA extension:
*
Fix handling of repeated ad loads, to avoid ads being discarded if the
user seeks away and then back to a preloaded postroll (for example).
*
Fix a bug where an assertion would fail if the player started to buffer
an ad media period before the ad URI was known then an ad state update
arrived that didn't set the ad URI.
*
Add
`ImaAdsLoader.focusSkipButton`
to allow apps to request that the
skip button should receive UI focus, if shown
(
[
#8565
](
https://github.com/google/ExoPlayer/issues/8565
)
).
*
DRM:
*
Re-use the previous
`DrmSessionManager`
instance when playing a playlist
(if possible)
(
[
#8523
](
https://github.com/google/ExoPlayer/issues/8523
)
).
*
Propagate DRM configuration when creating media sources for ad content
(
[
#8568
](
https://github.com/google/ExoPlayer/issues/8568
)
).
*
Only release 'keepalive' references to
`DrmSession`
in
`DefaultDrmSessionManager#release()`
if keepalive is enabled
(
[
#8576
](
https://github.com/google/ExoPlayer/issues/8576
)
).
### 2.13.0 (2021-02-04)
### 2.13.0 (2021-02-04)
*
Core library:
*
Core library:
...
...
constants.gradle
浏览文件 @
4b1e0fa9
...
@@ -13,8 +13,8 @@
...
@@ -13,8 +13,8 @@
// limitations under the License.
// limitations under the License.
project
.
ext
{
project
.
ext
{
// ExoPlayer version and version code.
// ExoPlayer version and version code.
releaseVersion
=
'2.13.
0
'
releaseVersion
=
'2.13.
1
'
releaseVersionCode
=
201300
0
releaseVersionCode
=
201300
1
minSdkVersion
=
16
minSdkVersion
=
16
appTargetSdkVersion
=
29
appTargetSdkVersion
=
29
targetSdkVersion
=
28
// TODO: Bump once b/143232359 is resolved. Also fix TODOs in UtilTest.
targetSdkVersion
=
28
// TODO: Bump once b/143232359 is resolved. Also fix TODOs in UtilTest.
...
...
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java
浏览文件 @
4b1e0fa9
...
@@ -281,6 +281,16 @@ import java.util.Map;
...
@@ -281,6 +281,16 @@ import java.util.Map;
}
}
}
}
/**
* Moves UI focus to the skip button (or other interactive elements), if currently shown. See
* {@link AdsManager#focus()}.
*/
public
void
focusSkipButton
()
{
if
(
adsManager
!=
null
)
{
adsManager
.
focus
();
}
}
/**
/**
* Starts passing events from this instance (including any pending ad playback state) and
* Starts passing events from this instance (including any pending ad playback state) and
* registers obstructions.
* registers obstructions.
...
@@ -879,7 +889,8 @@ import java.util.Map;
...
@@ -879,7 +889,8 @@ import java.util.Map;
int
adGroupIndex
=
getAdGroupIndexForAdPod
(
adPodInfo
);
int
adGroupIndex
=
getAdGroupIndexForAdPod
(
adPodInfo
);
int
adIndexInAdGroup
=
adPodInfo
.
getAdPosition
()
-
1
;
int
adIndexInAdGroup
=
adPodInfo
.
getAdPosition
()
-
1
;
AdInfo
adInfo
=
new
AdInfo
(
adGroupIndex
,
adIndexInAdGroup
);
AdInfo
adInfo
=
new
AdInfo
(
adGroupIndex
,
adIndexInAdGroup
);
adInfoByAdMediaInfo
.
put
(
adMediaInfo
,
adInfo
);
// The ad URI may already be known, so force put to update it if needed.
adInfoByAdMediaInfo
.
forcePut
(
adMediaInfo
,
adInfo
);
if
(
configuration
.
debugModeEnabled
)
{
if
(
configuration
.
debugModeEnabled
)
{
Log
.
d
(
TAG
,
"loadAd "
+
getAdMediaInfoString
(
adMediaInfo
));
Log
.
d
(
TAG
,
"loadAd "
+
getAdMediaInfoString
(
adMediaInfo
));
}
}
...
...
extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java
浏览文件 @
4b1e0fa9
...
@@ -473,6 +473,16 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
...
@@ -473,6 +473,16 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
}
}
}
}
/**
* Moves UI focus to the skip button (or other interactive elements), if currently shown. See
* {@link AdsManager#focus()}.
*/
public
void
focusSkipButton
()
{
if
(
currentAdTagLoader
!=
null
)
{
currentAdTagLoader
.
focusSkipButton
();
}
}
// AdsLoader implementation.
// AdsLoader implementation.
@Override
@Override
...
...
library/common/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java
浏览文件 @
4b1e0fa9
...
@@ -30,11 +30,11 @@ public final class ExoPlayerLibraryInfo {
...
@@ -30,11 +30,11 @@ public final class ExoPlayerLibraryInfo {
/** The version of the library expressed as a string, for example "1.2.3". */
/** The version of the library expressed as a string, for example "1.2.3". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public
static
final
String
VERSION
=
"2.13.
0
"
;
public
static
final
String
VERSION
=
"2.13.
1
"
;
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
/** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.13.
0
"
;
public
static
final
String
VERSION_SLASHY
=
"ExoPlayerLib/2.13.
1
"
;
/**
/**
* The version of the library expressed as an integer, for example 1002003.
* The version of the library expressed as an integer, for example 1002003.
...
@@ -44,7 +44,7 @@ public final class ExoPlayerLibraryInfo {
...
@@ -44,7 +44,7 @@ public final class ExoPlayerLibraryInfo {
* integer version 123045006 (123-045-006).
* integer version 123045006 (123-045-006).
*/
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public
static
final
int
VERSION_INT
=
201300
0
;
public
static
final
int
VERSION_INT
=
201300
1
;
/**
/**
* The default user agent for requests made by the library.
* The default user agent for requests made by the library.
...
...
library/common/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java
浏览文件 @
4b1e0fa9
...
@@ -182,9 +182,10 @@ public final class AdPlaybackState {
...
@@ -182,9 +182,10 @@ public final class AdPlaybackState {
/** Returns a new instance with the specified ad durations, in microseconds. */
/** Returns a new instance with the specified ad durations, in microseconds. */
@CheckResult
@CheckResult
public
AdGroup
withAdDurationsUs
(
long
[]
durationsUs
)
{
public
AdGroup
withAdDurationsUs
(
long
[]
durationsUs
)
{
Assertions
.
checkArgument
(
count
==
C
.
LENGTH_UNSET
||
durationsUs
.
length
<=
this
.
uris
.
length
);
if
(
durationsUs
.
length
<
uris
.
length
)
{
if
(
durationsUs
.
length
<
this
.
uris
.
length
)
{
durationsUs
=
copyDurationsUsWithSpaceForAdCount
(
durationsUs
,
uris
.
length
);
durationsUs
=
copyDurationsUsWithSpaceForAdCount
(
durationsUs
,
uris
.
length
);
}
else
if
(
count
!=
C
.
LENGTH_UNSET
&&
durationsUs
.
length
>
uris
.
length
)
{
durationsUs
=
Arrays
.
copyOf
(
durationsUs
,
uris
.
length
);
}
}
return
new
AdGroup
(
count
,
states
,
uris
,
durationsUs
);
return
new
AdGroup
(
count
,
states
,
uris
,
durationsUs
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
浏览文件 @
4b1e0fa9
...
@@ -880,7 +880,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
...
@@ -880,7 +880,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
// Adjust live playback speed to new position.
// Adjust live playback speed to new position.
if
(
playbackInfo
.
playWhenReady
if
(
playbackInfo
.
playWhenReady
&&
playbackInfo
.
playbackState
==
Player
.
STATE_READY
&&
playbackInfo
.
playbackState
==
Player
.
STATE_READY
&&
isCurrentPeriodInMovingLiveWindow
(
)
&&
shouldUseLivePlaybackSpeedControl
(
playbackInfo
.
timeline
,
playbackInfo
.
periodId
)
&&
playbackInfo
.
playbackParameters
.
speed
==
1
f
)
{
&&
playbackInfo
.
playbackParameters
.
speed
==
1
f
)
{
float
adjustedSpeed
=
float
adjustedSpeed
=
livePlaybackSpeedControl
.
getAdjustedPlaybackSpeed
(
livePlaybackSpeedControl
.
getAdjustedPlaybackSpeed
(
...
@@ -1051,17 +1051,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
...
@@ -1051,17 +1051,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
-
(
periodPositionUs
+
period
.
getPositionInWindowUs
());
-
(
periodPositionUs
+
period
.
getPositionInWindowUs
());
}
}
private
boolean
isCurrentPeriodInMovingLiveWindow
()
{
private
boolean
shouldUseLivePlaybackSpeedControl
(
return
isInMovingLiveWindow
(
playbackInfo
.
timeline
,
playbackInfo
.
periodId
);
Timeline
timeline
,
MediaPeriodId
mediaPeriodId
)
{
}
private
boolean
isInMovingLiveWindow
(
Timeline
timeline
,
MediaPeriodId
mediaPeriodId
)
{
if
(
mediaPeriodId
.
isAd
()
||
timeline
.
isEmpty
())
{
if
(
mediaPeriodId
.
isAd
()
||
timeline
.
isEmpty
())
{
return
false
;
return
false
;
}
}
int
windowIndex
=
timeline
.
getPeriodByUid
(
mediaPeriodId
.
periodUid
,
period
).
windowIndex
;
int
windowIndex
=
timeline
.
getPeriodByUid
(
mediaPeriodId
.
periodUid
,
period
).
windowIndex
;
timeline
.
getWindow
(
windowIndex
,
window
);
timeline
.
getWindow
(
windowIndex
,
window
);
return
window
.
isLive
()
&&
window
.
isDynamic
;
return
window
.
isLive
()
&&
window
.
isDynamic
&&
window
.
windowStartTimeMs
!=
C
.
TIME_UNSET
;
}
}
private
void
scheduleNextWork
(
long
thisOperationStartTimeMs
,
long
intervalMs
)
{
private
void
scheduleNextWork
(
long
thisOperationStartTimeMs
,
long
intervalMs
)
{
...
@@ -1725,7 +1722,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
...
@@ -1725,7 +1722,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
// Renderers are ready and we're loading. Ask the LoadControl whether to transition.
long
targetLiveOffsetUs
=
long
targetLiveOffsetUs
=
isInMovingLiveWindow
(
playbackInfo
.
timeline
,
queue
.
getPlayingPeriod
().
info
.
id
)
shouldUseLivePlaybackSpeedControl
(
playbackInfo
.
timeline
,
queue
.
getPlayingPeriod
().
info
.
id
)
?
livePlaybackSpeedControl
.
getTargetLiveOffsetUs
()
?
livePlaybackSpeedControl
.
getTargetLiveOffsetUs
()
:
C
.
TIME_UNSET
;
:
C
.
TIME_UNSET
;
MediaPeriodHolder
loadingHolder
=
queue
.
getLoadingPeriod
();
MediaPeriodHolder
loadingHolder
=
queue
.
getLoadingPeriod
();
...
@@ -1831,7 +1828,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
...
@@ -1831,7 +1828,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
Timeline
oldTimeline
,
Timeline
oldTimeline
,
MediaPeriodId
oldPeriodId
,
MediaPeriodId
oldPeriodId
,
long
positionForTargetOffsetOverrideUs
)
{
long
positionForTargetOffsetOverrideUs
)
{
if
(
newTimeline
.
isEmpty
()
||
!
isInMovingLiveWindow
(
newTimeline
,
newPeriodId
))
{
if
(
newTimeline
.
isEmpty
()
||
!
shouldUseLivePlaybackSpeedControl
(
newTimeline
,
newPeriodId
))
{
// Live playback speed control is unused.
// Live playback speed control is unused.
return
;
return
;
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
浏览文件 @
4b1e0fa9
...
@@ -488,7 +488,6 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -488,7 +488,6 @@ public final class DefaultAudioSink implements AudioSink {
throws
ConfigurationException
{
throws
ConfigurationException
{
int
inputPcmFrameSize
;
int
inputPcmFrameSize
;
@Nullable
AudioProcessor
[]
availableAudioProcessors
;
@Nullable
AudioProcessor
[]
availableAudioProcessors
;
boolean
canApplyPlaybackParameters
;
@OutputMode
int
outputMode
;
@OutputMode
int
outputMode
;
@C
.
Encoding
int
outputEncoding
;
@C
.
Encoding
int
outputEncoding
;
...
@@ -500,11 +499,10 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -500,11 +499,10 @@ public final class DefaultAudioSink implements AudioSink {
Assertions
.
checkArgument
(
Util
.
isEncodingLinearPcm
(
inputFormat
.
pcmEncoding
));
Assertions
.
checkArgument
(
Util
.
isEncodingLinearPcm
(
inputFormat
.
pcmEncoding
));
inputPcmFrameSize
=
Util
.
getPcmFrameSize
(
inputFormat
.
pcmEncoding
,
inputFormat
.
channelCount
);
inputPcmFrameSize
=
Util
.
getPcmFrameSize
(
inputFormat
.
pcmEncoding
,
inputFormat
.
channelCount
);
boolean
useFloatOutput
=
enableFloatOutput
&&
Util
.
isEncodingHighResolutionPcm
(
inputFormat
.
pcmEncoding
);
availableAudioProcessors
=
availableAudioProcessors
=
useFloatOutput
?
toFloatPcmAvailableAudioProcessors
:
toIntPcmAvailableAudioProcessors
;
shouldUseFloatOutput
(
inputFormat
.
pcmEncoding
)
canApplyPlaybackParameters
=
!
useFloatOutput
;
?
toFloatPcmAvailableAudioProcessors
:
toIntPcmAvailableAudioProcessors
;
trimmingAudioProcessor
.
setTrimFrameCount
(
trimmingAudioProcessor
.
setTrimFrameCount
(
inputFormat
.
encoderDelay
,
inputFormat
.
encoderPadding
);
inputFormat
.
encoderDelay
,
inputFormat
.
encoderPadding
);
...
@@ -541,7 +539,6 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -541,7 +539,6 @@ public final class DefaultAudioSink implements AudioSink {
}
else
{
}
else
{
inputPcmFrameSize
=
C
.
LENGTH_UNSET
;
inputPcmFrameSize
=
C
.
LENGTH_UNSET
;
availableAudioProcessors
=
new
AudioProcessor
[
0
];
availableAudioProcessors
=
new
AudioProcessor
[
0
];
canApplyPlaybackParameters
=
false
;
outputSampleRate
=
inputFormat
.
sampleRate
;
outputSampleRate
=
inputFormat
.
sampleRate
;
outputPcmFrameSize
=
C
.
LENGTH_UNSET
;
outputPcmFrameSize
=
C
.
LENGTH_UNSET
;
if
(
enableOffload
&&
isOffloadedPlaybackSupported
(
inputFormat
,
audioAttributes
))
{
if
(
enableOffload
&&
isOffloadedPlaybackSupported
(
inputFormat
,
audioAttributes
))
{
...
@@ -586,7 +583,6 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -586,7 +583,6 @@ public final class DefaultAudioSink implements AudioSink {
outputEncoding
,
outputEncoding
,
specifiedBufferSize
,
specifiedBufferSize
,
enableAudioTrackPlaybackParams
,
enableAudioTrackPlaybackParams
,
canApplyPlaybackParameters
,
availableAudioProcessors
);
availableAudioProcessors
);
if
(
isAudioTrackInitialized
())
{
if
(
isAudioTrackInitialized
())
{
this
.
pendingConfiguration
=
pendingConfiguration
;
this
.
pendingConfiguration
=
pendingConfiguration
;
...
@@ -1336,11 +1332,11 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -1336,11 +1332,11 @@ public final class DefaultAudioSink implements AudioSink {
private
void
applyAudioProcessorPlaybackParametersAndSkipSilence
(
long
presentationTimeUs
)
{
private
void
applyAudioProcessorPlaybackParametersAndSkipSilence
(
long
presentationTimeUs
)
{
PlaybackParameters
playbackParameters
=
PlaybackParameters
playbackParameters
=
configuration
.
canApplyPlaybackParameters
shouldApplyAudioProcessorPlaybackParameters
()
?
audioProcessorChain
.
applyPlaybackParameters
(
getAudioProcessorPlaybackParameters
())
?
audioProcessorChain
.
applyPlaybackParameters
(
getAudioProcessorPlaybackParameters
())
:
PlaybackParameters
.
DEFAULT
;
:
PlaybackParameters
.
DEFAULT
;
boolean
skipSilenceEnabled
=
boolean
skipSilenceEnabled
=
configuration
.
canApplyPlaybackParameters
shouldApplyAudioProcessorPlaybackParameters
()
?
audioProcessorChain
.
applySkipSilenceEnabled
(
getSkipSilenceEnabled
())
?
audioProcessorChain
.
applySkipSilenceEnabled
(
getSkipSilenceEnabled
())
:
DEFAULT_SKIP_SILENCE
;
:
DEFAULT_SKIP_SILENCE
;
mediaPositionParametersCheckpoints
.
add
(
mediaPositionParametersCheckpoints
.
add
(
...
@@ -1355,6 +1351,31 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -1355,6 +1351,31 @@ public final class DefaultAudioSink implements AudioSink {
}
}
}
}
/**
* Returns whether audio processor playback parameters should be applied in the current
* configuration.
*/
private
boolean
shouldApplyAudioProcessorPlaybackParameters
()
{
// We don't apply speed/pitch adjustment using an audio processor in the following cases:
// - in tunneling mode, because audio processing can change the duration of audio yet the video
// frame presentation times are currently not modified (see also
// https://github.com/google/ExoPlayer/issues/4803);
// - when playing encoded audio via passthrough/offload, because modifying the audio stream
// would require decoding/re-encoding; and
// - when outputting float PCM audio, because SonicAudioProcessor outputs 16-bit integer PCM.
return
!
tunneling
&&
MimeTypes
.
AUDIO_RAW
.
equals
(
configuration
.
inputFormat
.
sampleMimeType
)
&&
!
shouldUseFloatOutput
(
configuration
.
inputFormat
.
pcmEncoding
);
}
/**
* Returns whether audio in the specified PCM encoding should be written to the audio track as
* float PCM.
*/
private
boolean
shouldUseFloatOutput
(
@C
.
PcmEncoding
int
pcmEncoding
)
{
return
enableFloatOutput
&&
Util
.
isEncodingHighResolutionPcm
(
pcmEncoding
);
}
/**
/**
* Applies and updates media position parameters.
* Applies and updates media position parameters.
*
*
...
@@ -1897,7 +1918,6 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -1897,7 +1918,6 @@ public final class DefaultAudioSink implements AudioSink {
public
final
int
outputChannelConfig
;
public
final
int
outputChannelConfig
;
@C
.
Encoding
public
final
int
outputEncoding
;
@C
.
Encoding
public
final
int
outputEncoding
;
public
final
int
bufferSize
;
public
final
int
bufferSize
;
public
final
boolean
canApplyPlaybackParameters
;
public
final
AudioProcessor
[]
availableAudioProcessors
;
public
final
AudioProcessor
[]
availableAudioProcessors
;
public
Configuration
(
public
Configuration
(
...
@@ -1910,7 +1930,6 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -1910,7 +1930,6 @@ public final class DefaultAudioSink implements AudioSink {
int
outputEncoding
,
int
outputEncoding
,
int
specifiedBufferSize
,
int
specifiedBufferSize
,
boolean
enableAudioTrackPlaybackParams
,
boolean
enableAudioTrackPlaybackParams
,
boolean
canApplyPlaybackParameters
,
AudioProcessor
[]
availableAudioProcessors
)
{
AudioProcessor
[]
availableAudioProcessors
)
{
this
.
inputFormat
=
inputFormat
;
this
.
inputFormat
=
inputFormat
;
this
.
inputPcmFrameSize
=
inputPcmFrameSize
;
this
.
inputPcmFrameSize
=
inputPcmFrameSize
;
...
@@ -1919,7 +1938,6 @@ public final class DefaultAudioSink implements AudioSink {
...
@@ -1919,7 +1938,6 @@ public final class DefaultAudioSink implements AudioSink {
this
.
outputSampleRate
=
outputSampleRate
;
this
.
outputSampleRate
=
outputSampleRate
;
this
.
outputChannelConfig
=
outputChannelConfig
;
this
.
outputChannelConfig
=
outputChannelConfig
;
this
.
outputEncoding
=
outputEncoding
;
this
.
outputEncoding
=
outputEncoding
;
this
.
canApplyPlaybackParameters
=
canApplyPlaybackParameters
;
this
.
availableAudioProcessors
=
availableAudioProcessors
;
this
.
availableAudioProcessors
=
availableAudioProcessors
;
// Call computeBufferSize() last as it depends on the other configuration values.
// Call computeBufferSize() last as it depends on the other configuration values.
...
...
library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java
浏览文件 @
4b1e0fa9
...
@@ -457,12 +457,14 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
...
@@ -457,12 +457,14 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
if
(--
prepareCallsCount
!=
0
)
{
if
(--
prepareCallsCount
!=
0
)
{
return
;
return
;
}
}
// Make a local copy, because sessions are removed from this.sessions during release (via
// Release all keepalive acquisitions if keepalive is enabled.
// callback).
if
(
sessionKeepaliveMs
!=
C
.
TIME_UNSET
)
{
List
<
DefaultDrmSession
>
sessions
=
new
ArrayList
<>(
this
.
sessions
);
// Make a local copy, because sessions are removed from this.sessions during release (via
for
(
int
i
=
0
;
i
<
sessions
.
size
();
i
++)
{
// callback).
// Release all the keepalive acquisitions.
List
<
DefaultDrmSession
>
sessions
=
new
ArrayList
<>(
this
.
sessions
);
sessions
.
get
(
i
).
release
(
/* eventDispatcher= */
null
);
for
(
int
i
=
0
;
i
<
sessions
.
size
();
i
++)
{
sessions
.
get
(
i
).
release
(
/* eventDispatcher= */
null
);
}
}
}
Assertions
.
checkNotNull
(
exoMediaDrm
).
release
();
Assertions
.
checkNotNull
(
exoMediaDrm
).
release
();
exoMediaDrm
=
null
;
exoMediaDrm
=
null
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManagerProvider.java
浏览文件 @
4b1e0fa9
...
@@ -16,23 +16,38 @@
...
@@ -16,23 +16,38 @@
package
com.google.android.exoplayer2.drm
;
package
com.google.android.exoplayer2.drm
;
import
static
com
.
google
.
android
.
exoplayer2
.
drm
.
DefaultDrmSessionManager
.
MODE_PLAYBACK
;
import
static
com
.
google
.
android
.
exoplayer2
.
drm
.
DefaultDrmSessionManager
.
MODE_PLAYBACK
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
androidx.annotation.GuardedBy
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.RequiresApi
;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.upstream.DefaultHttpDataSource
;
import
com.google.android.exoplayer2.upstream.DefaultHttpDataSource
;
import
com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
;
import
com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
;
import
com.google.android.exoplayer2.upstream.HttpDataSource
;
import
com.google.android.exoplayer2.upstream.HttpDataSource
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.primitives.Ints
;
import
com.google.common.primitives.Ints
;
import
java.util.Map
;
import
java.util.Map
;
import
org.checkerframework.checker.nullness.qual.MonotonicNonNull
;
/** Default implementation of {@link DrmSessionManagerProvider}. */
/** Default implementation of {@link DrmSessionManagerProvider}. */
public
final
class
DefaultDrmSessionManagerProvider
implements
DrmSessionManagerProvider
{
public
final
class
DefaultDrmSessionManagerProvider
implements
DrmSessionManagerProvider
{
private
final
Object
lock
;
@GuardedBy
(
"lock"
)
private
MediaItem
.
@MonotonicNonNull
DrmConfiguration
drmConfiguration
;
@GuardedBy
(
"lock"
)
private
@MonotonicNonNull
DrmSessionManager
manager
;
@Nullable
private
HttpDataSource
.
Factory
drmHttpDataSourceFactory
;
@Nullable
private
HttpDataSource
.
Factory
drmHttpDataSourceFactory
;
@Nullable
private
String
userAgent
;
@Nullable
private
String
userAgent
;
public
DefaultDrmSessionManagerProvider
()
{
lock
=
new
Object
();
}
/**
/**
* Sets the {@link HttpDataSource.Factory} to be used for creating {@link HttpMediaDrmCallback
* Sets the {@link HttpDataSource.Factory} to be used for creating {@link HttpMediaDrmCallback
* HttpMediaDrmCallbacks} which executes key and provisioning requests over HTTP. If {@code null}
* HttpMediaDrmCallbacks} which executes key and provisioning requests over HTTP. If {@code null}
...
@@ -60,12 +75,24 @@ public final class DefaultDrmSessionManagerProvider implements DrmSessionManager
...
@@ -60,12 +75,24 @@ public final class DefaultDrmSessionManagerProvider implements DrmSessionManager
@Override
@Override
public
DrmSessionManager
get
(
MediaItem
mediaItem
)
{
public
DrmSessionManager
get
(
MediaItem
mediaItem
)
{
Assertions
.
checkNotNull
(
mediaItem
.
playbackProperties
);
checkNotNull
(
mediaItem
.
playbackProperties
);
@Nullable
@Nullable
MediaItem
.
DrmConfiguration
drmConfiguration
=
mediaItem
.
playbackProperties
.
drmConfiguration
;
MediaItem
.
DrmConfiguration
drmConfiguration
=
mediaItem
.
playbackProperties
.
drmConfiguration
;
if
(
drmConfiguration
==
null
||
Util
.
SDK_INT
<
18
)
{
if
(
drmConfiguration
==
null
||
Util
.
SDK_INT
<
18
)
{
return
DrmSessionManager
.
DRM_UNSUPPORTED
;
return
DrmSessionManager
.
DRM_UNSUPPORTED
;
}
}
synchronized
(
lock
)
{
if
(!
Util
.
areEqual
(
drmConfiguration
,
this
.
drmConfiguration
))
{
this
.
drmConfiguration
=
drmConfiguration
;
this
.
manager
=
createManager
(
drmConfiguration
);
}
return
checkNotNull
(
this
.
manager
);
}
}
@RequiresApi
(
18
)
private
DrmSessionManager
createManager
(
MediaItem
.
DrmConfiguration
drmConfiguration
)
{
HttpDataSource
.
Factory
dataSourceFactory
=
HttpDataSource
.
Factory
dataSourceFactory
=
drmHttpDataSourceFactory
!=
null
drmHttpDataSourceFactory
!=
null
?
drmHttpDataSourceFactory
?
drmHttpDataSourceFactory
...
...
library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java
浏览文件 @
4b1e0fa9
...
@@ -318,8 +318,28 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
...
@@ -318,8 +318,28 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
&&
adIndexInAdGroup
<
adPlaybackState
.
adGroups
[
adGroupIndex
].
uris
.
length
)
{
&&
adIndexInAdGroup
<
adPlaybackState
.
adGroups
[
adGroupIndex
].
uris
.
length
)
{
@Nullable
Uri
adUri
=
adPlaybackState
.
adGroups
[
adGroupIndex
].
uris
[
adIndexInAdGroup
];
@Nullable
Uri
adUri
=
adPlaybackState
.
adGroups
[
adGroupIndex
].
uris
[
adIndexInAdGroup
];
if
(
adUri
!=
null
)
{
if
(
adUri
!=
null
)
{
MediaSource
adMediaSource
=
MediaItem
.
Builder
adMediaItem
=
new
MediaItem
.
Builder
().
setUri
(
adUri
);
adMediaSourceFactory
.
createMediaSource
(
MediaItem
.
fromUri
(
adUri
));
// Propagate the content's DRM config into the ad media source.
@Nullable
MediaItem
.
PlaybackProperties
contentPlaybackProperties
=
contentMediaSource
.
getMediaItem
().
playbackProperties
;
if
(
contentPlaybackProperties
!=
null
&&
contentPlaybackProperties
.
drmConfiguration
!=
null
)
{
MediaItem
.
DrmConfiguration
drmConfiguration
=
contentPlaybackProperties
.
drmConfiguration
;
// TODO(internal b/179984779): Use MediaItem.Builder#setDrmConfiguration() when it's
// available.
adMediaItem
.
setDrmUuid
(
drmConfiguration
.
uuid
);
adMediaItem
.
setDrmKeySetId
(
drmConfiguration
.
getKeySetId
());
adMediaItem
.
setDrmLicenseUri
(
drmConfiguration
.
licenseUri
);
adMediaItem
.
setDrmForceDefaultLicenseUri
(
drmConfiguration
.
forceDefaultLicenseUri
);
adMediaItem
.
setDrmLicenseRequestHeaders
(
drmConfiguration
.
requestHeaders
);
adMediaItem
.
setDrmMultiSession
(
drmConfiguration
.
multiSession
);
adMediaItem
.
setDrmPlayClearContentWithoutKey
(
drmConfiguration
.
playClearContentWithoutKey
);
adMediaItem
.
setDrmSessionForClearTypes
(
drmConfiguration
.
sessionForClearTypes
);
}
MediaSource
adMediaSource
=
adMediaSourceFactory
.
createMediaSource
(
adMediaItem
.
build
());
adMediaSourceHolder
.
initializeWithMediaSource
(
adMediaSource
,
adUri
);
adMediaSourceHolder
.
initializeWithMediaSource
(
adMediaSource
,
adUri
);
}
}
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
浏览文件 @
4b1e0fa9
...
@@ -71,6 +71,7 @@ import com.google.android.exoplayer2.source.MediaSource;
...
@@ -71,6 +71,7 @@ import com.google.android.exoplayer2.source.MediaSource;
import
com.google.android.exoplayer2.source.MediaSource.MediaPeriodId
;
import
com.google.android.exoplayer2.source.MediaSource.MediaPeriodId
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener
;
import
com.google.android.exoplayer2.source.SilenceMediaSource
;
import
com.google.android.exoplayer2.source.SilenceMediaSource
;
import
com.google.android.exoplayer2.source.SinglePeriodTimeline
;
import
com.google.android.exoplayer2.source.TrackGroup
;
import
com.google.android.exoplayer2.source.TrackGroup
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.source.ads.AdPlaybackState
;
import
com.google.android.exoplayer2.source.ads.AdPlaybackState
;
...
@@ -83,6 +84,7 @@ import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner;
...
@@ -83,6 +84,7 @@ import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner;
import
com.google.android.exoplayer2.testutil.FakeAdaptiveDataSet
;
import
com.google.android.exoplayer2.testutil.FakeAdaptiveDataSet
;
import
com.google.android.exoplayer2.testutil.FakeAdaptiveMediaSource
;
import
com.google.android.exoplayer2.testutil.FakeAdaptiveMediaSource
;
import
com.google.android.exoplayer2.testutil.FakeChunkSource
;
import
com.google.android.exoplayer2.testutil.FakeChunkSource
;
import
com.google.android.exoplayer2.testutil.FakeClock
;
import
com.google.android.exoplayer2.testutil.FakeDataSource
;
import
com.google.android.exoplayer2.testutil.FakeDataSource
;
import
com.google.android.exoplayer2.testutil.FakeMediaClockRenderer
;
import
com.google.android.exoplayer2.testutil.FakeMediaClockRenderer
;
import
com.google.android.exoplayer2.testutil.FakeMediaPeriod
;
import
com.google.android.exoplayer2.testutil.FakeMediaPeriod
;
...
@@ -8833,6 +8835,42 @@ public final class ExoPlayerTest {
...
@@ -8833,6 +8835,42 @@ public final class ExoPlayerTest {
assertThat
(
liveOffsetAtEnd
).
isIn
(
Range
.
closed
(
1_900L
,
2_100L
));
assertThat
(
liveOffsetAtEnd
).
isIn
(
Range
.
closed
(
1_900L
,
2_100L
));
}
}
@Test
public
void
targetLiveOffsetInMedia_unknownWindowStartTime_doesNotAdjustLiveOffset
()
throws
Exception
{
FakeClock
fakeClock
=
new
AutoAdvancingFakeClock
(
/* initialTimeMs= */
987_654_321L
);
ExoPlayer
player
=
new
TestExoPlayerBuilder
(
context
).
setClock
(
fakeClock
).
build
();
MediaItem
mediaItem
=
new
MediaItem
.
Builder
().
setUri
(
Uri
.
EMPTY
).
setLiveTargetOffsetMs
(
4_000
).
build
();
Timeline
liveTimeline
=
new
SinglePeriodTimeline
(
/* presentationStartTimeMs= */
C
.
TIME_UNSET
,
/* windowStartTimeMs= */
C
.
TIME_UNSET
,
/* elapsedRealtimeEpochOffsetMs= */
C
.
TIME_UNSET
,
/* periodDurationUs= */
1000
*
C
.
MICROS_PER_SECOND
,
/* windowDurationUs= */
1000
*
C
.
MICROS_PER_SECOND
,
/* windowPositionInPeriodUs= */
0
,
/* windowDefaultStartPositionUs= */
0
,
/* isSeekable= */
true
,
/* isDynamic= */
true
,
/* manifest= */
null
,
mediaItem
,
mediaItem
.
liveConfiguration
);
player
.
pause
();
player
.
setMediaSource
(
new
FakeMediaSource
(
liveTimeline
));
player
.
prepare
();
TestPlayerRunHelper
.
runUntilPlaybackState
(
player
,
Player
.
STATE_READY
);
long
playbackStartTimeMs
=
fakeClock
.
elapsedRealtime
();
TestPlayerRunHelper
.
playUntilPosition
(
player
,
/* windowIndex= */
0
,
/* positionMs= */
999_000
);
long
playbackEndTimeMs
=
fakeClock
.
elapsedRealtime
();
player
.
release
();
// Assert that the time it took to play 999 seconds of media is 999 seconds (asserting that no
// playback speed adjustment was used).
assertThat
(
playbackEndTimeMs
-
playbackStartTimeMs
).
isEqualTo
(
999_000
);
}
@Test
@Test
public
void
noTargetLiveOffsetInMedia_doesNotAdjustLiveOffset
()
throws
Exception
{
public
void
noTargetLiveOffsetInMedia_doesNotAdjustLiveOffset
()
throws
Exception
{
long
windowStartUnixTimeMs
=
987_654_321_000L
;
long
windowStartUnixTimeMs
=
987_654_321_000L
;
...
...
library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioSinkTest.java
浏览文件 @
4b1e0fa9
...
@@ -320,6 +320,20 @@ public final class DefaultAudioSinkTest {
...
@@ -320,6 +320,20 @@ public final class DefaultAudioSinkTest {
assertThat
(
thrown
.
format
).
isEqualTo
(
format
);
assertThat
(
thrown
.
format
).
isEqualTo
(
format
);
}
}
@Test
public
void
setPlaybackParameters_doesNothingWhenTunnelingIsEnabled
()
throws
Exception
{
defaultAudioSink
.
setAudioSessionId
(
1
);
defaultAudioSink
.
enableTunnelingV21
();
defaultAudioSink
.
setPlaybackParameters
(
new
PlaybackParameters
(
2
));
configureDefaultAudioSink
(
/* channelCount= */
2
);
defaultAudioSink
.
handleBuffer
(
createDefaultSilenceBuffer
(),
/* presentationTimeUs= */
5
*
C
.
MICROS_PER_SECOND
,
/* encodedAccessUnitCount= */
1
);
assertThat
(
defaultAudioSink
.
getPlaybackParameters
().
speed
).
isEqualTo
(
1
);
}
private
void
configureDefaultAudioSink
(
int
channelCount
)
throws
AudioSink
.
ConfigurationException
{
private
void
configureDefaultAudioSink
(
int
channelCount
)
throws
AudioSink
.
ConfigurationException
{
configureDefaultAudioSink
(
channelCount
,
/* trimStartFrames= */
0
,
/* trimEndFrames= */
0
);
configureDefaultAudioSink
(
channelCount
,
/* trimStartFrames= */
0
,
/* trimEndFrames= */
0
);
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManagerTest.java
浏览文件 @
4b1e0fa9
...
@@ -147,6 +147,32 @@ public class DefaultDrmSessionManagerTest {
...
@@ -147,6 +147,32 @@ public class DefaultDrmSessionManagerTest {
assertThat
(
drmSession
.
getState
()).
isEqualTo
(
DrmSession
.
STATE_RELEASED
);
assertThat
(
drmSession
.
getState
()).
isEqualTo
(
DrmSession
.
STATE_RELEASED
);
}
}
@Test
(
timeout
=
10_000
)
public
void
managerRelease_keepaliveDisabled_doesntReleaseAnySessions
()
throws
Exception
{
FakeExoMediaDrm
.
LicenseServer
licenseServer
=
FakeExoMediaDrm
.
LicenseServer
.
allowingSchemeDatas
(
DRM_SCHEME_DATAS
);
DrmSessionManager
drmSessionManager
=
new
DefaultDrmSessionManager
.
Builder
()
.
setUuidAndExoMediaDrmProvider
(
DRM_SCHEME_UUID
,
uuid
->
new
FakeExoMediaDrm
())
.
setSessionKeepaliveMs
(
C
.
TIME_UNSET
)
.
build
(
/* mediaDrmCallback= */
licenseServer
);
drmSessionManager
.
prepare
();
DrmSession
drmSession
=
checkNotNull
(
drmSessionManager
.
acquireSession
(
/* playbackLooper= */
checkNotNull
(
Looper
.
myLooper
()),
/* eventDispatcher= */
null
,
FORMAT_WITH_DRM_INIT_DATA
));
waitForOpenedWithKeys
(
drmSession
);
assertThat
(
drmSession
.
getState
()).
isEqualTo
(
DrmSession
.
STATE_OPENED_WITH_KEYS
);
// Release the manager, the session should still be open (though it's unusable because
// the underlying ExoMediaDrm is released).
drmSessionManager
.
release
();
assertThat
(
drmSession
.
getState
()).
isEqualTo
(
DrmSession
.
STATE_OPENED_WITH_KEYS
);
}
@Test
(
timeout
=
10_000
)
@Test
(
timeout
=
10_000
)
public
void
maxConcurrentSessionsExceeded_allKeepAliveSessionsEagerlyReleased
()
throws
Exception
{
public
void
maxConcurrentSessionsExceeded_allKeepAliveSessionsEagerlyReleased
()
throws
Exception
{
ImmutableList
<
DrmInitData
.
SchemeData
>
secondSchemeDatas
=
ImmutableList
<
DrmInitData
.
SchemeData
>
secondSchemeDatas
=
...
...
library/core/src/test/java/com/google/android/exoplayer2/source/DefaultDrmSessionManagerProviderTest.java
浏览文件 @
4b1e0fa9
...
@@ -51,4 +51,39 @@ public class DefaultDrmSessionManagerProviderTest {
...
@@ -51,4 +51,39 @@ public class DefaultDrmSessionManagerProviderTest {
assertThat
(
drmSessionManager
).
isNotEqualTo
(
DrmSessionManager
.
DRM_UNSUPPORTED
);
assertThat
(
drmSessionManager
).
isNotEqualTo
(
DrmSessionManager
.
DRM_UNSUPPORTED
);
}
}
@Test
public
void
create_reusesCachedInstanceWherePossible
()
{
MediaItem
mediaItem1
=
new
MediaItem
.
Builder
()
.
setUri
(
"https://example.test/content-1"
)
.
setDrmUuid
(
C
.
WIDEVINE_UUID
)
.
build
();
// Same DRM info as item1, but different URL to check it doesn't prevent re-using a manager.
MediaItem
mediaItem2
=
new
MediaItem
.
Builder
()
.
setUri
(
"https://example.test/content-2"
)
.
setDrmUuid
(
C
.
WIDEVINE_UUID
)
.
build
();
// Different DRM info to 1 and 2, needs a different manager instance.
MediaItem
mediaItem3
=
new
MediaItem
.
Builder
()
.
setUri
(
"https://example.test/content-3"
)
.
setDrmUuid
(
C
.
WIDEVINE_UUID
)
.
setDrmLicenseUri
(
"https://example.test/license"
)
.
build
();
DefaultDrmSessionManagerProvider
provider
=
new
DefaultDrmSessionManagerProvider
();
DrmSessionManager
drmSessionManager1
=
provider
.
get
(
mediaItem1
);
DrmSessionManager
drmSessionManager2
=
provider
.
get
(
mediaItem2
);
DrmSessionManager
drmSessionManager3
=
provider
.
get
(
mediaItem3
);
// Get a manager for the first item again - expect it to be a different instance to last time
// since we only cache one.
DrmSessionManager
drmSessionManager4
=
provider
.
get
(
mediaItem1
);
assertThat
(
drmSessionManager1
).
isSameInstanceAs
(
drmSessionManager2
);
assertThat
(
drmSessionManager1
).
isNotSameInstanceAs
(
drmSessionManager3
);
assertThat
(
drmSessionManager1
).
isNotSameInstanceAs
(
drmSessionManager4
);
}
}
}
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java
浏览文件 @
4b1e0fa9
...
@@ -901,77 +901,54 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -901,77 +901,54 @@ public final class DashMediaSource extends BaseMediaSource {
}
}
}
}
// Update the window.
// Update the window.
boolean
windowChangingImplicitly
=
false
;
Period
firstPeriod
=
manifest
.
getPeriod
(
0
)
;
int
lastPeriodIndex
=
manifest
.
getPeriodCount
()
-
1
;
int
lastPeriodIndex
=
manifest
.
getPeriodCount
()
-
1
;
Period
lastPeriod
=
manifest
.
getPeriod
(
lastPeriodIndex
);
Period
lastPeriod
=
manifest
.
getPeriod
(
lastPeriodIndex
);
long
lastPeriodDurationUs
=
manifest
.
getPeriodDurationUs
(
lastPeriodIndex
);
long
lastPeriodDurationUs
=
manifest
.
getPeriodDurationUs
(
lastPeriodIndex
);
long
nowUnixTimeUs
=
C
.
msToUs
(
Util
.
getNowUnixTimeMs
(
elapsedRealtimeOffsetMs
));
long
nowUnixTimeUs
=
C
.
msToUs
(
Util
.
getNowUnixTimeMs
(
elapsedRealtimeOffsetMs
));
// Get the period-relative start/end times.
long
windowStartTimeInManifestUs
=
long
currentStartTimeUs
=
getAvailableStartTimeInManifestUs
(
getAvailableStartTimeUs
(
firstPeriod
,
manifest
.
getPeriodDurationUs
(
0
),
nowUnixTimeUs
);
manifest
.
getPeriod
(
0
),
manifest
.
getPeriodDurationUs
(
0
),
nowUnixTimeUs
);
long
windowEndTimeInManifestUs
=
long
currentEndTimeUs
=
getAvailableEndTimeUs
(
lastPeriod
,
lastPeriodDurationUs
,
nowUnixTimeUs
);
getAvailableEndTimeInManifestUs
(
lastPeriod
,
lastPeriodDurationUs
,
nowUnixTimeUs
);
if
(
manifest
.
dynamic
&&
!
isIndexExplicit
(
lastPeriod
))
{
boolean
windowChangingImplicitly
=
manifest
.
dynamic
&&
!
isIndexExplicit
(
lastPeriod
);
// The manifest describes an incomplete live stream. Update the start/end times to reflect the
if
(
windowChangingImplicitly
&&
manifest
.
timeShiftBufferDepthMs
!=
C
.
TIME_UNSET
)
{
// live stream duration and the manifest's time shift buffer depth.
// Update the available start time to reflect the manifest's time shift buffer depth.
long
liveStreamEndPositionInLastPeriodUs
=
currentEndTimeUs
-
C
.
msToUs
(
lastPeriod
.
startMs
);
long
timeShiftBufferStartTimeInManifestUs
=
currentEndTimeUs
=
min
(
liveStreamEndPositionInLastPeriodUs
,
currentEndTimeUs
);
windowEndTimeInManifestUs
-
C
.
msToUs
(
manifest
.
timeShiftBufferDepthMs
);
if
(
manifest
.
timeShiftBufferDepthMs
!=
C
.
TIME_UNSET
)
{
windowStartTimeInManifestUs
=
long
timeShiftBufferDepthUs
=
C
.
msToUs
(
manifest
.
timeShiftBufferDepthMs
);
max
(
windowStartTimeInManifestUs
,
timeShiftBufferStartTimeInManifestUs
);
long
offsetInPeriodUs
=
currentEndTimeUs
-
timeShiftBufferDepthUs
;
}
int
periodIndex
=
lastPeriodIndex
;
long
windowDurationUs
=
windowEndTimeInManifestUs
-
windowStartTimeInManifestUs
;
while
(
offsetInPeriodUs
<
0
&&
periodIndex
>
0
)
{
long
windowStartUnixTimeMs
=
C
.
TIME_UNSET
;
offsetInPeriodUs
+=
manifest
.
getPeriodDurationUs
(--
periodIndex
);
long
windowDefaultPositionUs
=
0
;
}
if
(
periodIndex
==
0
)
{
currentStartTimeUs
=
max
(
currentStartTimeUs
,
offsetInPeriodUs
);
}
else
{
// The time shift buffer starts after the earliest period.
// TODO: Does this ever happen?
currentStartTimeUs
=
manifest
.
getPeriodDurationUs
(
0
);
}
}
windowChangingImplicitly
=
true
;
}
long
windowDurationUs
=
currentEndTimeUs
-
currentStartTimeUs
;
for
(
int
i
=
0
;
i
<
manifest
.
getPeriodCount
()
-
1
;
i
++)
{
windowDurationUs
+=
manifest
.
getPeriodDurationUs
(
i
);
}
long
windowStartTimeMs
=
C
.
TIME_UNSET
;
if
(
manifest
.
availabilityStartTimeMs
!=
C
.
TIME_UNSET
)
{
windowStartTimeMs
=
manifest
.
availabilityStartTimeMs
+
manifest
.
getPeriod
(
0
).
startMs
+
C
.
usToMs
(
currentStartTimeUs
);
}
long
windowDefaultStartPositionUs
=
0
;
if
(
manifest
.
dynamic
)
{
if
(
manifest
.
dynamic
)
{
updateMediaItemLiveConfiguration
(
checkState
(
manifest
.
availabilityStartTimeMs
!=
C
.
TIME_UNSET
);
/* nowPeriodTimeUs= */
currentStartTimeUs
+
nowUnixTimeUs
-
C
.
msToUs
(
windowStartTimeMs
),
long
nowInWindowUs
=
/* windowStartPeriodTimeUs= */
currentStartTimeUs
,
nowUnixTimeUs
-
C
.
msToUs
(
manifest
.
availabilityStartTimeMs
)
-
windowStartTimeInManifestUs
;
/* windowEndPeriodTimeUs= */
currentEndTimeUs
);
updateMediaItemLiveConfiguration
(
nowInWindowUs
,
windowDurationUs
);
windowDefaultStartPositionUs
=
windowStartUnixTimeMs
=
nowUnixTimeUs
-
C
.
msToUs
(
windowStartTimeMs
+
liveConfiguration
.
targetOffsetMs
);
manifest
.
availabilityStartTimeMs
+
C
.
usToMs
(
windowStartTimeInManifestUs
);
long
minimumDefaultStartPositionUs
=
windowDefaultPositionUs
=
nowInWindowUs
-
C
.
msToUs
(
liveConfiguration
.
targetOffsetMs
);
long
minimumWindowDefaultPositionUs
=
min
(
MIN_LIVE_DEFAULT_START_POSITION_US
,
windowDurationUs
/
2
);
min
(
MIN_LIVE_DEFAULT_START_POSITION_US
,
windowDurationUs
/
2
);
if
(
windowDefault
StartPositionUs
<
minimumDefaultStar
tPositionUs
)
{
if
(
windowDefault
PositionUs
<
minimumWindowDefaul
tPositionUs
)
{
// The default
start position is too close to the start of the live window. Set it to the
// The default
position is too close to the start of the live window. Set it to the minimum
//
minimum default start position provided the window is at least twice as big. Else set
//
default position provided the window is at least twice as big. Else set it to the middle
//
it to the middle
of the window.
// of the window.
windowDefault
StartPositionUs
=
minimumDefaultStar
tPositionUs
;
windowDefault
PositionUs
=
minimumWindowDefaul
tPositionUs
;
}
}
}
}
long
offsetInFirstPeriodUs
=
windowStartTimeInManifestUs
-
C
.
msToUs
(
firstPeriod
.
startMs
);
DashTimeline
timeline
=
DashTimeline
timeline
=
new
DashTimeline
(
new
DashTimeline
(
manifest
.
availabilityStartTimeMs
,
manifest
.
availabilityStartTimeMs
,
windowStartTimeMs
,
windowStart
Unix
TimeMs
,
elapsedRealtimeOffsetMs
,
elapsedRealtimeOffsetMs
,
firstPeriodId
,
firstPeriodId
,
/* offsetInFirstPeriodUs= */
currentStartTime
Us
,
offsetInFirstPeriod
Us
,
windowDurationUs
,
windowDurationUs
,
windowDefault
Start
PositionUs
,
windowDefaultPositionUs
,
manifest
,
manifest
,
mediaItem
,
mediaItem
,
manifest
.
dynamic
?
liveConfiguration
:
null
);
manifest
.
dynamic
?
liveConfiguration
:
null
);
...
@@ -1008,8 +985,7 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1008,8 +985,7 @@ public final class DashMediaSource extends BaseMediaSource {
}
}
}
}
private
void
updateMediaItemLiveConfiguration
(
private
void
updateMediaItemLiveConfiguration
(
long
nowInWindowUs
,
long
windowDurationUs
)
{
long
nowPeriodTimeUs
,
long
windowStartPeriodTimeUs
,
long
windowEndPeriodTimeUs
)
{
long
maxLiveOffsetMs
;
long
maxLiveOffsetMs
;
if
(
mediaItem
.
liveConfiguration
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
if
(
mediaItem
.
liveConfiguration
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
maxLiveOffsetMs
=
mediaItem
.
liveConfiguration
.
maxOffsetMs
;
maxLiveOffsetMs
=
mediaItem
.
liveConfiguration
.
maxOffsetMs
;
...
@@ -1017,7 +993,7 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1017,7 +993,7 @@ public final class DashMediaSource extends BaseMediaSource {
&&
manifest
.
serviceDescription
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
&&
manifest
.
serviceDescription
.
maxOffsetMs
!=
C
.
TIME_UNSET
)
{
maxLiveOffsetMs
=
manifest
.
serviceDescription
.
maxOffsetMs
;
maxLiveOffsetMs
=
manifest
.
serviceDescription
.
maxOffsetMs
;
}
else
{
}
else
{
maxLiveOffsetMs
=
C
.
usToMs
(
now
PeriodTimeUs
-
windowStartPeriodTime
Us
);
maxLiveOffsetMs
=
C
.
usToMs
(
now
InWindow
Us
);
}
}
long
minLiveOffsetMs
;
long
minLiveOffsetMs
;
if
(
mediaItem
.
liveConfiguration
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
if
(
mediaItem
.
liveConfiguration
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
...
@@ -1026,7 +1002,7 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1026,7 +1002,7 @@ public final class DashMediaSource extends BaseMediaSource {
&&
manifest
.
serviceDescription
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
&&
manifest
.
serviceDescription
.
minOffsetMs
!=
C
.
TIME_UNSET
)
{
minLiveOffsetMs
=
manifest
.
serviceDescription
.
minOffsetMs
;
minLiveOffsetMs
=
manifest
.
serviceDescription
.
minOffsetMs
;
}
else
{
}
else
{
minLiveOffsetMs
=
C
.
usToMs
(
now
PeriodTimeUs
-
windowEndPeriodTime
Us
);
minLiveOffsetMs
=
C
.
usToMs
(
now
InWindowUs
-
windowDuration
Us
);
if
(
minLiveOffsetMs
<
0
&&
maxLiveOffsetMs
>
0
)
{
if
(
minLiveOffsetMs
<
0
&&
maxLiveOffsetMs
>
0
)
{
// The current time is in the window, so assume all clocks are synchronized and set the
// The current time is in the window, so assume all clocks are synchronized and set the
// minimum to a live offset of zero.
// minimum to a live offset of zero.
...
@@ -1052,12 +1028,10 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1052,12 +1028,10 @@ public final class DashMediaSource extends BaseMediaSource {
targetOffsetMs
=
minLiveOffsetMs
;
targetOffsetMs
=
minLiveOffsetMs
;
}
}
if
(
targetOffsetMs
>
maxLiveOffsetMs
)
{
if
(
targetOffsetMs
>
maxLiveOffsetMs
)
{
long
windowDurationUs
=
windowEndPeriodTimeUs
-
windowStartPeriodTimeUs
;
long
liveOffsetAtWindowStartUs
=
nowPeriodTimeUs
-
windowStartPeriodTimeUs
;
long
safeDistanceFromWindowStartUs
=
long
safeDistanceFromWindowStartUs
=
min
(
MIN_LIVE_DEFAULT_START_POSITION_US
,
windowDurationUs
/
2
);
min
(
MIN_LIVE_DEFAULT_START_POSITION_US
,
windowDurationUs
/
2
);
long
maxTargetOffsetForSafeDistanceToWindowStartMs
=
long
maxTargetOffsetForSafeDistanceToWindowStartMs
=
C
.
usToMs
(
liveOffsetAtWindowStart
Us
-
safeDistanceFromWindowStartUs
);
C
.
usToMs
(
nowInWindow
Us
-
safeDistanceFromWindowStartUs
);
targetOffsetMs
=
targetOffsetMs
=
Util
.
constrainValue
(
Util
.
constrainValue
(
maxTargetOffsetForSafeDistanceToWindowStartMs
,
minLiveOffsetMs
,
maxLiveOffsetMs
);
maxTargetOffsetForSafeDistanceToWindowStartMs
,
minLiveOffsetMs
,
maxLiveOffsetMs
);
...
@@ -1147,9 +1121,10 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1147,9 +1121,10 @@ public final class DashMediaSource extends BaseMediaSource {
return
LongMath
.
divide
(
intervalUs
,
1000
,
RoundingMode
.
CEILING
);
return
LongMath
.
divide
(
intervalUs
,
1000
,
RoundingMode
.
CEILING
);
}
}
private
static
long
getAvailableStartTimeUs
(
private
static
long
getAvailableStartTime
InManifest
Us
(
Period
period
,
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
Period
period
,
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
long
availableStartTimeUs
=
0
;
long
periodStartTimeInManifestUs
=
C
.
msToUs
(
period
.
startMs
);
long
availableStartTimeInManifestUs
=
periodStartTimeInManifestUs
;
boolean
haveAudioVideoAdaptationSets
=
hasVideoOrAudioAdaptationSets
(
period
);
boolean
haveAudioVideoAdaptationSets
=
hasVideoOrAudioAdaptationSets
(
period
);
for
(
int
i
=
0
;
i
<
period
.
adaptationSets
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
period
.
adaptationSets
.
size
();
i
++)
{
AdaptationSet
adaptationSet
=
period
.
adaptationSets
.
get
(
i
);
AdaptationSet
adaptationSet
=
period
.
adaptationSets
.
get
(
i
);
...
@@ -1162,23 +1137,26 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1162,23 +1137,26 @@ public final class DashMediaSource extends BaseMediaSource {
}
}
@Nullable
DashSegmentIndex
index
=
representations
.
get
(
0
).
getIndex
();
@Nullable
DashSegmentIndex
index
=
representations
.
get
(
0
).
getIndex
();
if
(
index
==
null
)
{
if
(
index
==
null
)
{
return
0
;
return
periodStartTimeInManifestUs
;
}
}
int
availableSegmentCount
=
index
.
getAvailableSegmentCount
(
periodDurationUs
,
nowUnixTimeUs
);
int
availableSegmentCount
=
index
.
getAvailableSegmentCount
(
periodDurationUs
,
nowUnixTimeUs
);
if
(
availableSegmentCount
==
0
)
{
if
(
availableSegmentCount
==
0
)
{
return
0
;
return
periodStartTimeInManifestUs
;
}
}
long
firstAvailableSegmentNum
=
long
firstAvailableSegmentNum
=
index
.
getFirstAvailableSegmentNum
(
periodDurationUs
,
nowUnixTimeUs
);
index
.
getFirstAvailableSegmentNum
(
periodDurationUs
,
nowUnixTimeUs
);
long
adaptationSetAvailableStartTimeUs
=
index
.
getTimeUs
(
firstAvailableSegmentNum
);
long
adaptationSetAvailableStartTimeInManifestUs
=
availableStartTimeUs
=
max
(
availableStartTimeUs
,
adaptationSetAvailableStartTimeUs
);
periodStartTimeInManifestUs
+
index
.
getTimeUs
(
firstAvailableSegmentNum
);
availableStartTimeInManifestUs
=
max
(
availableStartTimeInManifestUs
,
adaptationSetAvailableStartTimeInManifestUs
);
}
}
return
availableStartTimeUs
;
return
availableStartTime
InManifest
Us
;
}
}
private
static
long
getAvailableEndTimeUs
(
private
static
long
getAvailableEndTime
InManifest
Us
(
Period
period
,
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
Period
period
,
long
periodDurationUs
,
long
nowUnixTimeUs
)
{
long
availableEndTimeUs
=
Long
.
MAX_VALUE
;
long
periodStartTimeInManifestUs
=
C
.
msToUs
(
period
.
startMs
);
long
availableEndTimeInManifestUs
=
Long
.
MAX_VALUE
;
boolean
haveAudioVideoAdaptationSets
=
hasVideoOrAudioAdaptationSets
(
period
);
boolean
haveAudioVideoAdaptationSets
=
hasVideoOrAudioAdaptationSets
(
period
);
for
(
int
i
=
0
;
i
<
period
.
adaptationSets
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
period
.
adaptationSets
.
size
();
i
++)
{
AdaptationSet
adaptationSet
=
period
.
adaptationSets
.
get
(
i
);
AdaptationSet
adaptationSet
=
period
.
adaptationSets
.
get
(
i
);
...
@@ -1191,21 +1169,23 @@ public final class DashMediaSource extends BaseMediaSource {
...
@@ -1191,21 +1169,23 @@ public final class DashMediaSource extends BaseMediaSource {
}
}
@Nullable
DashSegmentIndex
index
=
representations
.
get
(
0
).
getIndex
();
@Nullable
DashSegmentIndex
index
=
representations
.
get
(
0
).
getIndex
();
if
(
index
==
null
)
{
if
(
index
==
null
)
{
return
periodDurationUs
;
return
period
StartTimeInManifestUs
+
period
DurationUs
;
}
}
int
availableSegmentCount
=
index
.
getAvailableSegmentCount
(
periodDurationUs
,
nowUnixTimeUs
);
int
availableSegmentCount
=
index
.
getAvailableSegmentCount
(
periodDurationUs
,
nowUnixTimeUs
);
if
(
availableSegmentCount
==
0
)
{
if
(
availableSegmentCount
==
0
)
{
return
0
;
return
periodStartTimeInManifestUs
;
}
}
long
firstAvailableSegmentNum
=
long
firstAvailableSegmentNum
=
index
.
getFirstAvailableSegmentNum
(
periodDurationUs
,
nowUnixTimeUs
);
index
.
getFirstAvailableSegmentNum
(
periodDurationUs
,
nowUnixTimeUs
);
long
lastAvailableSegmentNum
=
firstAvailableSegmentNum
+
availableSegmentCount
-
1
;
long
lastAvailableSegmentNum
=
firstAvailableSegmentNum
+
availableSegmentCount
-
1
;
long
adaptationSetAvailableEndTimeUs
=
long
adaptationSetAvailableEndTimeInManifestUs
=
index
.
getTimeUs
(
lastAvailableSegmentNum
)
periodStartTimeInManifestUs
+
index
.
getTimeUs
(
lastAvailableSegmentNum
)
+
index
.
getDurationUs
(
lastAvailableSegmentNum
,
periodDurationUs
);
+
index
.
getDurationUs
(
lastAvailableSegmentNum
,
periodDurationUs
);
availableEndTimeUs
=
min
(
availableEndTimeUs
,
adaptationSetAvailableEndTimeUs
);
availableEndTimeInManifestUs
=
min
(
availableEndTimeInManifestUs
,
adaptationSetAvailableEndTimeInManifestUs
);
}
}
return
availableEndTimeUs
;
return
availableEndTime
InManifest
Us
;
}
}
private
static
boolean
isIndexExplicit
(
Period
period
)
{
private
static
boolean
isIndexExplicit
(
Period
period
)
{
...
...
library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Period.java
浏览文件 @
4b1e0fa9
...
@@ -30,9 +30,7 @@ public class Period {
...
@@ -30,9 +30,7 @@ public class Period {
*/
*/
@Nullable
public
final
String
id
;
@Nullable
public
final
String
id
;
/**
/** The start time of the period in milliseconds, relative to the start of the manifest. */
* The start time of the period in milliseconds.
*/
public
final
long
startMs
;
public
final
long
startMs
;
/**
/**
...
...
library/transformer/src/main/java/com/google/android/exoplayer2/transformer/SpeedProvider.java
浏览文件 @
4b1e0fa9
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
package
com.google.android.exoplayer2.transformer
;
package
com.google.android.exoplayer2.transformer
;
/** A custom interface that determines the speed for media at specific timestamps. */
/** A custom interface that determines the speed for media at specific timestamps. */
public
interface
SpeedProvider
{
/* package */
interface
SpeedProvider
{
/**
/**
* Provides the speed that the media should be played at, based on the timeUs.
* Provides the speed that the media should be played at, based on the timeUs.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录