Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
brainfood
/
videojs-contrib-hls
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
55303704
authored
2015-07-10 16:41:57 -0400
by
David LaPalomento
Browse Files
Options
Browse Files
Tag
Download
Plain Diff
Fix seeks between segments. Improve duration calculation. Closes #339
2 parents
af92753d
e81de1a7
Show whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
621 additions
and
192 deletions
CHANGELOG.md
src/m3u8/m3u8-parser.js
src/playlist-loader.js
src/playlist.js
src/segment-parser.js
src/videojs-hls.js
test/manifest/absoluteUris.js
test/manifest/allowCache.js
test/manifest/allowCacheInvalid.js
test/manifest/brightcove.js
test/manifest/byteRange.js
test/manifest/disallowCache.js
test/manifest/disc-sequence.js
test/manifest/discontinuity.js
test/manifest/domainUris.js
test/manifest/emptyAllowCache.js
test/manifest/emptyMediaSequence.js
test/manifest/emptyPlaylistType.js
test/manifest/emptyTargetDuration.js
test/manifest/encrypted.js
test/manifest/event.js
test/manifest/extXPlaylistTypeInvalidPlaylist.js
test/manifest/extinf.js
test/manifest/invalidAllowCache.js
test/manifest/invalidMediaSequence.js
test/manifest/invalidPlaylistType.js
test/manifest/invalidTargetDuration.js
test/manifest/liveMissingSegmentDuration.js
test/manifest/liveStart30sBefore.js
test/manifest/manifestExtTTargetdurationNegative.js
test/manifest/manifestExtXEndlistEarly.js
test/manifest/manifestNoExtM3u.js
test/manifest/master.js
test/manifest/media.js
test/manifest/mediaSequence.js
test/manifest/missingEndlist.js
test/manifest/missingExtinf.js
test/manifest/missingMediaSequence.js
test/manifest/missingSegmentDuration.js
test/manifest/multipleTargetDurations.js
test/manifest/negativeMediaSequence.js
test/manifest/playlist.js
test/manifest/playlistMediaSequenceHigher.js
test/manifest/streamInfInvalid.js
test/manifest/twoMediaSequences.js
test/manifest/versionInvalid.js
test/manifest/whiteSpace.js
test/playlist_test.js
test/videojs-hls_test.js
CHANGELOG.md
View file @
5530370
...
...
@@ -2,7 +2,7 @@ CHANGELOG
=========
## HEAD (Unreleased)
_(none)_
*
Fix seeks between segments. Improve duration calculation. (
[
view
](
https://github.com/videojs/videojs-contrib-hls/pull/339
)
)
--------------------
...
...
src/m3u8/m3u8-parser.js
View file @
5530370
...
...
@@ -375,7 +375,8 @@
// the manifest is empty until the parse stream begins delivering data
this
.
manifest
=
{
allowCache
:
true
allowCache
:
true
,
discontinuityStarts
:
[]
};
// update the manifest with the m3u8 entry from the parse stream
...
...
@@ -513,6 +514,7 @@
},
'discontinuity'
:
function
()
{
currentUri
.
discontinuity
=
true
;
this
.
manifest
.
discontinuityStarts
.
push
(
uris
.
length
);
},
'targetduration'
:
function
()
{
if
(
!
isFinite
(
entry
.
duration
)
||
entry
.
duration
<
0
)
{
...
...
src/playlist-loader.js
View file @
5530370
...
...
@@ -431,11 +431,12 @@
for
(
i
=
0
;
i
<
this
.
media_
.
segments
.
length
;
i
++
)
{
time
-=
Playlist
.
duration
(
this
.
media_
,
this
.
media_
.
mediaSequence
+
i
,
this
.
media_
.
mediaSequence
+
i
+
1
);
this
.
media_
.
mediaSequence
+
i
+
1
,
false
);
// HLS version 3 and lower round segment durations to the
// nearest decimal integer. When the correct media index is
// ambiguous, prefer the
low
er one.
// ambiguous, prefer the
high
er one.
if
(
time
<=
0
)
{
return
i
;
}
...
...
src/playlist.js
View file @
5530370
...
...
@@ -5,7 +5,130 @@
'use strict'
;
var
DEFAULT_TARGET_DURATION
=
10
;
var
duration
,
seekable
,
segmentsDuration
;
var
accumulateDuration
,
ascendingNumeric
,
duration
,
intervalDuration
,
rangeDuration
,
seekable
;
// Array.sort comparator to sort numbers in ascending order
ascendingNumeric
=
function
(
left
,
right
)
{
return
left
-
right
;
};
/**
* Returns the media duration for the segments between a start and
* exclusive end index. The start and end parameters are interpreted
* as indices into the currently available segments. This method
* does not calculate durations for segments that have expired.
* @param playlist {object} a media playlist object
* @param start {number} an inclusive lower boundary for the
* segments to examine.
* @param end {number} an exclusive upper boundary for the segments
* to examine.
* @param includeTrailingTime {boolean} if false, the interval between
* the final segment and the subsequent segment will not be included
* in the result
* @return {number} the duration between the start index and end
* index in seconds.
*/
accumulateDuration
=
function
(
playlist
,
start
,
end
,
includeTrailingTime
)
{
var
ranges
=
[],
rangeEnds
=
(
playlist
.
discontinuityStarts
||
[]).
concat
(
end
),
result
=
0
,
i
;
// short circuit if start and end don't specify a non-empty range
// of segments
if
(
start
>=
end
)
{
return
0
;
}
// create a range object for each discontinuity sequence
rangeEnds
.
sort
(
ascendingNumeric
);
for
(
i
=
0
;
i
<
rangeEnds
.
length
;
i
++
)
{
if
(
rangeEnds
[
i
]
>
start
)
{
ranges
.
push
({
start
:
start
,
end
:
rangeEnds
[
i
]
});
i
++
;
break
;
}
}
for
(;
i
<
rangeEnds
.
length
;
i
++
)
{
// ignore times ranges later than end
if
(
rangeEnds
[
i
]
>=
end
)
{
ranges
.
push
({
start
:
rangeEnds
[
i
-
1
],
end
:
end
});
break
;
}
ranges
.
push
({
start
:
ranges
[
ranges
.
length
-
1
].
end
,
end
:
rangeEnds
[
i
]
});
}
// add up the durations for each of the ranges
for
(
i
=
0
;
i
<
ranges
.
length
;
i
++
)
{
result
+=
rangeDuration
(
playlist
,
ranges
[
i
],
i
===
ranges
.
length
-
1
&&
includeTrailingTime
);
}
return
result
;
};
/**
* Returns the duration of the specified range of segments. The
* range *must not* cross a discontinuity.
* @param playlist {object} a media playlist object
* @param range {object} an object that specifies a starting and
* ending index into the available segments.
* @param includeTrailingTime {boolean} if false, the interval between
* the final segment and the subsequent segment will not be included
* in the result
* @return {number} the duration of the range in seconds.
*/
rangeDuration
=
function
(
playlist
,
range
,
includeTrailingTime
)
{
var
result
=
0
,
targetDuration
=
playlist
.
targetDuration
||
DEFAULT_TARGET_DURATION
,
segment
,
left
,
right
;
// accumulate while searching for the earliest segment with
// available PTS information
for
(
left
=
range
.
start
;
left
<
range
.
end
;
left
++
)
{
segment
=
playlist
.
segments
[
left
];
if
(
segment
.
minVideoPts
!==
undefined
)
{
break
;
}
result
+=
segment
.
duration
||
targetDuration
;
}
// see if there's enough information to include the trailing time
if
(
includeTrailingTime
)
{
segment
=
playlist
.
segments
[
range
.
end
];
if
(
segment
&&
segment
.
minVideoPts
!==
undefined
)
{
result
+=
0.001
*
(
Math
.
min
(
segment
.
minVideoPts
,
segment
.
minAudioPts
)
-
Math
.
min
(
playlist
.
segments
[
left
].
minVideoPts
,
playlist
.
segments
[
left
].
minAudioPts
));
return
result
;
}
}
// do the same thing while finding the latest segment
for
(
right
=
range
.
end
-
1
;
right
>=
left
;
right
--
)
{
segment
=
playlist
.
segments
[
right
];
if
(
segment
.
maxVideoPts
!==
undefined
)
{
break
;
}
result
+=
segment
.
duration
||
targetDuration
;
}
// add in the PTS interval in seconds between them
if
(
right
>=
left
)
{
result
+=
0.001
*
(
Math
.
max
(
playlist
.
segments
[
right
].
maxVideoPts
,
playlist
.
segments
[
right
].
maxAudioPts
)
-
Math
.
min
(
playlist
.
segments
[
left
].
minVideoPts
,
playlist
.
segments
[
left
].
minAudioPts
));
}
return
result
;
};
/**
* Calculate the media duration from the segments associated with a
...
...
@@ -17,47 +140,28 @@
* boundary for the playlist. Defaults to 0.
* @param endSequence {number} (optional) an exclusive upper boundary
* for the playlist. Defaults to playlist length.
* @param includeTrailingTime {boolean} if false, the interval between
* the final segment and the subsequent segment will not be included
* in the result
* @return {number} the duration between the start index and end
* index.
*/
segmentsDuration
=
function
(
playlist
,
startSequence
,
endSequenc
e
)
{
var
targetDuration
,
i
,
j
,
segment
,
endSegment
,
expiredSegmentCount
,
result
=
0
;
intervalDuration
=
function
(
playlist
,
startSequence
,
endSequence
,
includeTrailingTim
e
)
{
var
result
=
0
,
targetDuration
,
expiredSegmentCount
;
startSequence
=
startSequence
||
0
;
i
=
startSequence
;
endSequence
=
endSequence
!==
undefined
?
endSequence
:
(
playlist
.
segments
||
[]).
length
;
targetDuration
=
playlist
.
targetDuration
||
DEFAULT_TARGET_DURATION
;
// estimate expired segment duration using the target duration
expiredSegmentCount
=
Math
.
max
(
playlist
.
mediaSequence
-
startSequence
,
0
);
result
+=
expiredSegmentCount
*
targetDuration
;
i
+=
expiredSegmentCount
;
// accumulate the segment durations into the result
for
(;
i
<
endSequence
;
i
++
)
{
segment
=
playlist
.
segments
[
i
-
playlist
.
mediaSequence
];
// when PTS values aren't available, use information from the playlist
if
(
segment
.
minVideoPts
===
undefined
)
{
result
+=
segment
.
duration
||
targetDuration
;
continue
;
}
// find the last segment with PTS info and use that to calculate
// the interval duration
for
(
j
=
i
;
j
<
endSequence
-
1
;
j
++
)
{
endSegment
=
playlist
.
segments
[
j
-
playlist
.
mediaSequence
+
1
];
if
(
endSegment
.
maxVideoPts
===
undefined
||
endSegment
.
discontinuity
)
{
break
;
}
}
endSegment
=
playlist
.
segments
[
j
-
playlist
.
mediaSequence
];
result
+=
(
Math
.
max
(
endSegment
.
maxVideoPts
,
endSegment
.
maxAudioPts
)
-
Math
.
min
(
segment
.
minVideoPts
,
segment
.
minAudioPts
))
*
0.001
;
i
=
j
;
}
result
+=
accumulateDuration
(
playlist
,
startSequence
+
expiredSegmentCount
-
playlist
.
mediaSequence
,
endSequence
-
playlist
.
mediaSequence
,
includeTrailingTime
);
return
result
;
};
...
...
@@ -72,14 +176,21 @@
* boundary for the playlist. Defaults to 0.
* @param endSequence {number} (optional) an exclusive upper boundary
* for the playlist. Defaults to playlist length.
* @param includeTrailingTime {boolean} (optional) if false, the interval between
* the final segment and the subsequent segment will not be included
* in the result
* @return {number} the duration between the start index and end
* index.
*/
duration
=
function
(
playlist
,
startSequence
,
endSequence
)
{
duration
=
function
(
playlist
,
startSequence
,
endSequence
,
includeTrailingTime
)
{
if
(
!
playlist
)
{
return
0
;
}
if
(
includeTrailingTime
===
undefined
)
{
includeTrailingTime
=
true
;
}
// if a slice of the total duration is not requested, use
// playlist-level duration indicators when they're present
if
(
startSequence
===
undefined
&&
endSequence
===
undefined
)
{
...
...
@@ -95,9 +206,10 @@
}
// calculate the total duration based on the segment durations
return
segments
Duration
(
playlist
,
return
interval
Duration
(
playlist
,
startSequence
,
endSequence
);
endSequence
,
includeTrailingTime
);
};
/**
...
...
@@ -119,8 +231,8 @@
return
videojs
.
createTimeRange
(
0
,
duration
(
playlist
));
}
start
=
segments
Duration
(
playlist
,
0
,
playlist
.
mediaSequence
);
end
=
start
+
segments
Duration
(
playlist
,
start
=
interval
Duration
(
playlist
,
0
,
playlist
.
mediaSequence
);
end
=
start
+
interval
Duration
(
playlist
,
playlist
.
mediaSequence
,
playlist
.
mediaSequence
+
playlist
.
segments
.
length
);
targetDuration
=
playlist
.
targetDuration
||
DEFAULT_TARGET_DURATION
;
...
...
src/segment-parser.js
View file @
5530370
...
...
@@ -31,15 +31,6 @@
// allow in-band metadata to be observed
self
.
metadataStream
=
new
MetadataStream
();
this
.
mediaTimelineOffset
=
null
;
// The first timestamp value encountered during parsing. This
// value can be used to determine the relative timing between
// frames and the start of the current timestamp sequence. It
// should be reset to null before parsing a segment with
// discontinuous timestamp values from previous segments.
self
.
timestampOffset
=
null
;
// For information on the FLV format, see
// http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf.
// Technically, this function returns the header and a metadata FLV tag
...
...
@@ -360,13 +351,6 @@
// Skip past "optional" portion of PTS header
offset
+=
pesHeaderLength
;
// keep track of the earliest encounted PTS value so
// external parties can align timestamps across
// discontinuities
if
(
self
.
timestampOffset
===
null
)
{
self
.
timestampOffset
=
pts
;
}
if
(
pid
===
self
.
stream
.
programMapTable
[
STREAM_TYPES
.
h264
])
{
h264Stream
.
setNextTimeStamp
(
pts
,
dts
,
...
...
src/videojs-hls.js
View file @
5530370
...
...
@@ -260,7 +260,7 @@ videojs.Hls.prototype.setupMetadataCueTranslation_ = function() {
// add a metadata cue whenever a metadata event is triggered during
// segment parsing
metadataStream
.
on
(
'data'
,
function
(
metadata
)
{
var
i
,
cue
,
frame
,
time
,
media
,
segmentOffset
,
hexDigit
;
var
i
,
hexDigit
;
// create the metadata track if this is the first ID3 tag we've
// seen
...
...
@@ -276,19 +276,11 @@ videojs.Hls.prototype.setupMetadataCueTranslation_ = function() {
}
}
// calculate the start time for the segment that is currently being parsed
media
=
tech
.
playlists
.
media
();
segmentOffset
=
tech
.
playlists
.
expiredPreDiscontinuity_
+
tech
.
playlists
.
expiredPostDiscontinuity_
;
segmentOffset
+=
videojs
.
Hls
.
Playlist
.
duration
(
media
,
media
.
mediaSequence
,
media
.
mediaSequence
+
tech
.
mediaIndex
);
// create cue points for all the ID3 frames in this metadata event
for
(
i
=
0
;
i
<
metadata
.
frames
.
length
;
i
++
)
{
frame
=
metadata
.
frames
[
i
];
time
=
tech
.
segmentParser_
.
mediaTimelineOffset
+
((
metadata
.
pts
-
tech
.
segmentParser_
.
timestampOffset
)
*
0.001
);
cue
=
new
window
.
VTTCue
(
time
,
time
,
frame
.
value
||
frame
.
url
||
''
);
cue
.
frame
=
frame
;
textTrack
.
addCue
(
cue
);
}
// store this event for processing once the muxing has finished
tech
.
segmentBuffer_
[
0
].
pendingMetadata
.
push
({
textTrack
:
textTrack
,
metadata
:
metadata
});
});
// when seeking, clear out all cues ahead of the earliest position
...
...
@@ -312,6 +304,30 @@ videojs.Hls.prototype.setupMetadataCueTranslation_ = function() {
});
};
videojs
.
Hls
.
prototype
.
addCuesForMetadata_
=
function
(
segmentInfo
)
{
var
i
,
cue
,
frame
,
metadata
,
minPts
,
segment
,
segmentOffset
,
textTrack
,
time
;
segmentOffset
=
videojs
.
Hls
.
Playlist
.
duration
(
segmentInfo
.
playlist
,
segmentInfo
.
playlist
.
mediaSequence
,
segmentInfo
.
playlist
.
mediaSequence
+
segmentInfo
.
mediaIndex
);
segment
=
segmentInfo
.
playlist
.
segments
[
segmentInfo
.
mediaIndex
];
minPts
=
Math
.
min
(
segment
.
minVideoPts
,
segment
.
minAudioPts
);
while
(
segmentInfo
.
pendingMetadata
.
length
)
{
metadata
=
segmentInfo
.
pendingMetadata
[
0
].
metadata
;
textTrack
=
segmentInfo
.
pendingMetadata
[
0
].
textTrack
;
// create cue points for all the ID3 frames in this metadata event
for
(
i
=
0
;
i
<
metadata
.
frames
.
length
;
i
++
)
{
frame
=
metadata
.
frames
[
i
];
time
=
segmentOffset
+
((
metadata
.
pts
-
minPts
)
*
0.001
);
cue
=
new
window
.
VTTCue
(
time
,
time
,
frame
.
value
||
frame
.
url
||
''
);
cue
.
frame
=
frame
;
textTrack
.
addCue
(
cue
);
}
segmentInfo
.
pendingMetadata
.
shift
();
}
};
/**
* Reset the mediaIndex if play() is called after the video has
* ended.
...
...
@@ -780,7 +796,10 @@ videojs.Hls.prototype.loadSegment = function(segmentUri, offset) {
// when a key is defined for this segment, the encrypted bytes
encryptedBytes
:
null
,
// optionally, the decrypter that is unencrypting the segment
decrypter
:
null
decrypter
:
null
,
// metadata events discovered during muxing that need to be
// translated into cue points
pendingMetadata
:
[]
};
if
(
segmentInfo
.
playlist
.
segments
[
segmentInfo
.
mediaIndex
].
key
)
{
segmentInfo
.
encryptedBytes
=
new
Uint8Array
(
this
.
response
);
...
...
@@ -870,20 +889,6 @@ videojs.Hls.prototype.drainBuffer = function(event) {
}
event
=
event
||
{};
segmentOffset
=
this
.
playlists
.
expiredPreDiscontinuity_
;
segmentOffset
+=
this
.
playlists
.
expiredPostDiscontinuity_
;
segmentOffset
+=
videojs
.
Hls
.
Playlist
.
duration
(
playlist
,
playlist
.
mediaSequence
,
playlist
.
mediaSequence
+
mediaIndex
);
segmentOffset
*=
1000
;
// if this segment starts is the start of a new discontinuity
// sequence, the segment parser's timestamp offset must be
// re-calculated
if
(
segment
.
discontinuity
)
{
this
.
segmentParser_
.
mediaTimelineOffset
=
segmentOffset
*
0.001
;
this
.
segmentParser_
.
timestampOffset
=
null
;
}
else
if
(
this
.
segmentParser_
.
mediaTimelineOffset
===
null
)
{
this
.
segmentParser_
.
mediaTimelineOffset
=
segmentOffset
*
0.001
;
}
// transmux the segment data from MP2T to FLV
this
.
segmentParser_
.
parseSegmentBinaryData
(
bytes
);
...
...
@@ -904,20 +909,27 @@ videojs.Hls.prototype.drainBuffer = function(event) {
tags
.
push
(
this
.
segmentParser_
.
getNextTag
());
}
this
.
addCuesForMetadata_
(
segmentInfo
);
this
.
updateDuration
(
this
.
playlists
.
media
());
// if we're refilling the buffer after a seek, scan through the muxed
// FLV tags until we find the one that is closest to the desired
// playback time
if
(
typeof
offset
===
'number'
)
{
ptsTime
=
offset
-
segmentOffset
+
tags
[
0
].
pts
;
while
(
tags
[
i
].
pts
<
ptsTime
)
{
// determine the offset within this segment we're seeking to
segmentOffset
=
this
.
playlists
.
expiredPostDiscontinuity_
+
this
.
playlists
.
expiredPreDiscontinuity_
;
segmentOffset
+=
videojs
.
Hls
.
Playlist
.
duration
(
playlist
,
playlist
.
mediaSequence
,
playlist
.
mediaSequence
+
mediaIndex
);
segmentOffset
=
offset
-
(
segmentOffset
*
1000
);
ptsTime
=
segmentOffset
+
tags
[
0
].
pts
;
while
(
tags
[
i
+
1
]
&&
tags
[
i
].
pts
<
ptsTime
)
{
i
++
;
}
// tell the SWF
where we will be seeking to
this
.
el
().
vjs_setProperty
(
'currentTime'
,
(
tags
[
i
].
pts
-
tags
[
0
].
pts
+
segmentOffset
)
*
0.001
);
// tell the SWF
the media position of the first tag we'll be delivering
this
.
el
().
vjs_setProperty
(
'currentTime'
,
(
(
tags
[
i
].
pts
-
ptsTime
+
offset
)
*
0.001
)
);
tags
=
tags
.
slice
(
i
);
...
...
@@ -1139,29 +1151,6 @@ videojs.Hls.getMediaIndexByTime = function() {
};
/**
* Determine the current time in seconds in one playlist by a media index. This
* function iterates through the segments of a playlist up to the specified index
* and then returns the time up to that point.
*
* @param playlist {object} The playlist of the segments being searched.
* @param mediaIndex {number} The index of the target segment in the playlist.
* @returns {number} The current time to that point, or 0 if none appropriate.
*/
videojs
.
Hls
.
prototype
.
getCurrentTimeByMediaIndex_
=
function
(
playlist
,
mediaIndex
)
{
var
index
,
time
=
0
;
if
(
!
playlist
.
segments
||
mediaIndex
===
0
)
{
return
0
;
}
for
(
index
=
0
;
index
<
mediaIndex
;
index
++
)
{
time
+=
playlist
.
segments
[
index
].
duration
;
}
return
time
;
};
/**
* A comparator function to sort two playlist object by bandwidth.
* @param left {object} a media playlist object
* @param right {object} a media playlist object
...
...
test/manifest/absoluteUris.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/allowCache.js
View file @
5530370
...
...
@@ -142,5 +142,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/allowCacheInvalid.js
View file @
5530370
...
...
@@ -14,5 +14,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/brightcove.js
View file @
5530370
...
...
@@ -41,5 +41,6 @@
},
"uri"
:
"http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824687660001&videoId=1824650741001"
}
]
],
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/byteRange.js
View file @
5530370
...
...
@@ -138,5 +138,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/disallowCache.js
View file @
5530370
...
...
@@ -14,5 +14,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/disc-sequence.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
}
],
"targetDuration"
:
19
,
"endList"
:
true
"endList"
:
true
,
"discontinuityStarts"
:
[
2
]
}
...
...
test/manifest/discontinuity.js
View file @
5530370
...
...
@@ -44,5 +44,6 @@
}
],
"targetDuration"
:
19
,
"endList"
:
true
"endList"
:
true
,
"discontinuityStarts"
:
[
2
,
4
,
7
]
}
...
...
test/manifest/domainUris.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/emptyAllowCache.js
View file @
5530370
...
...
@@ -14,5 +14,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/emptyMediaSequence.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/emptyPlaylistType.js
View file @
5530370
...
...
@@ -29,5 +29,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/emptyTargetDuration.js
View file @
5530370
...
...
@@ -41,5 +41,6 @@
},
"uri"
:
"http://c.brightcove.com/services/mobile/streaming/index/rendition.m3u8?assetId=1824687660001&videoId=1824650741001"
}
]
],
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/encrypted.js
View file @
5530370
...
...
@@ -2,6 +2,7 @@
"allowCache"
:
true
,
"mediaSequence"
:
7794
,
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[],
"segments"
:
[
{
"duration"
:
2.833
,
...
...
test/manifest/event.js
View file @
5530370
...
...
@@ -30,5 +30,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/extXPlaylistTypeInvalidPlaylist.js
View file @
5530370
...
...
@@ -9,5 +9,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/extinf.js
View file @
5530370
...
...
@@ -142,5 +142,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/invalidAllowCache.js
View file @
5530370
...
...
@@ -14,5 +14,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/invalidMediaSequence.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/invalidPlaylistType.js
View file @
5530370
...
...
@@ -29,5 +29,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/invalidTargetDuration.js
View file @
5530370
...
...
@@ -141,5 +141,6 @@
}
],
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/liveMissingSegmentDuration.js
View file @
5530370
...
...
@@ -17,5 +17,6 @@
}
],
"targetDuration"
:
8
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/liveStart30sBefore.js
View file @
5530370
...
...
@@ -40,5 +40,6 @@
}
],
"targetDuration"
:
10
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/manifestExtTTargetdurationNegative.js
View file @
5530370
...
...
@@ -8,5 +8,6 @@
}
],
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/manifestExtXEndlistEarly.js
View file @
5530370
...
...
@@ -25,5 +25,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/manifestNoExtM3u.js
View file @
5530370
...
...
@@ -9,5 +9,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/master.js
View file @
5530370
...
...
@@ -41,5 +41,6 @@
},
"uri"
:
"media3.m3u8"
}
]
],
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/media.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/mediaSequence.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/missingEndlist.js
View file @
5530370
...
...
@@ -12,5 +12,6 @@
}
],
"targetDuration"
:
10
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/missingExtinf.js
View file @
5530370
...
...
@@ -18,5 +18,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/missingMediaSequence.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/missingSegmentDuration.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/multipleTargetDurations.js
View file @
5530370
...
...
@@ -19,5 +19,6 @@
"duration"
:
10
}
],
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/negativeMediaSequence.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/playlist.js
View file @
5530370
...
...
@@ -142,5 +142,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/playlistMediaSequenceHigher.js
View file @
5530370
...
...
@@ -10,5 +10,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/streamInfInvalid.js
View file @
5530370
...
...
@@ -10,5 +10,6 @@
{
"uri"
:
"media1.m3u8"
}
]
],
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/twoMediaSequences.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
8
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/versionInvalid.js
View file @
5530370
...
...
@@ -10,5 +10,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/manifest/whiteSpace.js
View file @
5530370
...
...
@@ -22,5 +22,6 @@
],
"targetDuration"
:
10
,
"endList"
:
true
,
"discontinuitySequence"
:
0
"discontinuitySequence"
:
0
,
"discontinuityStarts"
:
[]
}
\ No newline at end of file
...
...
test/playlist_test.js
View file @
5530370
...
...
@@ -3,7 +3,7 @@
'use strict'
;
var
Playlist
=
videojs
.
Hls
.
Playlist
;
module
(
'Playlist
Utilities
'
);
module
(
'Playlist
Duration
'
);
test
(
'total duration for live playlists is Infinity'
,
function
()
{
var
duration
=
Playlist
.
duration
({
...
...
@@ -16,7 +16,9 @@
equal
(
duration
,
Infinity
,
'duration is infinity'
);
});
test
(
'interval duration accounts for media sequences'
,
function
()
{
module
(
'Playlist Interval Duration'
);
test
(
'accounts for media sequences'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
10
,
endList
:
true
,
...
...
@@ -38,7 +40,7 @@
equal
(
duration
,
14
*
10
,
'duration includes dropped segments'
);
});
test
(
'
interval duration
uses PTS values when available'
,
function
()
{
test
(
'uses PTS values when available'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
endList
:
true
,
...
...
@@ -67,52 +69,244 @@
equal
(
duration
,
((
4
*
10
*
1000
+
2
)
-
1
)
*
0.001
,
'used PTS values'
);
});
test
(
'
interval duration
works when partial PTS information is available'
,
function
()
{
var
firstInterval
,
secondInterval
,
duration
=
Playlist
.
duration
({
test
(
'works when partial PTS information is available'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
endList
:
true
,
segments
:
[{
minVideoPts
:
1
,
minAudioPts
:
2
,
maxVideoPts
:
1
*
1
0
*
1000
+
1
,
maxVideoPts
:
10
*
1000
+
1
,
// intentionally less duration than video
// the max stream duration should be used
maxAudioPts
:
1
*
10
*
1000
+
1
,
maxAudioPts
:
10
*
1000
+
1
,
uri
:
'0.ts'
},
{
duration
:
9
,
uri
:
'1.ts'
},
{
duration
:
10
,
uri
:
'2.ts'
},
{
duration
:
10
,
minVideoPts
:
30
*
1000
+
7
,
minAudioPts
:
30
*
1000
+
10
,
maxVideoPts
:
40
*
1000
+
1
,
maxAudioPts
:
40
*
1000
+
2
,
uri
:
'3.ts'
},
{
duration
:
10
,
maxVideoPts
:
50
*
1000
+
1
,
maxAudioPts
:
50
*
1000
+
2
,
uri
:
'4.ts'
}]
},
0
,
5
);
equal
(
duration
,
((
50
*
1000
+
2
)
-
1
)
*
0.001
,
'calculated with mixed intervals'
);
});
test
(
'ignores segments before the start'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
segments
:
[{
duration
:
10
,
uri
:
'0.ts'
},
{
duration
:
10
,
uri
:
'1.ts'
},
{
duration
:
10
,
minVideoPts
:
2
*
10
*
1000
+
7
,
minAudioPts
:
2
*
10
*
1000
+
10
,
maxVideoPts
:
3
*
10
*
1000
+
1
,
maxAudioPts
:
3
*
10
*
1000
+
2
,
uri
:
'2.ts'
}]
},
1
,
3
);
equal
(
duration
,
10
+
10
,
'ignored the first segment'
);
});
test
(
'ignores discontinuity sequences earlier than the start'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
discontinuityStarts
:
[
1
,
3
],
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
10
*
1000
,
maxAudioPts
:
10
*
1000
,
uri
:
'0.ts'
},
{
discontinuity
:
true
,
duration
:
9
,
uri
:
'1.ts'
},
{
duration
:
10
,
uri
:
'2.ts'
},
{
discontinuity
:
true
,
duration
:
10
,
maxVideoPts
:
4
*
10
*
1000
+
1
,
maxAudioPts
:
4
*
10
*
1000
+
2
,
uri
:
'3.ts'
}]
},
0
,
4
);
},
2
,
4
);
equal
(
duration
,
10
+
10
,
'excluded the earlier segments'
);
});
firstInterval
=
(
1
*
10
*
1000
+
1
)
-
1
;
firstInterval
*=
0.001
;
secondInterval
=
(
4
*
10
*
1000
+
2
)
-
(
2
*
10
*
1000
+
7
);
secondInterval
*=
0.001
;
test
(
'ignores discontinuity sequences later than the end'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
discontinuityStarts
:
[
1
,
3
],
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
10
*
1000
,
maxAudioPts
:
10
*
1000
,
uri
:
'0.ts'
},
{
discontinuity
:
true
,
duration
:
9
,
uri
:
'1.ts'
},
{
duration
:
10
,
uri
:
'2.ts'
},
{
discontinuity
:
true
,
duration
:
10
,
uri
:
'3.ts'
}]
},
0
,
2
);
equal
(
duration
,
firstInterval
+
10
+
secondInterval
,
'calculated with mixed interval
s'
);
equal
(
duration
,
19
,
'excluded the later segment
s'
);
});
test
(
'
interval duration accounts for discontinuities
'
,
function
()
{
test
(
'
handles trailing segments without PTS information
'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
endList
:
true
,
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
10
*
1000
,
maxAudioPts
:
10
*
1000
,
uri
:
'0.ts'
},
{
duration
:
9
,
uri
:
'1.ts'
},
{
duration
:
10
,
uri
:
'2.ts'
},
{
minVideoPts
:
29.5
*
1000
,
minAudioPts
:
29.5
*
1000
,
maxVideoPts
:
39.5
*
1000
,
maxAudioPts
:
39.5
*
1000
,
uri
:
'3.ts'
}]
},
0
,
3
);
equal
(
duration
,
29.5
,
'calculated duration'
);
});
test
(
'uses PTS intervals when the start and end segment have them'
,
function
()
{
var
playlist
,
duration
;
playlist
=
{
mediaSequence
:
0
,
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
10
*
1000
,
maxAudioPts
:
10
*
1000
,
uri
:
'0.ts'
},
{
duration
:
9
,
uri
:
'1.ts'
},{
minVideoPts
:
20
*
1000
+
100
,
minAudioPts
:
20
*
1000
+
100
,
maxVideoPts
:
30
*
1000
+
100
,
maxAudioPts
:
30
*
1000
+
100
,
duration
:
10
,
uri
:
'2.ts'
}]
};
duration
=
Playlist
.
duration
(
playlist
,
0
,
2
);
equal
(
duration
,
20.1
,
'used the PTS-based interval'
);
duration
=
Playlist
.
duration
(
playlist
,
0
,
3
);
equal
(
duration
,
30.1
,
'used the PTS-based interval'
);
});
test
(
'uses the largest continuous available PTS ranges'
,
function
()
{
var
playlist
=
{
mediaSequence
:
0
,
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
10
*
1000
,
maxAudioPts
:
10
*
1000
,
uri
:
'0.ts'
},
{
duration
:
10
,
uri
:
'1.ts'
},
{
// starts 0.5s earlier than the previous segment indicates
minVideoPts
:
19.5
*
1000
,
minAudioPts
:
19.5
*
1000
,
maxVideoPts
:
29.5
*
1000
,
maxAudioPts
:
29.5
*
1000
,
uri
:
'2.ts'
},
{
duration
:
10
,
uri
:
'3.ts'
},
{
// ... but by the last segment, there is actual 0.5s more
// content than duration indicates
minVideoPts
:
40.5
*
1000
,
minAudioPts
:
40.5
*
1000
,
maxVideoPts
:
50.5
*
1000
,
maxAudioPts
:
50.5
*
1000
,
uri
:
'4.ts'
}]
};
equal
(
Playlist
.
duration
(
playlist
,
0
,
5
),
50.5
,
'calculated across the larger PTS interval'
);
});
test
(
'counts the time between segments as part of the earlier segment\'s duration'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
endList
:
true
,
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
1
*
10
*
1000
,
maxAudioPts
:
1
*
10
*
1000
,
uri
:
'0.ts'
},
{
minVideoPts
:
1
*
10
*
1000
+
100
,
minAudioPts
:
1
*
10
*
1000
+
100
,
maxVideoPts
:
2
*
10
*
1000
+
100
,
maxAudioPts
:
2
*
10
*
1000
+
100
,
duration
:
10
,
uri
:
'1.ts'
}]
},
0
,
1
);
equal
(
duration
,
(
1
*
10
*
1000
+
100
)
*
0.001
,
'included the segment gap'
);
});
test
(
'accounts for discontinuities'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
endList
:
true
,
discontinuityStarts
:
[
1
],
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
1
*
10
*
1000
,
maxAudioPts
:
1
*
10
*
1000
,
uri
:
'0.ts'
...
...
@@ -130,6 +324,76 @@
equal
(
duration
,
10
+
10
,
'handles discontinuities'
);
});
test
(
'does not count ending segment gaps across a discontinuity'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
discontinuityStarts
:
[
1
],
endList
:
true
,
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
1
*
10
*
1000
,
maxAudioPts
:
1
*
10
*
1000
,
uri
:
'0.ts'
},
{
discontinuity
:
true
,
minVideoPts
:
1
*
10
*
1000
+
100
,
minAudioPts
:
1
*
10
*
1000
+
100
,
maxVideoPts
:
2
*
10
*
1000
+
100
,
maxAudioPts
:
2
*
10
*
1000
+
100
,
duration
:
10
,
uri
:
'1.ts'
}]
},
0
,
1
);
equal
(
duration
,
(
1
*
10
*
1000
)
*
0.001
,
'did not include the segment gap'
);
});
test
(
'trailing duration on the final segment can be excluded'
,
function
()
{
var
duration
=
Playlist
.
duration
({
mediaSequence
:
0
,
endList
:
true
,
segments
:
[{
minVideoPts
:
0
,
minAudioPts
:
0
,
maxVideoPts
:
1
*
10
*
1000
,
maxAudioPts
:
1
*
10
*
1000
,
uri
:
'0.ts'
},
{
minVideoPts
:
1
*
10
*
1000
+
100
,
minAudioPts
:
1
*
10
*
1000
+
100
,
maxVideoPts
:
2
*
10
*
1000
+
100
,
maxAudioPts
:
2
*
10
*
1000
+
100
,
duration
:
10
,
uri
:
'1.ts'
}]
},
0
,
1
,
false
);
equal
(
duration
,
(
1
*
10
*
1000
)
*
0.001
,
'did not include the segment gap'
);
});
test
(
'a non-positive length interval has zero duration'
,
function
()
{
var
playlist
=
{
mediaSequence
:
0
,
discontinuityStarts
:
[
1
],
segments
:
[{
duration
:
10
,
uri
:
'0.ts'
},
{
discontinuity
:
true
,
duration
:
10
,
uri
:
'1.ts'
}]
};
equal
(
Playlist
.
duration
(
playlist
,
0
,
0
),
0
,
'zero-length duration is zero'
);
equal
(
Playlist
.
duration
(
playlist
,
0
,
0
,
false
),
0
,
'zero-length duration is zero'
);
equal
(
Playlist
.
duration
(
playlist
,
0
,
-
1
),
0
,
'negative length duration is zero'
);
equal
(
Playlist
.
duration
(
playlist
,
2
,
1
,
false
),
0
,
'negative length duration is zero'
);
});
module
(
'Playlist Seekable'
);
test
(
'calculates seekable time ranges from the available segments'
,
function
()
{
var
playlist
=
{
mediaSequence
:
0
,
...
...
test/videojs-hls_test.js
View file @
5530370
...
...
@@ -97,15 +97,13 @@ var
var
MockSegmentParser
;
if
(
tags
===
undefined
)
{
tags
=
[];
tags
=
[
{
pts
:
0
,
bytes
:
new
Uint8Array
(
1
)
}
];
}
MockSegmentParser
=
function
()
{
this
.
getFlvHeader
=
function
()
{
return
'flv'
;
};
this
.
parseSegmentBinaryData
=
function
()
{};
this
.
timestampOffset
=
0
;
this
.
mediaTimelineOffset
=
0
;
this
.
flushTags
=
function
()
{};
this
.
tagsAvailable
=
function
()
{
return
tags
.
length
;
...
...
@@ -1287,30 +1285,32 @@ test('clears in-band cues ahead of current time on seek', function() {
player
.
hls
.
segmentParser_
.
parseSegmentBinaryData
=
function
()
{
// trigger a metadata event
if
(
events
.
length
)
{
while
(
events
.
length
)
{
player
.
hls
.
segmentParser_
.
metadataStream
.
trigger
(
'data'
,
events
.
shift
());
}
};
standardXHRResponse
(
requests
.
shift
());
// media
tags
.
push
({
pts
:
10
*
1000
,
bytes
:
new
Uint8Array
(
1
)
});
tags
.
push
({
pts
:
0
,
bytes
:
new
Uint8Array
(
1
)
},
{
pts
:
10
*
1000
,
bytes
:
new
Uint8Array
(
1
)
});
events
.
push
({
pts
:
20
*
1000
,
pts
:
9.9
*
1000
,
data
:
new
Uint8Array
([]),
frames
:
[{
id
:
'TXXX'
,
value
:
'cue
3
'
value
:
'cue
1
'
}]
});
events
.
push
({
pts
:
9.9
*
1000
,
pts
:
20
*
1000
,
data
:
new
Uint8Array
([]),
frames
:
[{
id
:
'TXXX'
,
value
:
'cue
1
'
value
:
'cue
3
'
}]
});
standardXHRResponse
(
requests
.
shift
());
// segment 0
tags
.
push
({
pts
:
20
*
1000
,
bytes
:
new
Uint8Array
(
1
)
});
tags
.
push
({
pts
:
10
*
1000
+
1
,
bytes
:
new
Uint8Array
(
1
)
},
{
pts
:
20
*
1000
,
bytes
:
new
Uint8Array
(
1
)
});
events
.
push
({
pts
:
19.9
*
1000
,
data
:
new
Uint8Array
([]),
...
...
@@ -1323,12 +1323,12 @@ test('clears in-band cues ahead of current time on seek', function() {
standardXHRResponse
(
requests
.
shift
());
// segment 1
track
=
player
.
textTracks
()[
0
];
equal
(
track
.
cues
.
length
,
2
,
'added the cues'
);
equal
(
track
.
cues
.
length
,
3
,
'added the cues'
);
// seek into segment 1
player
.
currentTime
(
11
);
player
.
trigger
(
'seeking'
);
equal
(
track
.
cues
.
length
,
1
,
'removed
a cue
'
);
equal
(
track
.
cues
.
length
,
1
,
'removed
later cues
'
);
equal
(
track
.
cues
[
0
].
startTime
,
9.9
,
'retained the earlier cue'
);
});
...
...
@@ -1342,9 +1342,6 @@ test('translates ID3 PTS values to cue media timeline positions', function() {
openMediaSource
(
player
);
player
.
hls
.
segmentParser_
.
parseSegmentBinaryData
=
function
()
{
// setup the timestamp offset
this
.
timestampOffset
=
tags
[
0
].
pts
;
// trigger a metadata event
player
.
hls
.
segmentParser_
.
metadataStream
.
trigger
(
'data'
,
{
pts
:
5
*
1000
,
...
...
@@ -1373,9 +1370,6 @@ test('translates ID3 PTS values across discontinuities', function() {
openMediaSource
(
player
);
player
.
hls
.
segmentParser_
.
parseSegmentBinaryData
=
function
()
{
if
(
this
.
timestampOffset
===
null
)
{
this
.
timestampOffset
=
tags
[
0
].
pts
;
}
// trigger a metadata event
if
(
events
.
length
)
{
player
.
hls
.
segmentParser_
.
metadataStream
.
trigger
(
'data'
,
events
.
shift
());
...
...
@@ -1393,7 +1387,6 @@ test('translates ID3 PTS values across discontinuities', function() {
'1.ts\n'
);
// segment 0 starts at PTS 14000 and has a cue point at 15000
player
.
hls
.
segmentParser_
.
timestampOffset
=
14
*
1000
;
tags
.
push
({
pts
:
14
*
1000
,
bytes
:
new
Uint8Array
(
1
)
},
{
pts
:
24
*
1000
,
bytes
:
new
Uint8Array
(
1
)
});
events
.
push
({
...
...
@@ -2010,6 +2003,48 @@ test('continues playing after seek to discontinuity', function() {
strictEqual
(
aborts
,
1
,
'cleared the segment buffer on a seek'
);
});
test
(
'seeking does not fail when targeted between segments'
,
function
()
{
var
tags
=
[],
currentTime
,
segmentUrl
;
videojs
.
Hls
.
SegmentParser
=
mockSegmentParser
(
tags
);
player
.
src
({
src
:
'media.m3u8'
,
type
:
'application/vnd.apple.mpegurl'
});
openMediaSource
(
player
);
// mock out the currentTime callbacks
player
.
hls
.
el
().
vjs_setProperty
=
function
(
property
,
value
)
{
if
(
property
===
'currentTime'
)
{
currentTime
=
value
;
}
};
player
.
hls
.
el
().
vjs_getProperty
=
function
(
property
)
{
if
(
property
===
'currentTime'
)
{
return
currentTime
;
}
};
standardXHRResponse
(
requests
.
shift
());
// media
tags
.
push
({
pts
:
100
,
bytes
:
new
Uint8Array
(
1
)
},
{
pts
:
9
*
1000
+
100
,
bytes
:
new
Uint8Array
(
1
)
});
standardXHRResponse
(
requests
.
shift
());
// segment 0
player
.
hls
.
checkBuffer_
();
tags
.
push
({
pts
:
9.5
*
1000
+
100
,
bytes
:
new
Uint8Array
(
1
)
},
{
pts
:
20
*
1000
+
100
,
bytes
:
new
Uint8Array
(
1
)
});
segmentUrl
=
requests
[
0
].
url
;
standardXHRResponse
(
requests
.
shift
());
// segment 1
// seek to a time that is greater than the last tag in segment 0 but
// less than the first in segment 1
player
.
currentTime
(
9.4
);
equal
(
requests
[
0
].
url
,
segmentUrl
,
'requested the later segment'
);
tags
.
push
({
pts
:
9.5
*
1000
+
100
,
bytes
:
new
Uint8Array
(
1
)
},
{
pts
:
20
*
1000
+
100
,
bytes
:
new
Uint8Array
(
1
)
});
standardXHRResponse
(
requests
.
shift
());
// segment 1
equal
(
player
.
currentTime
(),
9.5
,
'seeked to the later time'
);
});
test
(
'resets the switching algorithm if a request times out'
,
function
()
{
player
.
src
({
src
:
'master.m3u8'
,
...
...
@@ -2666,12 +2701,13 @@ test('treats invalid keys as a key request failure', function() {
equal
(
bytes
[
0
],
'flv'
,
'appended the flv header'
);
tags
.
length
=
0
;
tags
.
push
({
pts
:
1
,
bytes
:
new
Uint8Array
([
1
])
});
tags
.
push
({
pts
:
2833
,
bytes
:
new
Uint8Array
([
1
])
},
{
pts
:
4833
,
bytes
:
new
Uint8Array
([
2
])
});
// second segment request
standardXHRResponse
(
requests
.
shift
());
equal
(
bytes
.
length
,
2
,
'appended bytes'
);
deepEqual
(
new
Uint8Array
([
1
]),
bytes
[
1
]
,
'skipped to the second segment'
);
deepEqual
(
bytes
[
1
],
new
Uint8Array
([
1
,
2
])
,
'skipped to the second segment'
);
});
test
(
'live stream should not call endOfStream'
,
function
(){
...
...
Please
register
or
sign in
to post a comment