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
b05fa731
authored
Jan 07, 2021
by
bachinger
Committed by
Ian Baker
Jan 08, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Propagate segment properties when merging HLS delta updates
Issue: #5011 PiperOrigin-RevId: 350540152
parent
fc3b91c9
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
232 additions
and
114 deletions
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistParserFactory.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/FilteringHlsPlaylistParserFactory.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParserFactory.java
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTrackerTest.java
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistParserFactory.java
View file @
b05fa731
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
/** Default implementation for {@link HlsPlaylistParserFactory}. */
/** Default implementation for {@link HlsPlaylistParserFactory}. */
...
@@ -27,7 +28,7 @@ public final class DefaultHlsPlaylistParserFactory implements HlsPlaylistParserF
...
@@ -27,7 +28,7 @@ public final class DefaultHlsPlaylistParserFactory implements HlsPlaylistParserF
@Override
@Override
public
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
public
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
)
{
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
)
{
return
new
HlsPlaylistParser
(
masterPlaylist
);
return
new
HlsPlaylistParser
(
masterPlaylist
,
previousMediaPlaylist
);
}
}
}
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java
View file @
b05fa731
...
@@ -68,7 +68,6 @@ public final class DefaultHlsPlaylistTracker
...
@@ -68,7 +68,6 @@ public final class DefaultHlsPlaylistTracker
private
final
List
<
PlaylistEventListener
>
listeners
;
private
final
List
<
PlaylistEventListener
>
listeners
;
private
final
double
playlistStuckTargetDurationCoefficient
;
private
final
double
playlistStuckTargetDurationCoefficient
;
@Nullable
private
ParsingLoadable
.
Parser
<
HlsPlaylist
>
mediaPlaylistParser
;
@Nullable
private
EventDispatcher
eventDispatcher
;
@Nullable
private
EventDispatcher
eventDispatcher
;
@Nullable
private
Loader
initialPlaylistLoader
;
@Nullable
private
Loader
initialPlaylistLoader
;
@Nullable
private
Handler
playlistRefreshHandler
;
@Nullable
private
Handler
playlistRefreshHandler
;
...
@@ -243,7 +242,6 @@ public final class DefaultHlsPlaylistTracker
...
@@ -243,7 +242,6 @@ public final class DefaultHlsPlaylistTracker
masterPlaylist
=
(
HlsMasterPlaylist
)
result
;
masterPlaylist
=
(
HlsMasterPlaylist
)
result
;
}
}
this
.
masterPlaylist
=
masterPlaylist
;
this
.
masterPlaylist
=
masterPlaylist
;
mediaPlaylistParser
=
playlistParserFactory
.
createPlaylistParser
(
masterPlaylist
);
primaryMediaPlaylistUrl
=
masterPlaylist
.
variants
.
get
(
0
).
url
;
primaryMediaPlaylistUrl
=
masterPlaylist
.
variants
.
get
(
0
).
url
;
createBundles
(
masterPlaylist
.
mediaPlaylistUrls
);
createBundles
(
masterPlaylist
.
mediaPlaylistUrls
);
LoadEventInfo
loadEventInfo
=
LoadEventInfo
loadEventInfo
=
...
@@ -671,6 +669,8 @@ public final class DefaultHlsPlaylistTracker
...
@@ -671,6 +669,8 @@ public final class DefaultHlsPlaylistTracker
}
}
private
void
loadPlaylistImmediately
(
Uri
playlistRequestUri
)
{
private
void
loadPlaylistImmediately
(
Uri
playlistRequestUri
)
{
ParsingLoadable
.
Parser
<
HlsPlaylist
>
mediaPlaylistParser
=
playlistParserFactory
.
createPlaylistParser
(
masterPlaylist
,
playlistSnapshot
);
ParsingLoadable
<
HlsPlaylist
>
mediaPlaylistLoadable
=
ParsingLoadable
<
HlsPlaylist
>
mediaPlaylistLoadable
=
new
ParsingLoadable
<>(
new
ParsingLoadable
<>(
mediaPlaylistDataSource
,
mediaPlaylistDataSource
,
...
@@ -691,10 +691,6 @@ public final class DefaultHlsPlaylistTracker
...
@@ -691,10 +691,6 @@ public final class DefaultHlsPlaylistTracker
private
void
processLoadedPlaylist
(
private
void
processLoadedPlaylist
(
HlsMediaPlaylist
loadedPlaylist
,
LoadEventInfo
loadEventInfo
)
{
HlsMediaPlaylist
loadedPlaylist
,
LoadEventInfo
loadEventInfo
)
{
@Nullable
HlsMediaPlaylist
oldPlaylist
=
playlistSnapshot
;
@Nullable
HlsMediaPlaylist
oldPlaylist
=
playlistSnapshot
;
loadedPlaylist
=
loadedPlaylist
.
skippedSegmentCount
>
0
?
loadedPlaylist
.
expandSkippedSegments
(
checkNotNull
(
playlistSnapshot
))
:
loadedPlaylist
;
long
currentTimeMs
=
SystemClock
.
elapsedRealtime
();
long
currentTimeMs
=
SystemClock
.
elapsedRealtime
();
lastSnapshotLoadMs
=
currentTimeMs
;
lastSnapshotLoadMs
=
currentTimeMs
;
playlistSnapshot
=
getLatestPlaylistSnapshot
(
oldPlaylist
,
loadedPlaylist
);
playlistSnapshot
=
getLatestPlaylistSnapshot
(
oldPlaylist
,
loadedPlaylist
);
...
@@ -759,9 +755,7 @@ public final class DefaultHlsPlaylistTracker
...
@@ -759,9 +755,7 @@ public final class DefaultHlsPlaylistTracker
Uri
.
Builder
uriBuilder
=
playlistUrl
.
buildUpon
();
Uri
.
Builder
uriBuilder
=
playlistUrl
.
buildUpon
();
if
(
playlistSnapshot
.
serverControl
.
canBlockReload
)
{
if
(
playlistSnapshot
.
serverControl
.
canBlockReload
)
{
long
targetMediaSequence
=
long
targetMediaSequence
=
playlistSnapshot
.
mediaSequence
playlistSnapshot
.
mediaSequence
+
playlistSnapshot
.
segments
.
size
();
+
playlistSnapshot
.
segments
.
size
()
+
playlistSnapshot
.
skippedSegmentCount
;
uriBuilder
.
appendQueryParameter
(
BLOCK_MSN_PARAM
,
String
.
valueOf
(
targetMediaSequence
));
uriBuilder
.
appendQueryParameter
(
BLOCK_MSN_PARAM
,
String
.
valueOf
(
targetMediaSequence
));
if
(
playlistSnapshot
.
partTargetDurationUs
!=
C
.
TIME_UNSET
)
{
if
(
playlistSnapshot
.
partTargetDurationUs
!=
C
.
TIME_UNSET
)
{
List
<
Part
>
trailingParts
=
playlistSnapshot
.
trailingParts
;
List
<
Part
>
trailingParts
=
playlistSnapshot
.
trailingParts
;
...
@@ -774,9 +768,8 @@ public final class DefaultHlsPlaylistTracker
...
@@ -774,9 +768,8 @@ public final class DefaultHlsPlaylistTracker
}
}
}
}
if
(
playlistSnapshot
.
serverControl
.
skipUntilUs
!=
C
.
TIME_UNSET
)
{
if
(
playlistSnapshot
.
serverControl
.
skipUntilUs
!=
C
.
TIME_UNSET
)
{
// TODO: Fix skipped segment merging before re-enabling.
uriBuilder
.
appendQueryParameter
(
// uriBuilder.appendQueryParameter(
SKIP_PARAM
,
playlistSnapshot
.
serverControl
.
canSkipDateRanges
?
"v2"
:
"YES"
);
// SKIP_PARAM, playlistSnapshot.serverControl.canSkipDateRanges ? "v2" : "YES");
}
}
return
uriBuilder
.
build
();
return
uriBuilder
.
build
();
}
}
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/FilteringHlsPlaylistParserFactory.java
View file @
b05fa731
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.offline.FilteringManifestParser
;
import
com.google.android.exoplayer2.offline.FilteringManifestParser
;
import
com.google.android.exoplayer2.offline.StreamKey
;
import
com.google.android.exoplayer2.offline.StreamKey
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
...
@@ -48,8 +49,9 @@ public final class FilteringHlsPlaylistParserFactory implements HlsPlaylistParse
...
@@ -48,8 +49,9 @@ public final class FilteringHlsPlaylistParserFactory implements HlsPlaylistParse
@Override
@Override
public
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
public
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
)
{
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
)
{
return
new
FilteringManifestParser
<>(
return
new
FilteringManifestParser
<>(
hlsPlaylistParserFactory
.
createPlaylistParser
(
masterPlaylist
),
streamKeys
);
hlsPlaylistParserFactory
.
createPlaylistParser
(
masterPlaylist
,
previousMediaPlaylist
),
streamKeys
);
}
}
}
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java
View file @
b05fa731
...
@@ -15,7 +15,6 @@
...
@@ -15,7 +15,6 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
android.net.Uri
;
import
android.net.Uri
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntDef
;
...
@@ -170,6 +169,30 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -170,6 +169,30 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
title
=
title
;
this
.
title
=
title
;
this
.
parts
=
ImmutableList
.
copyOf
(
parts
);
this
.
parts
=
ImmutableList
.
copyOf
(
parts
);
}
}
public
Segment
copyWith
(
long
relativeStartTimeUs
,
int
relativeDiscontinuitySequence
)
{
List
<
Part
>
updatedParts
=
new
ArrayList
<>();
long
relativePartStartTimeUs
=
relativeStartTimeUs
;
for
(
int
i
=
0
;
i
<
parts
.
size
();
i
++)
{
Part
part
=
parts
.
get
(
i
);
updatedParts
.
add
(
part
.
copyWith
(
relativePartStartTimeUs
,
relativeDiscontinuitySequence
));
relativePartStartTimeUs
+=
part
.
durationUs
;
}
return
new
Segment
(
url
,
initializationSegment
,
title
,
durationUs
,
relativeDiscontinuitySequence
,
relativeStartTimeUs
,
drmInitData
,
fullSegmentEncryptionKeyUri
,
encryptionIV
,
byteRangeOffset
,
byteRangeLength
,
hasGapTag
,
updatedParts
);
}
}
}
/** A media part. */
/** A media part. */
...
@@ -226,6 +249,23 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -226,6 +249,23 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
isIndependent
=
isIndependent
;
this
.
isIndependent
=
isIndependent
;
this
.
isPreload
=
isPreload
;
this
.
isPreload
=
isPreload
;
}
}
public
Part
copyWith
(
long
relativeStartTimeUs
,
int
relativeDiscontinuitySequence
)
{
return
new
Part
(
url
,
initializationSegment
,
durationUs
,
relativeDiscontinuitySequence
,
relativeStartTimeUs
,
drmInitData
,
fullSegmentEncryptionKeyUri
,
encryptionIV
,
byteRangeOffset
,
byteRangeLength
,
hasGapTag
,
isIndependent
,
isPreload
);
}
}
}
/** The base for a {@link Segment} or a {@link Part} required for playback. */
/** The base for a {@link Segment} or a {@link Part} required for playback. */
...
@@ -405,8 +445,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -405,8 +445,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* The list of segments in the playlist.
* The list of segments in the playlist.
*/
*/
public
final
List
<
Segment
>
segments
;
public
final
List
<
Segment
>
segments
;
/** The number of skipped segments. */
public
int
skippedSegmentCount
;
/**
/**
* The list of parts at the end of the playlist for which the segment is not in the playlist yet.
* The list of parts at the end of the playlist for which the segment is not in the playlist yet.
*/
*/
...
@@ -434,7 +472,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -434,7 +472,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @param hasProgramDateTime See {@link #hasProgramDateTime}.
* @param hasProgramDateTime See {@link #hasProgramDateTime}.
* @param protectionSchemes See {@link #protectionSchemes}.
* @param protectionSchemes See {@link #protectionSchemes}.
* @param segments See {@link #segments}.
* @param segments See {@link #segments}.
* @param skippedSegmentCount See {@link #skippedSegmentCount}.
* @param trailingParts See {@link #trailingParts}.
* @param trailingParts See {@link #trailingParts}.
* @param serverControl See {@link #serverControl}
* @param serverControl See {@link #serverControl}
* @param renditionReports See {@link #renditionReports}.
* @param renditionReports See {@link #renditionReports}.
...
@@ -456,7 +493,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -456,7 +493,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
boolean
hasProgramDateTime
,
boolean
hasProgramDateTime
,
@Nullable
DrmInitData
protectionSchemes
,
@Nullable
DrmInitData
protectionSchemes
,
List
<
Segment
>
segments
,
List
<
Segment
>
segments
,
int
skippedSegmentCount
,
List
<
Part
>
trailingParts
,
List
<
Part
>
trailingParts
,
ServerControl
serverControl
,
ServerControl
serverControl
,
Map
<
Uri
,
RenditionReport
>
renditionReports
)
{
Map
<
Uri
,
RenditionReport
>
renditionReports
)
{
...
@@ -473,7 +509,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -473,7 +509,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
hasProgramDateTime
=
hasProgramDateTime
;
this
.
hasProgramDateTime
=
hasProgramDateTime
;
this
.
protectionSchemes
=
protectionSchemes
;
this
.
protectionSchemes
=
protectionSchemes
;
this
.
segments
=
ImmutableList
.
copyOf
(
segments
);
this
.
segments
=
ImmutableList
.
copyOf
(
segments
);
this
.
skippedSegmentCount
=
skippedSegmentCount
;
this
.
trailingParts
=
ImmutableList
.
copyOf
(
trailingParts
);
this
.
trailingParts
=
ImmutableList
.
copyOf
(
trailingParts
);
this
.
renditionReports
=
ImmutableMap
.
copyOf
(
renditionReports
);
this
.
renditionReports
=
ImmutableMap
.
copyOf
(
renditionReports
);
if
(!
trailingParts
.
isEmpty
())
{
if
(!
trailingParts
.
isEmpty
())
{
...
@@ -509,10 +544,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -509,10 +544,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
return
false
;
return
false
;
}
}
// The media sequences are equal.
// The media sequences are equal.
int
segmentCount
=
segments
.
size
()
+
skippedSegmentCount
;
int
segmentCountDifference
=
segments
.
size
()
-
other
.
segments
.
size
();
int
otherSegmentCount
=
other
.
segments
.
size
()
+
other
.
skippedSegmentCount
;
if
(
segmentCountDifference
!=
0
)
{
if
(
segmentCount
!=
otherSegmentCount
)
{
return
segmentCountDifference
>
0
;
return
segmentCount
>
otherSegmentCount
;
}
}
int
partCount
=
trailingParts
.
size
();
int
partCount
=
trailingParts
.
size
();
int
otherPartCount
=
other
.
trailingParts
.
size
();
int
otherPartCount
=
other
.
trailingParts
.
size
();
...
@@ -528,52 +562,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -528,52 +562,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
}
}
/**
/**
* Merges the skipped segments of the previous playlist and returns a copy with a {@link
* #skippedSegmentCount} of 0.
*
* @param previousPlaylist The previous playlist with a {@link #skippedSegmentCount} of zero.
* @return A new playlist with a complete list of segments.
*/
public
HlsMediaPlaylist
expandSkippedSegments
(
HlsMediaPlaylist
previousPlaylist
)
{
if
(
skippedSegmentCount
==
0
)
{
return
this
;
}
checkArgument
(
previousPlaylist
.
skippedSegmentCount
==
0
);
List
<
Segment
>
mergedSegments
=
new
ArrayList
<>();
long
mediaSequence
=
this
.
mediaSequence
;
int
startIndex
=
(
int
)
(
mediaSequence
-
previousPlaylist
.
mediaSequence
);
int
endIndex
=
startIndex
+
skippedSegmentCount
;
if
(
startIndex
>=
0
&&
endIndex
<=
previousPlaylist
.
segments
.
size
())
{
mergedSegments
.
addAll
(
previousPlaylist
.
segments
.
subList
(
startIndex
,
endIndex
));
}
else
{
// Adjust the media sequence if the old playlist doesn't contain all of the skipped segments.
mediaSequence
+=
skippedSegmentCount
;
}
mergedSegments
.
addAll
(
segments
);
return
new
HlsMediaPlaylist
(
playlistType
,
baseUri
,
tags
,
startOffsetUs
,
startTimeUs
,
hasDiscontinuitySequence
,
discontinuitySequence
,
mediaSequence
,
version
,
targetDurationUs
,
partTargetDurationUs
,
hasIndependentSegments
,
hasEndTag
,
hasProgramDateTime
,
protectionSchemes
,
mergedSegments
,
/* skippedSegmentCount= */
0
,
trailingParts
,
serverControl
,
renditionReports
);
}
/**
* Returns a playlist identical to this one except for the start time, the discontinuity sequence
* Returns a playlist identical to this one except for the start time, the discontinuity sequence
* and {@code hasDiscontinuitySequence} values. The first two are set to the specified values,
* and {@code hasDiscontinuitySequence} values. The first two are set to the specified values,
* {@code hasDiscontinuitySequence} is set to true.
* {@code hasDiscontinuitySequence} is set to true.
...
@@ -600,7 +588,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -600,7 +588,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
hasProgramDateTime
,
hasProgramDateTime
,
protectionSchemes
,
protectionSchemes
,
segments
,
segments
,
skippedSegmentCount
,
trailingParts
,
trailingParts
,
serverControl
,
serverControl
,
renditionReports
);
renditionReports
);
...
@@ -631,7 +618,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
...
@@ -631,7 +618,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
hasProgramDateTime
,
hasProgramDateTime
,
protectionSchemes
,
protectionSchemes
,
segments
,
segments
,
skippedSegmentCount
,
trailingParts
,
trailingParts
,
serverControl
,
serverControl
,
renditionReports
);
renditionReports
);
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
View file @
b05fa731
...
@@ -16,6 +16,8 @@
...
@@ -16,6 +16,8 @@
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Util
.
castNonNull
;
import
android.net.Uri
;
import
android.net.Uri
;
import
android.text.TextUtils
;
import
android.text.TextUtils
;
...
@@ -211,13 +213,14 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -211,13 +213,14 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
Pattern
.
compile
(
"\\{\\$([a-zA-Z0-9\\-_]+)\\}"
);
Pattern
.
compile
(
"\\{\\$([a-zA-Z0-9\\-_]+)\\}"
);
private
final
HlsMasterPlaylist
masterPlaylist
;
private
final
HlsMasterPlaylist
masterPlaylist
;
@Nullable
private
final
HlsMediaPlaylist
previousMediaPlaylist
;
/**
/**
* Creates an instance where media playlists are parsed without inheriting attributes from a
* Creates an instance where media playlists are parsed without inheriting attributes from a
* master playlist.
* master playlist.
*/
*/
public
HlsPlaylistParser
()
{
public
HlsPlaylistParser
()
{
this
(
HlsMasterPlaylist
.
EMPTY
);
this
(
HlsMasterPlaylist
.
EMPTY
,
/* previousMediaPlaylist= */
null
);
}
}
/**
/**
...
@@ -225,9 +228,13 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -225,9 +228,13 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
* playlist.
* playlist.
*
*
* @param masterPlaylist The master playlist from which media playlists will inherit attributes.
* @param masterPlaylist The master playlist from which media playlists will inherit attributes.
* @param previousMediaPlaylist The previous media playlist from which the new media playlist may
* inherit skipped segments.
*/
*/
public
HlsPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
)
{
public
HlsPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
)
{
this
.
masterPlaylist
=
masterPlaylist
;
this
.
masterPlaylist
=
masterPlaylist
;
this
.
previousMediaPlaylist
=
previousMediaPlaylist
;
}
}
@Override
@Override
...
@@ -257,7 +264,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -257,7 +264,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
||
line
.
equals
(
TAG_ENDLIST
))
{
||
line
.
equals
(
TAG_ENDLIST
))
{
extraLines
.
add
(
line
);
extraLines
.
add
(
line
);
return
parseMediaPlaylist
(
return
parseMediaPlaylist
(
masterPlaylist
,
new
LineIterator
(
extraLines
,
reader
),
uri
.
toString
());
masterPlaylist
,
previousMediaPlaylist
,
new
LineIterator
(
extraLines
,
reader
),
uri
.
toString
());
}
else
{
}
else
{
extraLines
.
add
(
line
);
extraLines
.
add
(
line
);
}
}
...
@@ -603,7 +613,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -603,7 +613,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
}
}
private
static
HlsMediaPlaylist
parseMediaPlaylist
(
private
static
HlsMediaPlaylist
parseMediaPlaylist
(
HlsMasterPlaylist
masterPlaylist
,
LineIterator
iterator
,
String
baseUri
)
throws
IOException
{
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
,
LineIterator
iterator
,
String
baseUri
)
throws
IOException
{
@HlsMediaPlaylist
.
PlaylistType
int
playlistType
=
HlsMediaPlaylist
.
PLAYLIST_TYPE_UNKNOWN
;
@HlsMediaPlaylist
.
PlaylistType
int
playlistType
=
HlsMediaPlaylist
.
PLAYLIST_TYPE_UNKNOWN
;
long
startOffsetUs
=
C
.
TIME_UNSET
;
long
startOffsetUs
=
C
.
TIME_UNSET
;
long
mediaSequence
=
0
;
long
mediaSequence
=
0
;
...
@@ -642,7 +656,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -642,7 +656,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
/* holdBackUs= */
C
.
TIME_UNSET
,
/* holdBackUs= */
C
.
TIME_UNSET
,
/* partHoldBackUs= */
C
.
TIME_UNSET
,
/* partHoldBackUs= */
C
.
TIME_UNSET
,
/* canBlockReload= */
false
);
/* canBlockReload= */
false
);
int
skippedSegmentCount
=
0
;
@Nullable
DrmInitData
playlistProtectionSchemes
=
null
;
@Nullable
DrmInitData
playlistProtectionSchemes
=
null
;
@Nullable
String
fullSegmentEncryptionKeyUri
=
null
;
@Nullable
String
fullSegmentEncryptionKeyUri
=
null
;
...
@@ -727,7 +740,41 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -727,7 +740,41 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
(
long
)
(
parseDoubleAttr
(
line
,
REGEX_MEDIA_DURATION
)
*
C
.
MICROS_PER_SECOND
);
(
long
)
(
parseDoubleAttr
(
line
,
REGEX_MEDIA_DURATION
)
*
C
.
MICROS_PER_SECOND
);
segmentTitle
=
parseOptionalStringAttr
(
line
,
REGEX_MEDIA_TITLE
,
""
,
variableDefinitions
);
segmentTitle
=
parseOptionalStringAttr
(
line
,
REGEX_MEDIA_TITLE
,
""
,
variableDefinitions
);
}
else
if
(
line
.
startsWith
(
TAG_SKIP
))
{
}
else
if
(
line
.
startsWith
(
TAG_SKIP
))
{
skippedSegmentCount
=
parseIntAttr
(
line
,
REGEX_SKIPPED_SEGMENTS
);
int
skippedSegmentCount
=
parseIntAttr
(
line
,
REGEX_SKIPPED_SEGMENTS
);
checkState
(
previousMediaPlaylist
!=
null
&&
segments
.
isEmpty
());
int
startIndex
=
(
int
)
(
mediaSequence
-
castNonNull
(
previousMediaPlaylist
).
mediaSequence
);
int
endIndex
=
startIndex
+
skippedSegmentCount
;
if
(
startIndex
>=
0
&&
endIndex
<=
previousMediaPlaylist
.
segments
.
size
())
{
// Merge only if all skipped segments are available in the previous playlist.
for
(
int
i
=
startIndex
;
i
<
endIndex
;
i
++)
{
Segment
segment
=
previousMediaPlaylist
.
segments
.
get
(
i
);
if
(
mediaSequence
!=
previousMediaPlaylist
.
mediaSequence
)
{
// If the media sequences of the playlists are not the same, we need to recreate the
// object with the updated relative start time and the relative discontinuity
// sequence. With identical playlist media sequences these values do not change.
int
newRelativeDiscontinuitySequence
=
previousMediaPlaylist
.
discontinuitySequence
-
playlistDiscontinuitySequence
+
segment
.
relativeDiscontinuitySequence
;
segment
=
segment
.
copyWith
(
segmentStartTimeUs
,
newRelativeDiscontinuitySequence
);
}
segments
.
add
(
segment
);
segmentStartTimeUs
+=
segment
.
durationUs
;
partStartTimeUs
=
segmentStartTimeUs
;
if
(
segment
.
byteRangeLength
!=
C
.
LENGTH_UNSET
)
{
segmentByteRangeOffset
=
segment
.
byteRangeOffset
+
segment
.
byteRangeLength
;
}
relativeDiscontinuitySequence
=
segment
.
relativeDiscontinuitySequence
;
initializationSegment
=
segment
.
initializationSegment
;
cachedDrmInitData
=
segment
.
drmInitData
;
fullSegmentEncryptionKeyUri
=
segment
.
fullSegmentEncryptionKeyUri
;
if
(
segment
.
encryptionIV
==
null
||
!
segment
.
encryptionIV
.
equals
(
Long
.
toHexString
(
segmentMediaSequence
)))
{
fullSegmentEncryptionIV
=
segment
.
encryptionIV
;
}
segmentMediaSequence
++;
}
}
}
else
if
(
line
.
startsWith
(
TAG_KEY
))
{
}
else
if
(
line
.
startsWith
(
TAG_KEY
))
{
String
method
=
parseStringAttr
(
line
,
REGEX_METHOD
,
variableDefinitions
);
String
method
=
parseStringAttr
(
line
,
REGEX_METHOD
,
variableDefinitions
);
String
keyFormat
=
String
keyFormat
=
...
@@ -972,7 +1019,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
...
@@ -972,7 +1019,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
/* hasProgramDateTime= */
playlistStartTimeUs
!=
0
,
/* hasProgramDateTime= */
playlistStartTimeUs
!=
0
,
playlistProtectionSchemes
,
playlistProtectionSchemes
,
segments
,
segments
,
skippedSegmentCount
,
trailingParts
,
trailingParts
,
serverControl
,
serverControl
,
renditionReports
);
renditionReports
);
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParserFactory.java
View file @
b05fa731
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
/** Factory for {@link HlsPlaylist} parsers. */
/** Factory for {@link HlsPlaylist} parsers. */
...
@@ -32,7 +33,10 @@ public interface HlsPlaylistParserFactory {
...
@@ -32,7 +33,10 @@ public interface HlsPlaylistParserFactory {
* {@code masterPlaylist}.
* {@code masterPlaylist}.
*
*
* @param masterPlaylist The master playlist that referenced any parsed media playlists.
* @param masterPlaylist The master playlist that referenced any parsed media playlists.
* @param previousMediaPlaylist The previous media playlist or null if there is no previous media
* playlist.
* @return A parser for HLS playlists.
* @return A parser for HLS playlists.
*/
*/
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
);
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
);
}
}
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTrackerTest.java
View file @
b05fa731
...
@@ -24,7 +24,7 @@ import com.google.android.exoplayer2.robolectric.RobolectricUtil;
...
@@ -24,7 +24,7 @@ import com.google.android.exoplayer2.robolectric.RobolectricUtil;
import
com.google.android.exoplayer2.source.MediaSourceEventListener
;
import
com.google.android.exoplayer2.source.MediaSourceEventListener
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DataSource
;
import
com.google.android.exoplayer2.upstream.DefaultHttpDataSource
Factory
;
import
com.google.android.exoplayer2.upstream.DefaultHttpDataSource
;
import
com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy
;
import
com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
...
@@ -116,7 +116,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -116,7 +116,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -128,14 +128,12 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -128,14 +128,12 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
firstFullPlaylist
.
segments
).
hasSize
(
6
);
assertThat
(
firstFullPlaylist
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
secondFullPlaylist
=
mediaPlaylists
.
get
(
1
);
HlsMediaPlaylist
secondFullPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
secondFullPlaylist
.
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
secondFullPlaylist
.
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
secondFullPlaylist
.
skippedSegmentCount
).
isEqualTo
(
0
);
assertThat
(
secondFullPlaylist
.
segments
.
get
(
0
).
url
).
isEqualTo
(
"fileSequence11.ts"
);
assertThat
(
secondFullPlaylist
.
segments
.
get
(
0
).
url
).
isEqualTo
(
"fileSequence11.ts"
);
assertThat
(
secondFullPlaylist
.
segments
.
get
(
5
).
url
).
isEqualTo
(
"fileSequence16.ts"
);
assertThat
(
secondFullPlaylist
.
segments
.
get
(
5
).
url
).
isEqualTo
(
"fileSequence16.ts"
);
assertThat
(
secondFullPlaylist
.
segments
).
hasSize
(
6
);
assertThat
(
secondFullPlaylist
.
segments
).
hasSize
(
6
);
assertThat
(
secondFullPlaylist
.
segments
).
containsNoneIn
(
firstFullPlaylist
.
segments
);
assertThat
(
secondFullPlaylist
.
segments
).
containsNoneIn
(
firstFullPlaylist
.
segments
);
}
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
@Test
public
void
start_playlistCanSkip_requestsDeltaUpdateAndExpandsSkippedSegments
()
public
void
start_playlistCanSkip_requestsDeltaUpdateAndExpandsSkippedSegments
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
@@ -150,7 +148,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -150,7 +148,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -160,14 +158,14 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -160,14 +158,14 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
mergedPlaylist
.
skippedSegmentCount
).
isEqualTo
(
0
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
6
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
6
);
// First 2 segments of the merged playlist need to be copied from the previous playlist.
// First 2 segments of the merged playlist need to be copied from the previous playlist.
assertThat
(
mergedPlaylist
.
segments
.
subList
(
0
,
2
))
assertThat
(
mergedPlaylist
.
segments
.
get
(
0
).
url
)
.
containsExactlyElementsIn
(
initialPlaylistWithAllSegments
.
segments
.
subList
(
1
,
3
))
.
isEqualTo
(
initialPlaylistWithAllSegments
.
segments
.
get
(
1
).
url
);
.
inOrder
();
assertThat
(
mergedPlaylist
.
segments
.
get
(
0
).
relativeStartTimeUs
).
isEqualTo
(
0
);
assertThat
(
mergedPlaylist
.
segments
.
get
(
2
).
url
)
assertThat
(
mergedPlaylist
.
segments
.
get
(
1
).
url
)
.
isEqualTo
(
initialPlaylistWithAllSegments
.
segments
.
get
(
3
).
url
);
.
isEqualTo
(
initialPlaylistWithAllSegments
.
segments
.
get
(
2
).
url
);
assertThat
(
mergedPlaylist
.
segments
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
4000000
);
}
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
...
@@ -185,7 +183,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -185,7 +183,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -195,11 +193,9 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -195,11 +193,9 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
22
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
22
);
assertThat
(
mergedPlaylist
.
skippedSegmentCount
).
isEqualTo
(
0
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
4
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
4
);
}
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
@Test
public
void
start_playlistCanSkipDataRanges_requestsDeltaUpdateV2
()
public
void
start_playlistCanSkipDataRanges_requestsDeltaUpdateV2
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
@@ -214,7 +210,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -214,7 +210,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -224,7 +220,6 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -224,7 +220,6 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
mediaPlaylists
.
get
(
1
).
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
mediaPlaylists
.
get
(
1
).
mediaSequence
).
isEqualTo
(
11
);
}
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
@Test
public
void
start_playlistCanSkipAndUriWithParams_preservesOriginalParams
()
public
void
start_playlistCanSkipAndUriWithParams_preservesOriginalParams
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
@@ -241,7 +236,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -241,7 +236,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -266,7 +261,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -266,7 +261,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -292,7 +287,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -292,7 +287,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -321,7 +316,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -321,7 +316,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -352,7 +347,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -352,7 +347,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
/* awaitedMediaPlaylistCount= */
2
);
...
@@ -365,7 +360,6 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -365,7 +360,6 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
mediaPlaylists
.
get
(
1
).
trailingParts
).
hasSize
(
2
);
assertThat
(
mediaPlaylists
.
get
(
1
).
trailingParts
).
hasSize
(
2
);
}
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
@Test
public
void
start_httpBadRequest_forcesFullNonBlockingPlaylistRequest
()
public
void
start_httpBadRequest_forcesFullNonBlockingPlaylistRequest
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
@@ -386,7 +380,7 @@ public class DefaultHlsPlaylistTrackerTest {
...
@@ -386,7 +380,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
runPlaylistTrackerAndCollectMediaPlaylists
(
/* dataSourceFactory= */
new
DefaultHttpDataSourceFactory
(),
/* dataSourceFactory= */
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
3
);
/* awaitedMediaPlaylistCount= */
3
);
...
...
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java
View file @
b05fa731
...
@@ -303,24 +303,112 @@ public class HlsMediaPlaylistParserTest {
...
@@ -303,24 +303,112 @@ public class HlsMediaPlaylistParserTest {
}
}
@Test
@Test
public
void
parseMediaPlaylist_withSkippedSegments_parsesNumberOfSkippedSegments
()
public
void
parseMediaPlaylist_withSkippedSegments_correctlyMergedSegments
()
throws
IOException
{
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
String
p
reviousP
laylistString
=
"#EXTM3U\n"
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-DISCONTINUITY-SEQUENCE:1234\n"
+
"#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24.0\n"
+
"#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24.0\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXT-X-MEDIA-SEQUENCE:263\n"
+
"#EXT-X-SKIP:SKIPPED-SEGMENTS=1234\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence264.mp4\n"
+
"#EXT-X-DISCONTINUITY\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence265.mp4\n"
+
"#EXTINF:4.00008,\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence266.mp4"
;
+
"fileSequence266.mp4"
;
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-DISCONTINUITY-SEQUENCE:1234\n"
+
"#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24.0\n"
+
"#EXT-X-MEDIA-SEQUENCE:265\n"
+
"#EXT-X-SKIP:SKIPPED-SEGMENTS=1\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence266.mp4"
+
"#EXTINF:4.00008,\n"
+
"fileSequence267.mp4\n"
;
InputStream
previousInputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
previousPlaylistString
));
HlsMediaPlaylist
previousPlaylist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
previousInputStream
);
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
HlsMasterPlaylist
.
EMPTY
,
previousPlaylist
)
.
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
segments
).
hasSize
(
3
);
assertThat
(
playlist
.
segments
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
4000079
);
assertThat
(
previousPlaylist
.
segments
.
get
(
0
).
relativeDiscontinuitySequence
).
isEqualTo
(
0
);
assertThat
(
previousPlaylist
.
segments
.
get
(
1
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
previousPlaylist
.
segments
.
get
(
2
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
segments
.
get
(
0
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
segments
.
get
(
1
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
segments
.
get
(
2
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
}
@Test
public
void
parseMediaPlaylist_withSkippedSegments_correctlyMergedParts
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
previousPlaylistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-DISCONTINUITY-SEQUENCE:1234\n"
+
"#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24.0\n"
+
"#EXT-X-MEDIA-SEQUENCE:264\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part264.1.ts\"\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part264.2.ts\"\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence264.mp4\n"
+
"#EXT-X-DISCONTINUITY\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part265.1.ts\"\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part265.2.ts\"\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence265.mp4\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part266.1.ts\"\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part266.2.ts\"\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part267.1.ts\""
;
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-DISCONTINUITY-SEQUENCE:1234\n"
+
"#EXT-X-SERVER-CONTROL:CAN-SKIP-UNTIL=24.0\n"
+
"#EXT-X-MEDIA-SEQUENCE:265\n"
+
"#EXT-X-SKIP:SKIPPED-SEGMENTS=2\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part267.1.ts\""
;
InputStream
previousInputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
previousPlaylistString
));
HlsMediaPlaylist
previousPlaylist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
previousInputStream
);
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
assertThat
(
playlist
.
skippedSegmentCount
).
isEqualTo
(
1234
);
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
HlsMasterPlaylist
.
EMPTY
,
previousPlaylist
)
.
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
segments
).
hasSize
(
2
);
assertThat
(
playlist
.
segments
.
get
(
0
).
relativeStartTimeUs
).
isEqualTo
(
0
);
assertThat
(
playlist
.
segments
.
get
(
0
).
parts
.
get
(
0
).
relativeStartTimeUs
).
isEqualTo
(
0
);
assertThat
(
playlist
.
segments
.
get
(
0
).
parts
.
get
(
0
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
segments
.
get
(
0
).
parts
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
2000000
);
assertThat
(
playlist
.
segments
.
get
(
0
).
parts
.
get
(
1
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
segments
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
4000079
);
assertThat
(
playlist
.
segments
.
get
(
1
).
parts
.
get
(
0
).
relativeStartTimeUs
).
isEqualTo
(
4000079
);
assertThat
(
playlist
.
segments
.
get
(
1
).
parts
.
get
(
1
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
segments
.
get
(
1
).
parts
.
get
(
1
).
relativeStartTimeUs
).
isEqualTo
(
6000079
);
assertThat
(
playlist
.
segments
.
get
(
1
).
parts
.
get
(
1
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
assertThat
(
playlist
.
trailingParts
.
get
(
0
).
relativeStartTimeUs
).
isEqualTo
(
8000158
);
assertThat
(
playlist
.
trailingParts
.
get
(
0
).
relativeDiscontinuitySequence
).
isEqualTo
(
1
);
}
}
@Test
@Test
...
@@ -1125,7 +1213,9 @@ public class HlsMediaPlaylistParserTest {
...
@@ -1125,7 +1213,9 @@ public class HlsMediaPlaylistParserTest {
/* variableDefinitions= */
Collections
.
emptyMap
(),
/* variableDefinitions= */
Collections
.
emptyMap
(),
/* sessionKeyDrmInitData= */
Collections
.
emptyList
());
/* sessionKeyDrmInitData= */
Collections
.
emptyList
());
HlsMediaPlaylist
playlistWithInheritance
=
HlsMediaPlaylist
playlistWithInheritance
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
masterPlaylist
).
parse
(
playlistUri
,
inputStream
);
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
masterPlaylist
,
/* previousMediaPlaylist= */
null
)
.
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlistWithInheritance
.
hasIndependentSegments
).
isTrue
();
assertThat
(
playlistWithInheritance
.
hasIndependentSegments
).
isTrue
();
}
}
...
@@ -1187,7 +1277,9 @@ public class HlsMediaPlaylistParserTest {
...
@@ -1187,7 +1277,9 @@ public class HlsMediaPlaylistParserTest {
variableDefinitions
,
variableDefinitions
,
/* sessionKeyDrmInitData= */
Collections
.
emptyList
());
/* sessionKeyDrmInitData= */
Collections
.
emptyList
());
HlsMediaPlaylist
playlist
=
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
masterPlaylist
).
parse
(
playlistUri
,
inputStream
);
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
masterPlaylist
,
/* previousMediaPlaylist= */
null
)
.
parse
(
playlistUri
,
inputStream
);
for
(
int
i
=
1
;
i
<=
4
;
i
++)
{
for
(
int
i
=
1
;
i
<=
4
;
i
++)
{
assertThat
(
playlist
.
segments
.
get
(
i
-
1
).
url
).
isEqualTo
(
"long_path"
+
i
+
".ts"
);
assertThat
(
playlist
.
segments
.
get
(
i
-
1
).
url
).
isEqualTo
(
"long_path"
+
i
+
".ts"
);
}
}
...
...
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