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
42a2b923
authored
Nov 02, 2020
by
christosts
Committed by
Oliver Woodman
Nov 02, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
HLS: populate targetLiveOffset in MediaItem from server control
Issue: #5011 PiperOrigin-RevId: 340260636
parent
e1211f92
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
82 additions
and
15 deletions
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaSourceTest.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java
View file @
42a2b923
...
@@ -16,12 +16,13 @@
...
@@ -16,12 +16,13 @@
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
annotation
.
RetentionPolicy
.
SOURCE
;
import
static
java
.
lang
.
annotation
.
RetentionPolicy
.
SOURCE
;
import
android.net.Uri
;
import
android.net.Uri
;
import
android.os.SystemClock
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.MediaItem
;
import
com.google.android.exoplayer2.MediaItem
;
...
@@ -52,6 +53,7 @@ import com.google.android.exoplayer2.upstream.HttpDataSource;
...
@@ -52,6 +53,7 @@ import com.google.android.exoplayer2.upstream.HttpDataSource;
import
com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy
;
import
com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy
;
import
com.google.android.exoplayer2.upstream.TransferListener
;
import
com.google.android.exoplayer2.upstream.TransferListener
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.Retention
;
...
@@ -87,7 +89,6 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -87,7 +89,6 @@ public final class HlsMediaSource extends BaseMediaSource
public
static
final
int
METADATA_TYPE_ID3
=
1
;
public
static
final
int
METADATA_TYPE_ID3
=
1
;
/** Type for ESMG metadata in HLS streams. */
/** Type for ESMG metadata in HLS streams. */
public
static
final
int
METADATA_TYPE_EMSG
=
3
;
public
static
final
int
METADATA_TYPE_EMSG
=
3
;
/** Factory for {@link HlsMediaSource}s. */
/** Factory for {@link HlsMediaSource}s. */
public
static
final
class
Factory
implements
MediaSourceFactory
{
public
static
final
class
Factory
implements
MediaSourceFactory
{
...
@@ -105,6 +106,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -105,6 +106,7 @@ public final class HlsMediaSource extends BaseMediaSource
private
boolean
useSessionKeys
;
private
boolean
useSessionKeys
;
private
List
<
StreamKey
>
streamKeys
;
private
List
<
StreamKey
>
streamKeys
;
@Nullable
private
Object
tag
;
@Nullable
private
Object
tag
;
private
long
elapsedRealTimeOffsetMs
;
/**
/**
* Creates a new factory for {@link HlsMediaSource}s.
* Creates a new factory for {@link HlsMediaSource}s.
...
@@ -133,6 +135,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -133,6 +135,7 @@ public final class HlsMediaSource extends BaseMediaSource
compositeSequenceableLoaderFactory
=
new
DefaultCompositeSequenceableLoaderFactory
();
compositeSequenceableLoaderFactory
=
new
DefaultCompositeSequenceableLoaderFactory
();
metadataType
=
METADATA_TYPE_ID3
;
metadataType
=
METADATA_TYPE_ID3
;
streamKeys
=
Collections
.
emptyList
();
streamKeys
=
Collections
.
emptyList
();
elapsedRealTimeOffsetMs
=
C
.
TIME_UNSET
;
}
}
/**
/**
...
@@ -316,6 +319,20 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -316,6 +319,20 @@ public final class HlsMediaSource extends BaseMediaSource
return
this
;
return
this
;
}
}
/**
* Sets the offset between {@link SystemClock#elapsedRealtime()} and the time since the Unix
* epoch. By default, is it set to {@link C#TIME_UNSET}.
*
* @param elapsedRealTimeOffsetMs The offset between {@link SystemClock#elapsedRealtime()} and
* the time since the Unix epoch, in milliseconds.
* @return This factory, for convenience.
*/
@VisibleForTesting
/* package */
Factory
setElapsedRealTimeOffsetMs
(
long
elapsedRealTimeOffsetMs
)
{
this
.
elapsedRealTimeOffsetMs
=
elapsedRealTimeOffsetMs
;
return
this
;
}
/** @deprecated Use {@link #createMediaSource(MediaItem)} instead. */
/** @deprecated Use {@link #createMediaSource(MediaItem)} instead. */
@SuppressWarnings
(
"deprecation"
)
@SuppressWarnings
(
"deprecation"
)
@Deprecated
@Deprecated
...
@@ -364,6 +381,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -364,6 +381,7 @@ public final class HlsMediaSource extends BaseMediaSource
loadErrorHandlingPolicy
,
loadErrorHandlingPolicy
,
playlistTrackerFactory
.
createTracker
(
playlistTrackerFactory
.
createTracker
(
hlsDataSourceFactory
,
loadErrorHandlingPolicy
,
playlistParserFactory
),
hlsDataSourceFactory
,
loadErrorHandlingPolicy
,
playlistParserFactory
),
elapsedRealTimeOffsetMs
,
allowChunklessPreparation
,
allowChunklessPreparation
,
metadataType
,
metadataType
,
useSessionKeys
);
useSessionKeys
);
...
@@ -376,7 +394,6 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -376,7 +394,6 @@ public final class HlsMediaSource extends BaseMediaSource
}
}
private
final
HlsExtractorFactory
extractorFactory
;
private
final
HlsExtractorFactory
extractorFactory
;
private
final
MediaItem
mediaItem
;
private
final
MediaItem
.
PlaybackProperties
playbackProperties
;
private
final
MediaItem
.
PlaybackProperties
playbackProperties
;
private
final
HlsDataSourceFactory
dataSourceFactory
;
private
final
HlsDataSourceFactory
dataSourceFactory
;
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
...
@@ -386,7 +403,9 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -386,7 +403,9 @@ public final class HlsMediaSource extends BaseMediaSource
private
final
@MetadataType
int
metadataType
;
private
final
@MetadataType
int
metadataType
;
private
final
boolean
useSessionKeys
;
private
final
boolean
useSessionKeys
;
private
final
HlsPlaylistTracker
playlistTracker
;
private
final
HlsPlaylistTracker
playlistTracker
;
private
final
long
elapsedRealTimeOffsetMs
;
private
MediaItem
mediaItem
;
@Nullable
private
TransferListener
mediaTransferListener
;
@Nullable
private
TransferListener
mediaTransferListener
;
private
HlsMediaSource
(
private
HlsMediaSource
(
...
@@ -397,6 +416,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -397,6 +416,7 @@ public final class HlsMediaSource extends BaseMediaSource
DrmSessionManager
drmSessionManager
,
DrmSessionManager
drmSessionManager
,
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
,
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
,
HlsPlaylistTracker
playlistTracker
,
HlsPlaylistTracker
playlistTracker
,
long
elapsedRealTimeOffsetMs
,
boolean
allowChunklessPreparation
,
boolean
allowChunklessPreparation
,
@MetadataType
int
metadataType
,
@MetadataType
int
metadataType
,
boolean
useSessionKeys
)
{
boolean
useSessionKeys
)
{
...
@@ -408,6 +428,7 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -408,6 +428,7 @@ public final class HlsMediaSource extends BaseMediaSource
this
.
drmSessionManager
=
drmSessionManager
;
this
.
drmSessionManager
=
drmSessionManager
;
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
playlistTracker
=
playlistTracker
;
this
.
playlistTracker
=
playlistTracker
;
this
.
elapsedRealTimeOffsetMs
=
elapsedRealTimeOffsetMs
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
metadataType
=
metadataType
;
this
.
metadataType
=
metadataType
;
this
.
useSessionKeys
=
useSessionKeys
;
this
.
useSessionKeys
=
useSessionKeys
;
...
@@ -491,25 +512,28 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -491,25 +512,28 @@ public final class HlsMediaSource extends BaseMediaSource
HlsManifest
manifest
=
HlsManifest
manifest
=
new
HlsManifest
(
checkNotNull
(
playlistTracker
.
getMasterPlaylist
()),
playlist
);
new
HlsManifest
(
checkNotNull
(
playlistTracker
.
getMasterPlaylist
()),
playlist
);
if
(
playlistTracker
.
isLive
())
{
if
(
playlistTracker
.
isLive
())
{
long
liveEdgeOffsetUs
=
getLiveEdgeOffsetUs
(
playlist
);
long
targetLiveOffsetUs
=
mediaItem
.
liveConfiguration
.
targetLiveOffsetMs
!=
C
.
TIME_UNSET
?
C
.
msToUs
(
mediaItem
.
liveConfiguration
.
targetLiveOffsetMs
)
:
getTargetLiveOffsetUs
(
playlist
,
liveEdgeOffsetUs
);
// Ensure target live offset is within the live window and greater than the live edge offset.
targetLiveOffsetUs
=
Util
.
constrainValue
(
targetLiveOffsetUs
,
liveEdgeOffsetUs
,
playlist
.
durationUs
+
liveEdgeOffsetUs
);
maybeUpdateMediaItem
(
targetLiveOffsetUs
);
long
offsetFromInitialStartTimeUs
=
long
offsetFromInitialStartTimeUs
=
playlist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
playlist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
long
periodDurationUs
=
long
periodDurationUs
=
playlist
.
hasEndTag
?
offsetFromInitialStartTimeUs
+
playlist
.
durationUs
:
C
.
TIME_UNSET
;
playlist
.
hasEndTag
?
offsetFromInitialStartTimeUs
+
playlist
.
durationUs
:
C
.
TIME_UNSET
;
List
<
HlsMediaPlaylist
.
Segment
>
segments
=
playlist
.
segments
;
List
<
HlsMediaPlaylist
.
Segment
>
segments
=
playlist
.
segments
;
if
(
windowDefaultStartPositionUs
==
C
.
TIME_UNSET
)
{
windowDefaultStartPositionUs
=
0
;
if
(!
segments
.
isEmpty
())
{
if
(!
segments
.
isEmpty
())
{
int
defaultStartSegmentIndex
=
max
(
0
,
segments
.
size
()
-
3
);
windowDefaultStartPositionUs
=
getWindowDefaultStartPosition
(
playlist
,
liveEdgeOffsetUs
);
// We attempt to set the default start position to be at least twice the target duration
}
else
if
(
windowDefaultStartPositionUs
==
C
.
TIME_UNSET
)
{
// behind the live edge.
windowDefaultStartPositionUs
=
0
;
long
minStartPositionUs
=
playlist
.
durationUs
-
playlist
.
targetDurationUs
*
2
;
while
(
defaultStartSegmentIndex
>
0
&&
segments
.
get
(
defaultStartSegmentIndex
).
relativeStartTimeUs
>
minStartPositionUs
)
{
defaultStartSegmentIndex
--;
}
windowDefaultStartPositionUs
=
segments
.
get
(
defaultStartSegmentIndex
).
relativeStartTimeUs
;
}
}
}
timeline
=
timeline
=
new
SinglePeriodTimeline
(
new
SinglePeriodTimeline
(
presentationStartTimeMs
,
presentationStartTimeMs
,
...
@@ -545,4 +569,47 @@ public final class HlsMediaSource extends BaseMediaSource
...
@@ -545,4 +569,47 @@ public final class HlsMediaSource extends BaseMediaSource
}
}
refreshSourceInfo
(
timeline
);
refreshSourceInfo
(
timeline
);
}
}
private
long
getLiveEdgeOffsetUs
(
HlsMediaPlaylist
playlist
)
{
return
playlist
.
hasProgramDateTime
?
C
.
msToUs
(
Util
.
getNowUnixTimeMs
(
elapsedRealTimeOffsetMs
))
-
playlist
.
getEndTimeUs
()
:
0
;
}
private
long
getWindowDefaultStartPosition
(
HlsMediaPlaylist
playlist
,
long
liveEdgeOffsetUs
)
{
List
<
HlsMediaPlaylist
.
Segment
>
segments
=
playlist
.
segments
;
int
segmentIndex
=
segments
.
size
()
-
1
;
long
minStartPositionUs
=
playlist
.
durationUs
+
liveEdgeOffsetUs
-
C
.
msToUs
(
mediaItem
.
liveConfiguration
.
targetLiveOffsetMs
);
while
(
segmentIndex
>
0
&&
segments
.
get
(
segmentIndex
).
relativeStartTimeUs
>
minStartPositionUs
)
{
segmentIndex
--;
}
return
segments
.
get
(
segmentIndex
).
relativeStartTimeUs
;
}
private
void
maybeUpdateMediaItem
(
long
targetLiveOffsetUs
)
{
long
targetLiveOffsetMs
=
C
.
usToMs
(
targetLiveOffsetUs
);
if
(
targetLiveOffsetMs
!=
mediaItem
.
liveConfiguration
.
targetLiveOffsetMs
)
{
mediaItem
=
mediaItem
.
buildUpon
().
setLiveTargetOffsetMs
(
targetLiveOffsetMs
).
build
();
}
}
private
static
long
getTargetLiveOffsetUs
(
HlsMediaPlaylist
playlist
,
long
liveEdgeOffsetUs
)
{
HlsMediaPlaylist
.
ServerControl
serverControl
=
playlist
.
serverControl
;
// Select part hold back only if the playlist has a part target duration.
long
offsetToEndOfPlaylistUs
;
if
(
serverControl
.
partHoldBackUs
!=
C
.
TIME_UNSET
&&
playlist
.
partTargetDurationUs
!=
C
.
TIME_UNSET
)
{
offsetToEndOfPlaylistUs
=
serverControl
.
partHoldBackUs
;
}
else
if
(
serverControl
.
holdBackUs
!=
C
.
TIME_UNSET
)
{
offsetToEndOfPlaylistUs
=
serverControl
.
holdBackUs
;
}
else
{
// Fallback, see RFC 8216, Section 4.4.3.8.
offsetToEndOfPlaylistUs
=
3
*
playlist
.
targetDurationUs
;
}
return
offsetToEndOfPlaylistUs
+
liveEdgeOffsetUs
;
}
}
}
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaSourceTest.java
View file @
42a2b923
This diff is collapsed.
Click to expand it.
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