6c574219 by David LaPalomento

Be more forgiving about incompatibilities

Allow h.264 codecs to mingle with one another. Only exclude variants based on audio if one or the other is using HE-AAC.
1 parent 99a5aeb1
...@@ -294,6 +294,27 @@ videojs.Hls.bufferedAdditions_ = function(original, update) { ...@@ -294,6 +294,27 @@ videojs.Hls.bufferedAdditions_ = function(original, update) {
294 return result; 294 return result;
295 }; 295 };
296 296
297
298 var parseCodecs = function(codecs) {
299 var result = {
300 codecCount: 0,
301 videoCodec: null,
302 audioProfile: null
303 };
304
305 result.codecCount = codecs.split(',').length;
306 result.codecCount = result.codecCount || 2;
307
308 // parse the video codec but ignore the version
309 result.videoCodec = /(^|\s|,)+(avc1)[^ ,]*/i.exec(codecs);
310 result.videoCodec = result.videoCodec && result.videoCodec[2];
311
312 // parse the last field of the audio codec
313 result.audioProfile = /(^|\s|,)+mp4a.\d+\.(\d+)/i.exec(codecs);
314 result.audioProfile = result.audioProfile && result.audioProfile[2];
315
316 return result;
317 };
297 /** 318 /**
298 * Blacklist playlists that are known to be codec or 319 * Blacklist playlists that are known to be codec or
299 * stream-incompatible with the SourceBuffer configuration. For 320 * stream-incompatible with the SourceBuffer configuration. For
...@@ -307,19 +328,46 @@ videojs.Hls.bufferedAdditions_ = function(original, update) { ...@@ -307,19 +328,46 @@ videojs.Hls.bufferedAdditions_ = function(original, update) {
307 * will be excluded from the default playlist selection algorithm 328 * will be excluded from the default playlist selection algorithm
308 * indefinitely. 329 * indefinitely.
309 */ 330 */
310 videojs.HlsHandler.prototype.excludeIncompatibleStreams_ = function(media) { 331 videojs.HlsHandler.prototype.excludeIncompatibleVariants_ = function(media) {
311 var master = this.playlists.master, codecs = ''; 332 var
333 master = this.playlists.master,
334 codecCount = 2,
335 videoCodec = null,
336 audioProfile = null,
337 codecs;
312 338
313 if (media.attributes && media.attributes.CODECS) { 339 if (media.attributes && media.attributes.CODECS) {
314 codecs = media.attributes.CODECS; 340 codecs = parseCodecs(media.attributes.CODECS);
341 videoCodec = codecs.videoCodec;
342 audioProfile = codecs.audioProfile;
343 codecCount = codecs.codecCount;
315 } 344 }
316 master.playlists.forEach(function(variant) { 345 master.playlists.forEach(function(variant) {
317 var variantCodecs = ''; 346 var variantCodecs = {
347 codecCount: 2,
348 videoCodec: null,
349 audioProfile: null
350 };
351
318 if (variant.attributes && variant.attributes.CODECS) { 352 if (variant.attributes && variant.attributes.CODECS) {
319 variantCodecs = variant.attributes.CODECS; 353 variantCodecs = parseCodecs(variant.attributes.CODECS);
354 }
355
356 // if the streams differ in the presence or absence of audio or
357 // video, they are incompatible
358 if (variantCodecs.codecCount !== codecCount) {
359 variant.excludeUntil = Infinity;
320 } 360 }
321 361
322 if (variantCodecs !== codecs) { 362 // if h.264 is specified on the current playlist, some flavor of
363 // it must be specified on all compatible variants
364 if (variantCodecs.videoCodec !== videoCodec) {
365 variant.excludeUntil = Infinity;
366 }
367 // HE-AAC ("mp4a.40.5") is incompatible with all other versions of
368 // AAC audio in Chrome 46. Don't mix the two.
369 if ((variantCodecs.audioProfile === '5' && audioProfile !== '5') ||
370 (audioProfile === '5' && variantCodecs.audioProfile !== '5')) {
323 variant.excludeUntil = Infinity; 371 variant.excludeUntil = Infinity;
324 } 372 }
325 }); 373 });
...@@ -344,7 +392,7 @@ videojs.HlsHandler.prototype.setupSourceBuffer_ = function() { ...@@ -344,7 +392,7 @@ videojs.HlsHandler.prototype.setupSourceBuffer_ = function() {
344 392
345 // exclude any incompatible variant streams from future playlist 393 // exclude any incompatible variant streams from future playlist
346 // selection 394 // selection
347 this.excludeIncompatibleStreams_(media); 395 this.excludeIncompatibleVariants_(media);
348 396
349 // transition the sourcebuffer to the ended state if we've hit the end of 397 // transition the sourcebuffer to the ended state if we've hit the end of
350 // the playlist 398 // the playlist
......
...@@ -1171,6 +1171,50 @@ test('blacklists switching from video-only playlists to video+audio', function() ...@@ -1171,6 +1171,50 @@ test('blacklists switching from video-only playlists to video+audio', function()
1171 equal(videoAudioPlaylist.excludeUntil, Infinity, 'excluded incompatible playlist'); 1171 equal(videoAudioPlaylist.excludeUntil, Infinity, 'excluded incompatible playlist');
1172 }); 1172 });
1173 1173
1174 test('does not blacklist compatible H.264 codec strings', function() {
1175 var master;
1176 player.src({
1177 src: 'manifest/master.m3u8',
1178 type: 'application/vnd.apple.mpegurl'
1179 });
1180 openMediaSource(player);
1181
1182 player.tech_.hls.bandwidth = 1;
1183 requests.shift().respond(200, null,
1184 '#EXTM3U\n' +
1185 '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.5"\n' +
1186 'media.m3u8\n' +
1187 '#EXT-X-STREAM-INF:BANDWIDTH=10,CODECS="avc1.4d400f,mp4a.40.5"\n' +
1188 'media1.m3u8\n'); // master
1189
1190 standardXHRResponse(requests.shift()); // media
1191 master = player.tech_.hls.playlists.master;
1192 strictEqual(master.playlists[0].excludeUntil, undefined, 'did not blacklist');
1193 strictEqual(master.playlists[1].excludeUntil, undefined, 'did not blacklist');
1194 });
1195
1196 test('does not blacklist compatible AAC codec strings', function() {
1197 var master;
1198 player.src({
1199 src: 'manifest/master.m3u8',
1200 type: 'application/vnd.apple.mpegurl'
1201 });
1202 openMediaSource(player);
1203
1204 player.tech_.hls.bandwidth = 1;
1205 requests.shift().respond(200, null,
1206 '#EXTM3U\n' +
1207 '#EXT-X-STREAM-INF:BANDWIDTH=1,CODECS="avc1.4d400d,mp4a.40.2"\n' +
1208 'media.m3u8\n' +
1209 '#EXT-X-STREAM-INF:BANDWIDTH=10,CODECS="avc1.4d400d,mp4a.40.3"\n' +
1210 'media1.m3u8\n'); // master
1211
1212 standardXHRResponse(requests.shift()); // media
1213 master = player.tech_.hls.playlists.master;
1214 strictEqual(master.playlists[0].excludeUntil, undefined, 'did not blacklist');
1215 strictEqual(master.playlists[1].excludeUntil, undefined, 'did not blacklist');
1216 });
1217
1174 test('blacklists switching between playlists with incompatible audio codecs', function() { 1218 test('blacklists switching between playlists with incompatible audio codecs', function() {
1175 var alternatePlaylist; 1219 var alternatePlaylist;
1176 player.src({ 1220 player.src({
......