diff --git a/AUTHORS b/AUTHORS index 08a07a68e6..4d37ed7643 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,6 +31,7 @@ Edgeware AB <*@edgeware.tv> Esteban Dosztal Fadomire Gil Gonen +Giorgio Gamberoni Giuseppe Samela Google Inc. <*@google.com> Itay Kinnrot diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0ae7c916f3..9a82e23345 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -48,6 +48,7 @@ Esteban Dosztal Fadomire François Beaufort Gil Gonen +Giorgio Gamberoni Giuseppe Samela Hichem Taoufik Itay Kinnrot diff --git a/lib/util/periods.js b/lib/util/periods.js index ec15872c6a..4c45b32712 100644 --- a/lib/util/periods.js +++ b/lib/util/periods.js @@ -263,6 +263,7 @@ shaka.util.PeriodCombiner = class { a1.label == a2.label && a1.codecs == a2.codecs && a1.mimeType == a2.mimeType && + a1.originalId == a2.originalId && ArrayUtils.hasSameElements(a1.roles, a2.roles) && a1.audioSamplingRate == a2.audioSamplingRate && a1.primary == a2.primary) { @@ -298,6 +299,7 @@ shaka.util.PeriodCombiner = class { t1.label == t2.label && t1.codecs == t2.codecs && t1.mimeType == t2.mimeType && + t1.originalId == t2.originalId && ArrayUtils.hasSameElements(t1.roles, t2.roles)) { duplicate = true; } @@ -333,6 +335,7 @@ shaka.util.PeriodCombiner = class { v1.codecs == v2.codecs && v1.mimeType == v2.mimeType && v1.label == v2.label && + v1.originalId == v2.originalId && ArrayUtils.hasSameElements(v1.roles, v2.roles) && MapUtils.hasSameElements(v1.closedCaptions, v2.closedCaptions) && v1.bandwidth == v2.bandwidth) { @@ -365,7 +368,8 @@ shaka.util.PeriodCombiner = class { if (i1.id != i2.id && i1.width == i2.width && i1.codecs == i2.codecs && - i1.mimeType == i2.mimeType) { + i1.mimeType == i2.mimeType && + i1.originalId == i2.originalId) { duplicate = true; } } diff --git a/test/util/periods_unit.js b/test/util/periods_unit.js index ada49fc45e..6676541430 100644 --- a/test/util/periods_unit.js +++ b/test/util/periods_unit.js @@ -446,44 +446,51 @@ describe('PeriodCombiner', () => { it('Filters out duplicate streams', async () => { // v1 and v3 are duplicates const v1 = makeVideoStream(1280); + v1.id = 1; v1.frameRate = 30000/1001; - v1.originalId = 'v1'; + v1.originalId = 'video/1280'; v1.bandwidth = 6200000; const v2 = makeVideoStream(1920); + v2.id = 2; v2.frameRate = 30000/1001; - v2.originalId = 'v2'; + v2.originalId = 'video/1920'; v2.bandwidth = 8000000; const v3 = makeVideoStream(1280); + v3.id = 3; v3.frameRate = 30000/1001; - v3.originalId = 'v3'; + v3.originalId = 'video/1280'; v3.bandwidth = 6200000; // a1 and a2 are duplicates. const a1 = makeAudioStream('en', /* channels= */ 2); - a1.originalId = 'a1'; + a1.id = 1; + a1.originalId = 'audio/65106'; a1.bandwidth = 65106; a1.roles = ['role1', 'role2']; a1.codecs = 'mp4a.40.2'; const a2 = makeAudioStream('en', /* channels= */ 2); - a2.originalId = 'a2'; + a2.id = 2; + a2.originalId = 'audio/65106'; a2.bandwidth = 65106; a2.roles = ['role1', 'role2']; a2.codecs = 'mp4a.40.2'; const a3 = makeAudioStream('en', /* channels= */ 2); - a3.originalId = 'a3'; + a3.id = 3; + a3.originalId = 'audio/97065'; a3.bandwidth = 97065; a3.roles = ['role1', 'role2']; - a2.codecs = 'mp4a.40.2'; + a3.codecs = 'mp4a.40.2'; // a4 has a different label from a3, and should not // be filtered out. const a4 = makeAudioStream('en', /* channels= */ 2); - a4.originalId = 'a4'; - a4.bandwidth = 97065; + a4.id = 4; + a4.originalId = 'audio/65106'; + a4.bandwidth = 65106; a4.roles = ['role1', 'role2']; a4.label = 'Surround'; a4.codecs = 'mp4a.40.2'; @@ -491,33 +498,59 @@ describe('PeriodCombiner', () => { // a5 has a different codec from a3, and should not // be filtered out. const a5 = makeAudioStream('en', /* channels= */ 2); - a5.originalId = 'a5'; + a5.id = 5; + a5.originalId = 'audio/97065'; a5.bandwidth = 97065; a5.roles = ['role1', 'role2']; a5.codecs = 'ec-3'; // t1 and t3 are duplicates. const t1 = makeTextStream('en'); - t1.originalId = 't1'; + t1.id = 1; + t1.originalId = 'text/en'; + t1.language = 'en'; + t1.mimeType = 'application/mp4'; + t1.codecs = 'stpp'; t1.roles = ['role1']; const t2 = makeTextStream('en'); - t2.originalId = 't2'; + t2.id = 2; + t2.originalId = 'text/en'; + t2.language = 'en'; + t2.mimeType = 'application/mp4'; + t2.codecs = 'stpp'; t2.roles = ['role1', 'role2']; const t3 = makeTextStream('en'); - t3.originalId = 't3'; + t3.id = 3; + t3.originalId = 'text/en'; + t3.language = 'en'; + t3.mimeType = 'application/mp4'; + t3.codecs = 'stpp'; t3.roles = ['role1']; + // t4 has a different original Id from t3, and should not + // be filtered out. + const t4 = makeAudioStream('en', /* channels= */ 2); + t4.id = 4; + t4.originalId = 'text/en-us'; + t4.language = 'en'; + t4.mimeType = 'application/mp4'; + t4.codecs = 'stpp'; + t4.roles = ['role1']; + // i1 and i3 are duplicates. const i1 = makeImageStream(240); - i1.originalId = 'i1'; + i1.id = 1; + i1.originalId = 'image/240'; const i2 = makeImageStream(480); - i2.originalId = 'i2'; + i2.id = 2; + i2.originalId = 'image/480'; const i3 = makeImageStream(240); - i3.originalId = 'i3'; + i3.id = 3; + i3.originalId = 'image/240'; /** @type {!Array.} */ const periods = [ @@ -539,6 +572,7 @@ describe('PeriodCombiner', () => { t1, t2, t3, + t4, ], imageStreams: [ i1, @@ -553,33 +587,33 @@ describe('PeriodCombiner', () => { expect(variants.length).toBe(8); // v3 should've been filtered out - const videoIds = variants.map((v) => v.video.originalId); + const videoIds = variants.map((v) => v.video.id); for (const id of videoIds) { - expect(id).not.toBe('v3'); + expect(id).not.toBe(3); } // a2 should've been filtered out - const audioIds = variants.map((v) => v.audio.originalId); + const audioIds = variants.map((v) => v.audio.id); for (const id of audioIds) { - expect(id).not.toBe('a2'); + expect(id).not.toBe(2); } const textStreams = combiner.getTextStreams(); - expect(textStreams.length).toBe(2); + expect(textStreams.length).toBe(3); // t3 should've been filtered out - const textIds = textStreams.map((t) => t.originalId); + const textIds = textStreams.map((t) => t.id); for (const id of textIds) { - expect(id).not.toBe('t3'); + expect(id).not.toBe(3); } const imageStreams = combiner.getImageStreams(); expect(imageStreams.length).toBe(2); // i3 should've been filtered out - const imageIds = imageStreams.map((i) => i.originalId); + const imageIds = imageStreams.map((i) => i.id); for (const id of imageIds) { - expect(id).not.toBe('i3'); + expect(id).not.toBe(3); } });