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
4332dc23
authored
Nov 04, 2020
by
bachinger
Committed by
Andrew Lewis
Nov 06, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Parse HLS #EXT-X-RENDITION-REPORT tag
Issue: #5011 PiperOrigin-RevId: 340621758
parent
ae17e6d6
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
274 additions
and
15 deletions
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/test/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java
View file @
4332dc23
...
...
@@ -17,17 +17,20 @@ 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
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.drm.DrmInitData
;
import
com.google.android.exoplayer2.offline.StreamKey
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableMap
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
/** Represents an HLS media playlist. */
public
final
class
HlsMediaPlaylist
extends
HlsPlaylist
{
...
...
@@ -298,6 +301,36 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
}
/**
* A rendition report for an alternative rendition defined in another media playlist.
*
* <p>See RFC 8216, section 4.4.5.1.4.
*/
public
static
final
class
RenditionReport
{
/** The URI of the media playlist of the reported rendition. */
public
final
Uri
playlistUri
;
/** The last media sequence that is in the playlist of the reported rendition. */
public
final
long
lastMediaSequence
;
/**
* The last part index that is in the playlist of the reported rendition, or {@link
* C#INDEX_UNSET} if the rendition does not contain partial segments.
*/
public
final
int
lastPartIndex
;
/**
* Creates a new instance.
*
* @param playlistUri See {@link #playlistUri}.
* @param lastMediaSequence See {@link #lastMediaSequence}.
* @param lastPartIndex See {@link #lastPartIndex}.
*/
public
RenditionReport
(
Uri
playlistUri
,
long
lastMediaSequence
,
int
lastPartIndex
)
{
this
.
playlistUri
=
playlistUri
;
this
.
lastMediaSequence
=
lastMediaSequence
;
this
.
lastPartIndex
=
lastPartIndex
;
}
}
/**
* Type of the playlist, as defined by #EXT-X-PLAYLIST-TYPE. One of {@link
* #PLAYLIST_TYPE_UNKNOWN}, {@link #PLAYLIST_TYPE_VOD} or {@link #PLAYLIST_TYPE_EVENT}.
*/
...
...
@@ -372,6 +405,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* The list of parts at the end of the playlist for which the segment is not in the playlist yet.
*/
public
final
List
<
Part
>
trailingParts
;
/** The rendition reports of alternative rendition playlists. */
public
final
Map
<
Uri
,
RenditionReport
>
renditionReports
;
/** The total duration of the playlist in microseconds. */
public
final
long
durationUs
;
/** The attributes of the #EXT-X-SERVER-CONTROL header. */
...
...
@@ -396,6 +431,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
* @param skippedSegmentCount See {@link #skippedSegmentCount}.
* @param trailingParts See {@link #trailingParts}.
* @param serverControl See {@link #serverControl}
* @param renditionReports See {@link #renditionReports}.
*/
public
HlsMediaPlaylist
(
@PlaylistType
int
playlistType
,
...
...
@@ -416,7 +452,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
List
<
Segment
>
segments
,
int
skippedSegmentCount
,
List
<
Part
>
trailingParts
,
ServerControl
serverControl
)
{
ServerControl
serverControl
,
Map
<
Uri
,
RenditionReport
>
renditionReports
)
{
super
(
baseUri
,
tags
,
hasIndependentSegments
);
this
.
playlistType
=
playlistType
;
this
.
startTimeUs
=
startTimeUs
;
...
...
@@ -432,6 +469,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
this
.
segments
=
ImmutableList
.
copyOf
(
segments
);
this
.
skippedSegmentCount
=
skippedSegmentCount
;
this
.
trailingParts
=
ImmutableList
.
copyOf
(
trailingParts
);
this
.
renditionReports
=
ImmutableMap
.
copyOf
(
renditionReports
);
if
(!
segments
.
isEmpty
())
{
Segment
last
=
segments
.
get
(
segments
.
size
()
-
1
);
durationUs
=
last
.
relativeStartTimeUs
+
last
.
durationUs
;
...
...
@@ -517,7 +555,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
mergedSegments
,
/* skippedSegmentCount= */
0
,
trailingParts
,
serverControl
);
serverControl
,
renditionReports
);
}
/**
...
...
@@ -549,7 +588,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
segments
,
skippedSegmentCount
,
trailingParts
,
serverControl
);
serverControl
,
renditionReports
);
}
/**
...
...
@@ -579,7 +619,8 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
segments
,
skippedSegmentCount
,
trailingParts
,
serverControl
);
serverControl
,
renditionReports
);
}
}
library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
View file @
4332dc23
...
...
@@ -34,12 +34,14 @@ import com.google.android.exoplayer2.source.hls.HlsTrackMetadataEntry.VariantInf
import
com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Rendition
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Variant
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Part
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.RenditionReport
;
import
com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment
;
import
com.google.android.exoplayer2.upstream.ParsingLoadable
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.UriUtil
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.common.collect.Iterables
;
import
java.io.BufferedReader
;
import
java.io.IOException
;
import
java.io.InputStream
;
...
...
@@ -94,6 +96,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
private
static
final
String
TAG_GAP
=
"#EXT-X-GAP"
;
private
static
final
String
TAG_SKIP
=
"#EXT-X-SKIP"
;
private
static
final
String
TAG_PRELOAD_HINT
=
"#EXT-X-PRELOAD-HINT"
;
private
static
final
String
TAG_RENDITION_REPORT
=
"#EXT-X-RENDITION-REPORT"
;
private
static
final
String
TYPE_AUDIO
=
"AUDIO"
;
private
static
final
String
TYPE_VIDEO
=
"VIDEO"
;
...
...
@@ -155,6 +158,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
+
":([\\d\\.]+)\\b"
);
private
static
final
Pattern
REGEX_MEDIA_TITLE
=
Pattern
.
compile
(
TAG_MEDIA_DURATION
+
":[\\d\\.]+\\b,(.+)"
);
private
static
final
Pattern
REGEX_LAST_MSN
=
Pattern
.
compile
(
"LAST-MSN"
+
"=(\\d+)\\b"
);
private
static
final
Pattern
REGEX_LAST_PART
=
Pattern
.
compile
(
"LAST-PART"
+
"=(\\d+)\\b"
);
private
static
final
Pattern
REGEX_TIME_OFFSET
=
Pattern
.
compile
(
"TIME-OFFSET=(-?[\\d\\.]+)\\b"
);
private
static
final
Pattern
REGEX_BYTERANGE
=
Pattern
.
compile
(
TAG_BYTERANGE
+
":(\\d+(?:@\\d+)?)\\b"
);
...
...
@@ -600,12 +605,13 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
long
partTargetDurationUs
=
C
.
TIME_UNSET
;
boolean
hasIndependentSegmentsTag
=
masterPlaylist
.
hasIndependentSegments
;
boolean
hasEndTag
=
false
;
boolean
seenPreloadPart
=
false
;
@Nullable
Segment
initializationSegment
=
null
;
HashMap
<
String
,
String
>
variableDefinitions
=
new
HashMap
<>();
HashMap
<
String
,
Segment
>
urlToInferredInitSegment
=
new
HashMap
<>();
List
<
Segment
>
segments
=
new
ArrayList
<>();
List
<
Part
>
parts
=
new
ArrayList
<>();
List
<
Part
>
trailingParts
=
new
ArrayList
<>();
@Nullable
Part
preloadPart
=
null
;
Map
<
Uri
,
RenditionReport
>
renditionReports
=
new
HashMap
<>();
List
<
String
>
tags
=
new
ArrayList
<>();
long
segmentDurationUs
=
0
;
...
...
@@ -769,7 +775,22 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
hasIndependentSegmentsTag
=
true
;
}
else
if
(
line
.
equals
(
TAG_ENDLIST
))
{
hasEndTag
=
true
;
}
else
if
(
line
.
startsWith
(
TAG_PRELOAD_HINT
)
&&
!
seenPreloadPart
)
{
}
else
if
(
line
.
startsWith
(
TAG_RENDITION_REPORT
))
{
long
defaultValue
=
mediaSequence
+
segments
.
size
()
-
(
trailingParts
.
isEmpty
()
?
1
:
0
);
long
lastMediaSequence
=
parseOptionalLongAttr
(
line
,
REGEX_LAST_MSN
,
defaultValue
);
List
<
Part
>
lastParts
=
trailingParts
.
isEmpty
()
?
Iterables
.
getLast
(
segments
).
parts
:
trailingParts
;
int
defaultPartIndex
=
partTargetDurationUs
!=
C
.
TIME_UNSET
?
lastParts
.
size
()
-
1
:
C
.
INDEX_UNSET
;
int
lastPartIndex
=
parseOptionalIntAttr
(
line
,
REGEX_LAST_PART
,
defaultPartIndex
);
String
uri
=
parseStringAttr
(
line
,
REGEX_URI
,
variableDefinitions
);
Uri
playlistUri
=
Uri
.
parse
(
UriUtil
.
resolve
(
baseUri
,
uri
));
renditionReports
.
put
(
playlistUri
,
new
RenditionReport
(
playlistUri
,
lastMediaSequence
,
lastPartIndex
));
}
else
if
(
line
.
startsWith
(
TAG_PRELOAD_HINT
))
{
if
(
preloadPart
!=
null
)
{
continue
;
}
String
type
=
parseStringAttr
(
line
,
REGEX_PRELOAD_HINT_TYPE
,
variableDefinitions
);
if
(!
TYPE_PART
.
equals
(
type
))
{
continue
;
...
...
@@ -790,7 +811,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
playlistProtectionSchemes
=
getPlaylistProtectionSchemes
(
encryptionScheme
,
schemeDatas
);
}
}
p
arts
.
add
(
p
reloadPart
=
new
Part
(
url
,
initializationSegment
,
...
...
@@ -803,8 +824,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
byteRangeStart
,
byteRangeLength
,
/* hasGapTag= */
false
,
/* isIndependent= */
false
));
seenPreloadPart
=
true
;
/* isIndependent= */
false
);
}
else
if
(
line
.
startsWith
(
TAG_PART
))
{
@Nullable
String
segmentEncryptionIV
=
...
...
@@ -836,7 +856,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
playlistProtectionSchemes
=
getPlaylistProtectionSchemes
(
encryptionScheme
,
schemeDatas
);
}
}
p
arts
.
add
(
trailingP
arts
.
add
(
new
Part
(
url
,
initializationSegment
,
...
...
@@ -903,12 +923,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
segmentByteRangeOffset
,
segmentByteRangeLength
,
hasGapTag
,
p
arts
));
trailingP
arts
));
segmentStartTimeUs
+=
segmentDurationUs
;
partStartTimeUs
=
segmentStartTimeUs
;
segmentDurationUs
=
0
;
segmentTitle
=
""
;
p
arts
=
new
ArrayList
<>();
trailingP
arts
=
new
ArrayList
<>();
if
(
segmentByteRangeLength
!=
C
.
LENGTH_UNSET
)
{
segmentByteRangeOffset
+=
segmentByteRangeLength
;
}
...
...
@@ -917,6 +937,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
}
}
if
(
preloadPart
!=
null
)
{
trailingParts
.
add
(
preloadPart
);
}
return
new
HlsMediaPlaylist
(
playlistType
,
baseUri
,
...
...
@@ -935,8 +959,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
playlistProtectionSchemes
,
segments
,
skippedSegmentCount
,
parts
,
serverControl
);
trailingParts
,
serverControl
,
renditionReports
);
}
private
static
DrmInitData
getPlaylistProtectionSchemes
(
...
...
library/hls/src/test/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java
View file @
4332dc23
...
...
@@ -637,6 +637,199 @@ public class HlsMediaPlaylistParserTest {
}
@Test
public
void
parseMediaPlaylist_withRenditionReportWithoutPartTargetDuration_lastPartIndexUnset
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=100\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
1
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
100
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
C
.
INDEX_UNSET
);
}
@Test
public
void
parseMediaPlaylist_withRenditionReportWithoutPartTargetDurationWithoutLastMsn_sameLastMsnAsCurrentPlaylist
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\"\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
1
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
266
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
C
.
INDEX_UNSET
);
}
@Test
public
void
parseMediaPlaylist_withRenditionReportLowLatency_parseAllAttributes
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-PART-INF:PART-TARGET=1\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=100,LAST-PART=2\n"
+
"#EXT-X-RENDITION-REPORT:"
+
"URI=\"http://foo.bar/rendition2.m3u8\",LAST-MSN=1000,LAST-PART=3\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
2
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
100
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
2
);
HlsMediaPlaylist
.
RenditionReport
report2
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"http://foo.bar/rendition2.m3u8"
));
assertThat
(
report2
.
lastMediaSequence
).
isEqualTo
(
1000
);
assertThat
(
report2
.
lastPartIndex
).
isEqualTo
(
3
);
}
@Test
public
void
parseMediaPlaylist_withRenditionReportLowLatencyWithoutLastMsn_sameMsnAsCurrentPlaylist
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-PART-INF:PART-TARGET=1\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-PART=2\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
1
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
267
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
2
);
}
@Test
public
void
parseMediaPlaylist_withRenditionReportLowLatencyWithoutLastPartIndex_sameLastPartIndexAsCurrentPlaylist
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-PART-INF:PART-TARGET=1\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=100\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
1
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
100
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
0
);
}
@Test
public
void
parseMediaPlaylist_withRenditionReportLowLatencyWithoutLastPartIndex_ignoredPreloadPart
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-PART-INF:PART-TARGET=1\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
+
"#EXT-X-PRELOAD-HINT:TYPE=PART,URI=\"filePart267.1.ts\"\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=100\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
trailingParts
).
hasSize
(
2
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
1
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
100
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
0
);
}
@Test
public
void
parseMediaPlaylist_withRenditionReportLowLatencyFullSegment_rollingPartIndexUriParam
()
throws
IOException
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
"#EXTM3U\n"
+
"#EXT-X-TARGETDURATION:4\n"
+
"#EXT-X-PART-INF:PART-TARGET=1\n"
+
"#EXT-X-VERSION:6\n"
+
"#EXT-X-MEDIA-SEQUENCE:266\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part266.0.ts\"\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part266.1.ts\"\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part266.2.ts\"\n"
+
"#EXT-X-PART:DURATION=2.00000,URI=\"part266.3.ts\"\n"
+
"#EXTINF:4.00000,\n"
+
"fileSequence266.mp4\n"
+
"#EXT-X-PRELOAD-HINT:TYPE=PART,URI=\"filePart267.0.ts\"\n"
+
"#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\"\n"
;
InputStream
inputStream
=
new
ByteArrayInputStream
(
Util
.
getUtf8Bytes
(
playlistString
));
HlsMediaPlaylist
playlist
=
(
HlsMediaPlaylist
)
new
HlsPlaylistParser
().
parse
(
playlistUri
,
inputStream
);
assertThat
(
playlist
.
renditionReports
).
hasSize
(
1
);
HlsMediaPlaylist
.
RenditionReport
report0
=
playlist
.
renditionReports
.
get
(
Uri
.
parse
(
"https://example.com/rendition0.m3u8"
));
assertThat
(
report0
.
lastMediaSequence
).
isEqualTo
(
266
);
assertThat
(
report0
.
lastPartIndex
).
isEqualTo
(
3
);
}
@Test
public
void
multipleExtXKeysForSingleSegment
()
throws
Exception
{
Uri
playlistUri
=
Uri
.
parse
(
"https://example.com/test.m3u8"
);
String
playlistString
=
...
...
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