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
Hide 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 @@
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
annotation
.
RetentionPolicy
.
SOURCE
;
import
android.net.Uri
;
import
android.os.SystemClock
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.MediaItem
;
...
...
@@ -52,6 +53,7 @@ import com.google.android.exoplayer2.upstream.HttpDataSource;
import
com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy
;
import
com.google.android.exoplayer2.upstream.TransferListener
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.Util
;
import
java.io.IOException
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
...
...
@@ -87,7 +89,6 @@ public final class HlsMediaSource extends BaseMediaSource
public
static
final
int
METADATA_TYPE_ID3
=
1
;
/** Type for ESMG metadata in HLS streams. */
public
static
final
int
METADATA_TYPE_EMSG
=
3
;
/** Factory for {@link HlsMediaSource}s. */
public
static
final
class
Factory
implements
MediaSourceFactory
{
...
...
@@ -105,6 +106,7 @@ public final class HlsMediaSource extends BaseMediaSource
private
boolean
useSessionKeys
;
private
List
<
StreamKey
>
streamKeys
;
@Nullable
private
Object
tag
;
private
long
elapsedRealTimeOffsetMs
;
/**
* Creates a new factory for {@link HlsMediaSource}s.
...
...
@@ -133,6 +135,7 @@ public final class HlsMediaSource extends BaseMediaSource
compositeSequenceableLoaderFactory
=
new
DefaultCompositeSequenceableLoaderFactory
();
metadataType
=
METADATA_TYPE_ID3
;
streamKeys
=
Collections
.
emptyList
();
elapsedRealTimeOffsetMs
=
C
.
TIME_UNSET
;
}
/**
...
...
@@ -316,6 +319,20 @@ public final class HlsMediaSource extends BaseMediaSource
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. */
@SuppressWarnings
(
"deprecation"
)
@Deprecated
...
...
@@ -364,6 +381,7 @@ public final class HlsMediaSource extends BaseMediaSource
loadErrorHandlingPolicy
,
playlistTrackerFactory
.
createTracker
(
hlsDataSourceFactory
,
loadErrorHandlingPolicy
,
playlistParserFactory
),
elapsedRealTimeOffsetMs
,
allowChunklessPreparation
,
metadataType
,
useSessionKeys
);
...
...
@@ -376,7 +394,6 @@ public final class HlsMediaSource extends BaseMediaSource
}
private
final
HlsExtractorFactory
extractorFactory
;
private
final
MediaItem
mediaItem
;
private
final
MediaItem
.
PlaybackProperties
playbackProperties
;
private
final
HlsDataSourceFactory
dataSourceFactory
;
private
final
CompositeSequenceableLoaderFactory
compositeSequenceableLoaderFactory
;
...
...
@@ -386,7 +403,9 @@ public final class HlsMediaSource extends BaseMediaSource
private
final
@MetadataType
int
metadataType
;
private
final
boolean
useSessionKeys
;
private
final
HlsPlaylistTracker
playlistTracker
;
private
final
long
elapsedRealTimeOffsetMs
;
private
MediaItem
mediaItem
;
@Nullable
private
TransferListener
mediaTransferListener
;
private
HlsMediaSource
(
...
...
@@ -397,6 +416,7 @@ public final class HlsMediaSource extends BaseMediaSource
DrmSessionManager
drmSessionManager
,
LoadErrorHandlingPolicy
loadErrorHandlingPolicy
,
HlsPlaylistTracker
playlistTracker
,
long
elapsedRealTimeOffsetMs
,
boolean
allowChunklessPreparation
,
@MetadataType
int
metadataType
,
boolean
useSessionKeys
)
{
...
...
@@ -408,6 +428,7 @@ public final class HlsMediaSource extends BaseMediaSource
this
.
drmSessionManager
=
drmSessionManager
;
this
.
loadErrorHandlingPolicy
=
loadErrorHandlingPolicy
;
this
.
playlistTracker
=
playlistTracker
;
this
.
elapsedRealTimeOffsetMs
=
elapsedRealTimeOffsetMs
;
this
.
allowChunklessPreparation
=
allowChunklessPreparation
;
this
.
metadataType
=
metadataType
;
this
.
useSessionKeys
=
useSessionKeys
;
...
...
@@ -491,25 +512,28 @@ public final class HlsMediaSource extends BaseMediaSource
HlsManifest
manifest
=
new
HlsManifest
(
checkNotNull
(
playlistTracker
.
getMasterPlaylist
()),
playlist
);
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
=
playlist
.
startTimeUs
-
playlistTracker
.
getInitialStartTimeUs
();
long
periodDurationUs
=
playlist
.
hasEndTag
?
offsetFromInitialStartTimeUs
+
playlist
.
durationUs
:
C
.
TIME_UNSET
;
List
<
HlsMediaPlaylist
.
Segment
>
segments
=
playlist
.
segments
;
if
(
windowDefaultStartPositionUs
==
C
.
TIME_UNSET
)
{
if
(!
segments
.
isEmpty
())
{
windowDefaultStartPositionUs
=
getWindowDefaultStartPosition
(
playlist
,
liveEdgeOffsetUs
);
}
else
if
(
windowDefaultStartPositionUs
==
C
.
TIME_UNSET
)
{
windowDefaultStartPositionUs
=
0
;
if
(!
segments
.
isEmpty
())
{
int
defaultStartSegmentIndex
=
max
(
0
,
segments
.
size
()
-
3
);
// We attempt to set the default start position to be at least twice the target duration
// behind the live edge.
long
minStartPositionUs
=
playlist
.
durationUs
-
playlist
.
targetDurationUs
*
2
;
while
(
defaultStartSegmentIndex
>
0
&&
segments
.
get
(
defaultStartSegmentIndex
).
relativeStartTimeUs
>
minStartPositionUs
)
{
defaultStartSegmentIndex
--;
}
windowDefaultStartPositionUs
=
segments
.
get
(
defaultStartSegmentIndex
).
relativeStartTimeUs
;
}
}
timeline
=
new
SinglePeriodTimeline
(
presentationStartTimeMs
,
...
...
@@ -545,4 +569,47 @@ public final class HlsMediaSource extends BaseMediaSource
}
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