25033e31 by Jon-Carlos Rivera

Merge pull request #508 from videojs/rendition-selection

Rendition selection
2 parents 7080865c e4a526c4
......@@ -632,7 +632,6 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
now = +new Date(),
i,
variant,
oldvariant,
bandwidthBestVariant,
resolutionPlusOne,
resolutionBestVariant,
......@@ -689,7 +688,6 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
// iterate through the bandwidth-filtered playlists and find
// best rendition by player dimension
while (i--) {
oldvariant = variant;
variant = bandwidthPlaylists[i];
// ignore playlists without resolution information
......@@ -700,9 +698,9 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
continue;
}
// since the playlists are sorted, the first variant that has
// dimensions less than or equal to the player size is the best
if (variant.attributes.RESOLUTION.width === width &&
variant.attributes.RESOLUTION.height === height) {
// if we have the exact resolution as the player use it
......@@ -711,13 +709,21 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
break;
} else if (variant.attributes.RESOLUTION.width < width &&
variant.attributes.RESOLUTION.height < height) {
// if we don't have an exact match, see if we have a good higher quality variant to use
if (oldvariant && oldvariant.attributes && oldvariant.attributes.RESOLUTION &&
oldvariant.attributes.RESOLUTION.width && oldvariant.attributes.RESOLUTION.height) {
resolutionPlusOne = oldvariant;
}
resolutionBestVariant = variant;
// if both dimensions are less than the player use the
// previous (next-largest) variant
break;
} else if (!resolutionPlusOne ||
(variant.attributes.RESOLUTION.width < resolutionPlusOne.attributes.RESOLUTION.width &&
variant.attributes.RESOLUTION.height < resolutionPlusOne.attributes.RESOLUTION.height)) {
// If we still haven't found a good match keep a
// reference to the previous variant for the next loop
// iteration
// By only saving variants if they are smaller than the
// previously saved variant, we ensure that we also pick
// the highest bandwidth variant that is just-larger-than
// the video player
resolutionPlusOne = variant;
}
}
......
#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXTINF:10,
media2-00001.ts
#EXTINF:10,
media2-00002.ts
#EXTINF:10,
media2-00003.ts
#EXTINF:10,
media2-00004.ts
#ZEN-TOTAL-DURATION:57.9911
#EXT-X-ENDLIST
......@@ -496,9 +496,6 @@ test('calls `remove` on sourceBuffer to when loading a vod segment', function()
standardXHRResponse(requests[2]);
strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested');
strictEqual(requests[1].url,
absoluteUrl('manifest/media3.m3u8'),
'media playlist requested');
equal(removes.length, 1, 'remove called');
deepEqual(removes[0], [0, 120 - 60], 'remove called with the right range');
});
......@@ -773,10 +770,10 @@ test('downloads media playlists after loading the master', function() {
strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested');
strictEqual(requests[1].url,
absoluteUrl('manifest/media3.m3u8'),
absoluteUrl('manifest/media2.m3u8'),
'media playlist requested');
strictEqual(requests[2].url,
absoluteUrl('manifest/media3-00001.ts'),
absoluteUrl('manifest/media2-00001.ts'),
'first segment requested');
});
......@@ -794,10 +791,10 @@ test('upshifts if the initial bandwidth hint is high', function() {
strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested');
strictEqual(requests[1].url,
absoluteUrl('manifest/media3.m3u8'),
absoluteUrl('manifest/media2.m3u8'),
'media playlist requested');
strictEqual(requests[2].url,
absoluteUrl('manifest/media3-00001.ts'),
absoluteUrl('manifest/media2-00001.ts'),
'first segment requested');
});
......@@ -1133,7 +1130,10 @@ test('selects the correct rendition by player dimensions', function() {
playlist = player.tech_.hls.selectPlaylist();
deepEqual(playlist.attributes.RESOLUTION, {width:960,height:540},'should return the correct resolution by player dimensions');
deepEqual(playlist.attributes.RESOLUTION, {
width: 960,
height:540
},'should return the correct resolution by player dimensions');
equal(playlist.attributes.BANDWIDTH, 1928000, 'should have the expected bandwidth in case of multiple');
player.width(1920);
......@@ -1158,6 +1158,15 @@ test('selects the correct rendition by player dimensions', function() {
},'should return the correct resolution by player dimensions, if exact match');
equal(playlist.attributes.BANDWIDTH, 440000, 'should have the expected bandwidth in case of multiple, if exact match');
player.width(395);
player.height(222);
playlist = player.tech_.hls.selectPlaylist();
deepEqual(playlist.attributes.RESOLUTION, {
width:396,
height:224
},'should return the next larger resolution by player dimensions, if no exact match exists');
equal(playlist.attributes.BANDWIDTH, 440000, 'should have the expected bandwidth in case of multiple, if exact match');
});
test('selects the highest bitrate playlist when the player dimensions are ' +
......@@ -1498,7 +1507,7 @@ test('waits to download new segments until the media playlist is stable', functi
standardXHRResponse(requests.shift()); // media1
// force a playlist switch
player.tech_.hls.playlists.media('media3.m3u8');
player.tech_.hls.playlists.media('media2.m3u8');
standardXHRResponse(requests.shift()); // segment 0
player.tech_.hls.sourceBuffer.trigger('updateend');
......