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
Show 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 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
/** Default implementation for {@link HlsPlaylistParserFactory}. */
...
...
@@ -27,7 +28,7 @@ public final class DefaultHlsPlaylistParserFactory implements HlsPlaylistParserF
@Override
public
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
)
{
return
new
HlsPlaylistParser
(
masterPlaylist
);
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
)
{
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
private
final
List
<
PlaylistEventListener
>
listeners
;
private
final
double
playlistStuckTargetDurationCoefficient
;
@Nullable
private
ParsingLoadable
.
Parser
<
HlsPlaylist
>
mediaPlaylistParser
;
@Nullable
private
EventDispatcher
eventDispatcher
;
@Nullable
private
Loader
initialPlaylistLoader
;
@Nullable
private
Handler
playlistRefreshHandler
;
...
...
@@ -243,7 +242,6 @@ public final class DefaultHlsPlaylistTracker
masterPlaylist
=
(
HlsMasterPlaylist
)
result
;
}
this
.
masterPlaylist
=
masterPlaylist
;
mediaPlaylistParser
=
playlistParserFactory
.
createPlaylistParser
(
masterPlaylist
);
primaryMediaPlaylistUrl
=
masterPlaylist
.
variants
.
get
(
0
).
url
;
createBundles
(
masterPlaylist
.
mediaPlaylistUrls
);
LoadEventInfo
loadEventInfo
=
...
...
@@ -671,6 +669,8 @@ public final class DefaultHlsPlaylistTracker
}
private
void
loadPlaylistImmediately
(
Uri
playlistRequestUri
)
{
ParsingLoadable
.
Parser
<
HlsPlaylist
>
mediaPlaylistParser
=
playlistParserFactory
.
createPlaylistParser
(
masterPlaylist
,
playlistSnapshot
);
ParsingLoadable
<
HlsPlaylist
>
mediaPlaylistLoadable
=
new
ParsingLoadable
<>(
mediaPlaylistDataSource
,
...
...
@@ -691,10 +691,6 @@ public final class DefaultHlsPlaylistTracker
private
void
processLoadedPlaylist
(
HlsMediaPlaylist
loadedPlaylist
,
LoadEventInfo
loadEventInfo
)
{
@Nullable
HlsMediaPlaylist
oldPlaylist
=
playlistSnapshot
;
loadedPlaylist
=
loadedPlaylist
.
skippedSegmentCount
>
0
?
loadedPlaylist
.
expandSkippedSegments
(
checkNotNull
(
playlistSnapshot
))
:
loadedPlaylist
;
long
currentTimeMs
=
SystemClock
.
elapsedRealtime
();
lastSnapshotLoadMs
=
currentTimeMs
;
playlistSnapshot
=
getLatestPlaylistSnapshot
(
oldPlaylist
,
loadedPlaylist
);
...
...
@@ -759,9 +755,7 @@ public final class DefaultHlsPlaylistTracker
Uri
.
Builder
uriBuilder
=
playlistUrl
.
buildUpon
();
if
(
playlistSnapshot
.
serverControl
.
canBlockReload
)
{
long
targetMediaSequence
=
playlistSnapshot
.
mediaSequence
+
playlistSnapshot
.
segments
.
size
()
+
playlistSnapshot
.
skippedSegmentCount
;
playlistSnapshot
.
mediaSequence
+
playlistSnapshot
.
segments
.
size
();
uriBuilder
.
appendQueryParameter
(
BLOCK_MSN_PARAM
,
String
.
valueOf
(
targetMediaSequence
));
if
(
playlistSnapshot
.
partTargetDurationUs
!=
C
.
TIME_UNSET
)
{
List
<
Part
>
trailingParts
=
playlistSnapshot
.
trailingParts
;
...
...
@@ -774,9 +768,8 @@ public final class DefaultHlsPlaylistTracker
}
}
if
(
playlistSnapshot
.
serverControl
.
skipUntilUs
!=
C
.
TIME_UNSET
)
{
// TODO: Fix skipped segment merging before re-enabling.
// uriBuilder.appendQueryParameter(
// SKIP_PARAM, playlistSnapshot.serverControl.canSkipDateRanges ? "v2" : "YES");
uriBuilder
.
appendQueryParameter
(
SKIP_PARAM
,
playlistSnapshot
.
serverControl
.
canSkipDateRanges
?
"v2"
:
"YES"
);
}
return
uriBuilder
.
build
();
}
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/FilteringHlsPlaylistParserFactory.java
View file @
b05fa731
...
...
@@ -15,6 +15,7 @@
*/
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.StreamKey
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
...
...
@@ -48,8 +49,9 @@ public final class FilteringHlsPlaylistParserFactory implements HlsPlaylistParse
@Override
public
ParsingLoadable
.
Parser
<
HlsPlaylist
>
createPlaylistParser
(
HlsMasterPlaylist
masterPlaylist
)
{
HlsMasterPlaylist
masterPlaylist
,
@Nullable
HlsMediaPlaylist
previousMediaPlaylist
)
{
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 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
android.net.Uri
;
import
androidx.annotation.IntDef
;
...
...
@@ -170,6 +169,30 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
title
=
title
;
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. */
...
...
@@ -226,6 +249,23 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
isIndependent
=
isIndependent
;
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. */
...
...
@@ -405,8 +445,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* The list of segments in the playlist.
*/
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.
*/
...
...
@@ -434,7 +472,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @param hasProgramDateTime See {@link #hasProgramDateTime}.
* @param protectionSchemes See {@link #protectionSchemes}.
* @param segments See {@link #segments}.
* @param skippedSegmentCount See {@link #skippedSegmentCount}.
* @param trailingParts See {@link #trailingParts}.
* @param serverControl See {@link #serverControl}
* @param renditionReports See {@link #renditionReports}.
...
...
@@ -456,7 +493,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
boolean
hasProgramDateTime
,
@Nullable
DrmInitData
protectionSchemes
,
List
<
Segment
>
segments
,
int
skippedSegmentCount
,
List
<
Part
>
trailingParts
,
ServerControl
serverControl
,
Map
<
Uri
,
RenditionReport
>
renditionReports
)
{
...
...
@@ -473,7 +509,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
hasProgramDateTime
=
hasProgramDateTime
;
this
.
protectionSchemes
=
protectionSchemes
;
this
.
segments
=
ImmutableList
.
copyOf
(
segments
);
this
.
skippedSegmentCount
=
skippedSegmentCount
;
this
.
trailingParts
=
ImmutableList
.
copyOf
(
trailingParts
);
this
.
renditionReports
=
ImmutableMap
.
copyOf
(
renditionReports
);
if
(!
trailingParts
.
isEmpty
())
{
...
...
@@ -509,10 +544,9 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
return
false
;
}
// The media sequences are equal.
int
segmentCount
=
segments
.
size
()
+
skippedSegmentCount
;
int
otherSegmentCount
=
other
.
segments
.
size
()
+
other
.
skippedSegmentCount
;
if
(
segmentCount
!=
otherSegmentCount
)
{
return
segmentCount
>
otherSegmentCount
;
int
segmentCountDifference
=
segments
.
size
()
-
other
.
segments
.
size
();
if
(
segmentCountDifference
!=
0
)
{
return
segmentCountDifference
>
0
;
}
int
partCount
=
trailingParts
.
size
();
int
otherPartCount
=
other
.
trailingParts
.
size
();
...
...
@@ -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
* and {@code hasDiscontinuitySequence} values. The first two are set to the specified values,
* {@code hasDiscontinuitySequence} is set to true.
...
...
@@ -600,7 +588,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
hasProgramDateTime
,
protectionSchemes
,
segments
,
skippedSegmentCount
,
trailingParts
,
serverControl
,
renditionReports
);
...
...
@@ -631,7 +618,6 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
hasProgramDateTime
,
protectionSchemes
,
segments
,
skippedSegmentCount
,
trailingParts
,
serverControl
,
renditionReports
);
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
View file @
b05fa731
...
...
@@ -16,6 +16,8 @@
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
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Util
.
castNonNull
;
import
android.net.Uri
;
import
android.text.TextUtils
;
...
...
@@ -211,13 +213,14 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
Pattern
.
compile
(
"\\{\\$([a-zA-Z0-9\\-_]+)\\}"
);
private
final
HlsMasterPlaylist
masterPlaylist
;
@Nullable
private
final
HlsMediaPlaylist
previousMediaPlaylist
;
/**
* Creates an instance where media playlists are parsed without inheriting attributes from a
* master playlist.
*/
public
HlsPlaylistParser
()
{
this
(
HlsMasterPlaylist
.
EMPTY
);
this
(
HlsMasterPlaylist
.
EMPTY
,
/* previousMediaPlaylist= */
null
);
}
/**
...
...
@@ -225,9 +228,13 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
* playlist.
*
* @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
.
previousMediaPlaylist
=
previousMediaPlaylist
;
}
@Override
...
...
@@ -257,7 +264,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
||
line
.
equals
(
TAG_ENDLIST
))
{
extraLines
.
add
(
line
);
return
parseMediaPlaylist
(
masterPlaylist
,
new
LineIterator
(
extraLines
,
reader
),
uri
.
toString
());
masterPlaylist
,
previousMediaPlaylist
,
new
LineIterator
(
extraLines
,
reader
),
uri
.
toString
());
}
else
{
extraLines
.
add
(
line
);
}
...
...
@@ -603,7 +613,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
}
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
;
long
startOffsetUs
=
C
.
TIME_UNSET
;
long
mediaSequence
=
0
;
...
...
@@ -642,7 +656,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
/* holdBackUs= */
C
.
TIME_UNSET
,
/* partHoldBackUs= */
C
.
TIME_UNSET
,
/* canBlockReload= */
false
);
int
skippedSegmentCount
=
0
;
@Nullable
DrmInitData
playlistProtectionSchemes
=
null
;
@Nullable
String
fullSegmentEncryptionKeyUri
=
null
;
...
...
@@ -727,7 +740,41 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
(
long
)
(
parseDoubleAttr
(
line
,
REGEX_MEDIA_DURATION
)
*
C
.
MICROS_PER_SECOND
);
segmentTitle
=
parseOptionalStringAttr
(
line
,
REGEX_MEDIA_TITLE
,
""
,
variableDefinitions
);
}
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
))
{
String
method
=
parseStringAttr
(
line
,
REGEX_METHOD
,
variableDefinitions
);
String
keyFormat
=
...
...
@@ -972,7 +1019,6 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
/* hasProgramDateTime= */
playlistStartTimeUs
!=
0
,
playlistProtectionSchemes
,
segments
,
skippedSegmentCount
,
trailingParts
,
serverControl
,
renditionReports
);
...
...
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParserFactory.java
View file @
b05fa731
...
...
@@ -15,6 +15,7 @@
*/
package
com
.
google
.
android
.
exoplayer2
.
source
.
hls
.
playlist
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
/** Factory for {@link HlsPlaylist} parsers. */
...
...
@@ -32,7 +33,10 @@ public interface HlsPlaylistParserFactory {
* {@code masterPlaylist}.
*
* @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.
*/
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;
import
com.google.android.exoplayer2.source.MediaSourceEventListener
;
import
com.google.android.exoplayer2.testutil.TestUtil
;
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
java.io.IOException
;
import
java.util.ArrayList
;
...
...
@@ -116,7 +116,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -128,14 +128,12 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
firstFullPlaylist
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
secondFullPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
secondFullPlaylist
.
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
secondFullPlaylist
.
skippedSegmentCount
).
isEqualTo
(
0
);
assertThat
(
secondFullPlaylist
.
segments
.
get
(
0
).
url
).
isEqualTo
(
"fileSequence11.ts"
);
assertThat
(
secondFullPlaylist
.
segments
.
get
(
5
).
url
).
isEqualTo
(
"fileSequence16.ts"
);
assertThat
(
secondFullPlaylist
.
segments
).
hasSize
(
6
);
assertThat
(
secondFullPlaylist
.
segments
).
containsNoneIn
(
firstFullPlaylist
.
segments
);
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
public
void
start_playlistCanSkip_requestsDeltaUpdateAndExpandsSkippedSegments
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
...
@@ -150,7 +148,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -160,14 +158,14 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
11
);
assertThat
(
mergedPlaylist
.
skippedSegmentCount
).
isEqualTo
(
0
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
6
);
// First 2 segments of the merged playlist need to be copied from the previous playlist.
assertThat
(
mergedPlaylist
.
segments
.
subList
(
0
,
2
))
.
containsExactlyElementsIn
(
initialPlaylistWithAllSegments
.
segments
.
subList
(
1
,
3
))
.
inOrder
();
assertThat
(
mergedPlaylist
.
segments
.
get
(
2
).
url
)
.
isEqualTo
(
initialPlaylistWithAllSegments
.
segments
.
get
(
3
).
url
);
assertThat
(
mergedPlaylist
.
segments
.
get
(
0
).
url
)
.
isEqualTo
(
initialPlaylistWithAllSegments
.
segments
.
get
(
1
).
url
);
assertThat
(
mergedPlaylist
.
segments
.
get
(
0
).
relativeStartTimeUs
).
isEqualTo
(
0
);
assertThat
(
mergedPlaylist
.
segments
.
get
(
1
).
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.
...
...
@@ -185,7 +183,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -195,11 +193,9 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
initialPlaylistWithAllSegments
.
segments
).
hasSize
(
6
);
HlsMediaPlaylist
mergedPlaylist
=
mediaPlaylists
.
get
(
1
);
assertThat
(
mergedPlaylist
.
mediaSequence
).
isEqualTo
(
22
);
assertThat
(
mergedPlaylist
.
skippedSegmentCount
).
isEqualTo
(
0
);
assertThat
(
mergedPlaylist
.
segments
).
hasSize
(
4
);
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
public
void
start_playlistCanSkipDataRanges_requestsDeltaUpdateV2
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
...
@@ -214,7 +210,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -224,7 +220,6 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
mediaPlaylists
.
get
(
1
).
mediaSequence
).
isEqualTo
(
11
);
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
public
void
start_playlistCanSkipAndUriWithParams_preservesOriginalParams
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
...
@@ -241,7 +236,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -266,7 +261,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -292,7 +287,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -321,7 +316,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -352,7 +347,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
new
DefaultHttpDataSourceFactory
(),
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* awaitedMediaPlaylistCount= */
2
);
...
...
@@ -365,7 +360,6 @@ public class DefaultHlsPlaylistTrackerTest {
assertThat
(
mediaPlaylists
.
get
(
1
).
trailingParts
).
hasSize
(
2
);
}
@Ignore
// Test disabled because playlist delta updates are temporarily disabled.
@Test
public
void
start_httpBadRequest_forcesFullNonBlockingPlaylistRequest
()
throws
IOException
,
TimeoutException
,
InterruptedException
{
...
...
@@ -386,7 +380,7 @@ public class DefaultHlsPlaylistTrackerTest {
List
<
HlsMediaPlaylist
>
mediaPlaylists
=
runPlaylistTrackerAndCollectMediaPlaylists
(
/* dataSourceFactory= */
new
DefaultHttpDataSourceFactory
(),
/* dataSourceFactory= */
new
DefaultHttpDataSource
.
Factory
(),
Uri
.
parse
(
mockWebServer
.
url
(
"/master.m3u8"
).
toString
()),
/* 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 {
}
@Test
public
void
parseMediaPlaylist_withSkippedSegments_parsesNumberOfSkippedSegments
()
throws
IOException
{
public
void
parseMediaPlaylist_withSkippedSegments_correctlyMergedSegments
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
String
p
reviousP
laylistString
=
"#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:266\n"
+
"#EXT-X-SKIP:SKIPPED-SEGMENTS=1234\n"
+
"#EXT-X-MEDIA-SEQUENCE:263\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence264.mp4\n"
+
"#EXT-X-DISCONTINUITY\n"
+
"#EXTINF:4.00008,\n"
+
"fileSequence265.mp4\n"
+
"#EXTINF:4.00008,\n"
+
"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
));
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
...
...
@@ -1125,7 +1213,9 @@ public class HlsMediaPlaylistParserTest {
/* variableDefinitions= */
Collections
.
emptyMap
(),
/* sessionKeyDrmInitData= */
Collections
.
emptyList
());
HlsMediaPlaylist
playlistWithInheritance
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
masterPlaylist
).
parse
(
playlistUri
,
inputStream
);
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
(
masterPlaylist
,
/* previousMediaPlaylist= */
null
)
.
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlistWithInheritance
.
hasIndependentSegments
).
isTrue
();
}
...
...
@@ -1187,7 +1277,9 @@ public class HlsMediaPlaylistParserTest {
variableDefinitions
,
/* sessionKeyDrmInitData= */
Collections
.
emptyList
());
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
++)
{
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