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 () { ...@@ -632,7 +632,6 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
632 now = +new Date(), 632 now = +new Date(),
633 i, 633 i,
634 variant, 634 variant,
635 oldvariant,
636 bandwidthBestVariant, 635 bandwidthBestVariant,
637 resolutionPlusOne, 636 resolutionPlusOne,
638 resolutionBestVariant, 637 resolutionBestVariant,
...@@ -689,7 +688,6 @@ videojs.HlsHandler.prototype.selectPlaylist = function () { ...@@ -689,7 +688,6 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
689 // iterate through the bandwidth-filtered playlists and find 688 // iterate through the bandwidth-filtered playlists and find
690 // best rendition by player dimension 689 // best rendition by player dimension
691 while (i--) { 690 while (i--) {
692 oldvariant = variant;
693 variant = bandwidthPlaylists[i]; 691 variant = bandwidthPlaylists[i];
694 692
695 // ignore playlists without resolution information 693 // ignore playlists without resolution information
...@@ -700,9 +698,9 @@ videojs.HlsHandler.prototype.selectPlaylist = function () { ...@@ -700,9 +698,9 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
700 continue; 698 continue;
701 } 699 }
702 700
703
704 // since the playlists are sorted, the first variant that has 701 // since the playlists are sorted, the first variant that has
705 // dimensions less than or equal to the player size is the best 702 // dimensions less than or equal to the player size is the best
703
706 if (variant.attributes.RESOLUTION.width === width && 704 if (variant.attributes.RESOLUTION.width === width &&
707 variant.attributes.RESOLUTION.height === height) { 705 variant.attributes.RESOLUTION.height === height) {
708 // if we have the exact resolution as the player use it 706 // if we have the exact resolution as the player use it
...@@ -711,13 +709,21 @@ videojs.HlsHandler.prototype.selectPlaylist = function () { ...@@ -711,13 +709,21 @@ videojs.HlsHandler.prototype.selectPlaylist = function () {
711 break; 709 break;
712 } else if (variant.attributes.RESOLUTION.width < width && 710 } else if (variant.attributes.RESOLUTION.width < width &&
713 variant.attributes.RESOLUTION.height < height) { 711 variant.attributes.RESOLUTION.height < height) {
714 // if we don't have an exact match, see if we have a good higher quality variant to use 712 // if both dimensions are less than the player use the
715 if (oldvariant && oldvariant.attributes && oldvariant.attributes.RESOLUTION && 713 // previous (next-largest) variant
716 oldvariant.attributes.RESOLUTION.width && oldvariant.attributes.RESOLUTION.height) {
717 resolutionPlusOne = oldvariant;
718 }
719 resolutionBestVariant = variant;
720 break; 714 break;
715 } else if (!resolutionPlusOne ||
716 (variant.attributes.RESOLUTION.width < resolutionPlusOne.attributes.RESOLUTION.width &&
717 variant.attributes.RESOLUTION.height < resolutionPlusOne.attributes.RESOLUTION.height)) {
718 // If we still haven't found a good match keep a
719 // reference to the previous variant for the next loop
720 // iteration
721
722 // By only saving variants if they are smaller than the
723 // previously saved variant, we ensure that we also pick
724 // the highest bandwidth variant that is just-larger-than
725 // the video player
726 resolutionPlusOne = variant;
721 } 727 }
722 } 728 }
723 729
......
1 #EXTM3U
2 #EXT-X-PLAYLIST-TYPE:VOD
3 #EXT-X-TARGETDURATION:10
4 #EXTINF:10,
5 media2-00001.ts
6 #EXTINF:10,
7 media2-00002.ts
8 #EXTINF:10,
9 media2-00003.ts
10 #EXTINF:10,
11 media2-00004.ts
12 #ZEN-TOTAL-DURATION:57.9911
13 #EXT-X-ENDLIST
...@@ -496,9 +496,6 @@ test('calls `remove` on sourceBuffer to when loading a vod segment', function() ...@@ -496,9 +496,6 @@ test('calls `remove` on sourceBuffer to when loading a vod segment', function()
496 standardXHRResponse(requests[2]); 496 standardXHRResponse(requests[2]);
497 497
498 strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested'); 498 strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested');
499 strictEqual(requests[1].url,
500 absoluteUrl('manifest/media3.m3u8'),
501 'media playlist requested');
502 equal(removes.length, 1, 'remove called'); 499 equal(removes.length, 1, 'remove called');
503 deepEqual(removes[0], [0, 120 - 60], 'remove called with the right range'); 500 deepEqual(removes[0], [0, 120 - 60], 'remove called with the right range');
504 }); 501 });
...@@ -773,10 +770,10 @@ test('downloads media playlists after loading the master', function() { ...@@ -773,10 +770,10 @@ test('downloads media playlists after loading the master', function() {
773 770
774 strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested'); 771 strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested');
775 strictEqual(requests[1].url, 772 strictEqual(requests[1].url,
776 absoluteUrl('manifest/media3.m3u8'), 773 absoluteUrl('manifest/media2.m3u8'),
777 'media playlist requested'); 774 'media playlist requested');
778 strictEqual(requests[2].url, 775 strictEqual(requests[2].url,
779 absoluteUrl('manifest/media3-00001.ts'), 776 absoluteUrl('manifest/media2-00001.ts'),
780 'first segment requested'); 777 'first segment requested');
781 }); 778 });
782 779
...@@ -794,10 +791,10 @@ test('upshifts if the initial bandwidth hint is high', function() { ...@@ -794,10 +791,10 @@ test('upshifts if the initial bandwidth hint is high', function() {
794 791
795 strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested'); 792 strictEqual(requests[0].url, 'manifest/master.m3u8', 'master playlist requested');
796 strictEqual(requests[1].url, 793 strictEqual(requests[1].url,
797 absoluteUrl('manifest/media3.m3u8'), 794 absoluteUrl('manifest/media2.m3u8'),
798 'media playlist requested'); 795 'media playlist requested');
799 strictEqual(requests[2].url, 796 strictEqual(requests[2].url,
800 absoluteUrl('manifest/media3-00001.ts'), 797 absoluteUrl('manifest/media2-00001.ts'),
801 'first segment requested'); 798 'first segment requested');
802 }); 799 });
803 800
...@@ -1133,7 +1130,10 @@ test('selects the correct rendition by player dimensions', function() { ...@@ -1133,7 +1130,10 @@ test('selects the correct rendition by player dimensions', function() {
1133 1130
1134 playlist = player.tech_.hls.selectPlaylist(); 1131 playlist = player.tech_.hls.selectPlaylist();
1135 1132
1136 deepEqual(playlist.attributes.RESOLUTION, {width:960,height:540},'should return the correct resolution by player dimensions'); 1133 deepEqual(playlist.attributes.RESOLUTION, {
1134 width: 960,
1135 height:540
1136 },'should return the correct resolution by player dimensions');
1137 equal(playlist.attributes.BANDWIDTH, 1928000, 'should have the expected bandwidth in case of multiple'); 1137 equal(playlist.attributes.BANDWIDTH, 1928000, 'should have the expected bandwidth in case of multiple');
1138 1138
1139 player.width(1920); 1139 player.width(1920);
...@@ -1158,6 +1158,15 @@ test('selects the correct rendition by player dimensions', function() { ...@@ -1158,6 +1158,15 @@ test('selects the correct rendition by player dimensions', function() {
1158 },'should return the correct resolution by player dimensions, if exact match'); 1158 },'should return the correct resolution by player dimensions, if exact match');
1159 equal(playlist.attributes.BANDWIDTH, 440000, 'should have the expected bandwidth in case of multiple, if exact match'); 1159 equal(playlist.attributes.BANDWIDTH, 440000, 'should have the expected bandwidth in case of multiple, if exact match');
1160 1160
1161 player.width(395);
1162 player.height(222);
1163 playlist = player.tech_.hls.selectPlaylist();
1164
1165 deepEqual(playlist.attributes.RESOLUTION, {
1166 width:396,
1167 height:224
1168 },'should return the next larger resolution by player dimensions, if no exact match exists');
1169 equal(playlist.attributes.BANDWIDTH, 440000, 'should have the expected bandwidth in case of multiple, if exact match');
1161 }); 1170 });
1162 1171
1163 test('selects the highest bitrate playlist when the player dimensions are ' + 1172 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 ...@@ -1498,7 +1507,7 @@ test('waits to download new segments until the media playlist is stable', functi
1498 standardXHRResponse(requests.shift()); // media1 1507 standardXHRResponse(requests.shift()); // media1
1499 1508
1500 // force a playlist switch 1509 // force a playlist switch
1501 player.tech_.hls.playlists.media('media3.m3u8'); 1510 player.tech_.hls.playlists.media('media2.m3u8');
1502 1511
1503 standardXHRResponse(requests.shift()); // segment 0 1512 standardXHRResponse(requests.shift()); // segment 0
1504 player.tech_.hls.sourceBuffer.trigger('updateend'); 1513 player.tech_.hls.sourceBuffer.trigger('updateend');
......