From f2b9e3fdf19ba8a0cd45f4b5086804fa49163577 Mon Sep 17 00:00:00 2001 From: Michelle Zhuo Date: Tue, 6 Nov 2018 14:01:43 -0800 Subject: [PATCH] Add support for CEA with no channel and language info for Dash When the dash content has CEA closed captions signal but no detail information about channel number and language, we show the default caption information. Issue #1404 Change-Id: Ie6ca77739a043d24832efc5a28d4ba708dc4b17f --- lib/dash/dash_parser.js | 26 +++++++---- test/dash/dash_parser_manifest_unit.js | 63 ++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js index db8cd39e54..4a68aef8e8 100644 --- a/lib/dash/dash_parser.js +++ b/lib/dash/dash_parser.js @@ -1014,25 +1014,25 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) { const accessibilities = XmlUtils.findChildren(elem, 'Accessibility'); const LanguageUtils = shaka.util.LanguageUtils; let closedCaptions = new Map(); - let captionId = 0; for (const prop of accessibilities) { let schemeId = prop.getAttribute('schemeIdUri'); if (schemeId == 'urn:scte:dash:cc:cea-608:2015' || schemeId == 'urn:scte:dash:cc:cea-708:2015') { + let channelId = 1; let closedCaptionsValue = prop.getAttribute('value'); if (closedCaptionsValue != null) { closedCaptionsValue.split(';').forEach((captionStr) => { + let channel; + let language; // Some closed caption descriptions have channel number and language, // like "CC1=eng" or "1=lang:eng", others may only have the language, // like "eng". - // Since only odd numbers are used as channel numbers, like CC1, CC3, - // CC5, etc, when the channel number is not provided, use an odd - // number as the key. https://en.wikipedia.org/wiki/EIA-608 - let channel; - let language; if (!captionStr.includes('=')) { - channel = 'CC' + ((captionId * 2) + 1); - captionId++; + // Since only odd numbers are used as channel numbers, like CC1, + // CC3, CC5, etc, when the channel number is not provided, use an + // odd number as the key. https://en.wikipedia.org/wiki/EIA-608 + channel = 'CC' + channelId; + channelId += 2; language = captionStr; } else { const channelAndLanguage = captionStr.split('='); @@ -1041,11 +1041,17 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) { // as prefix so that it can be a full channel id (like 'CC1'). channel = channelAndLanguage[0].startsWith('CC') ? channelAndLanguage[0] : 'CC' + channelAndLanguage[0]; - // The language info can be 'eng' or 'lang:eng'. - language = channelAndLanguage[1].split(':').pop(); + // The language info can be different formats, like 'eng', + // 'lang:eng', or 'lang:eng,war:1,er:1'. Extract the language info + // and convert it to 2-letter language code format. + language = channelAndLanguage[1].split(',')[0].split(':').pop(); } closedCaptions.set(channel, LanguageUtils.normalize(language)); }); + } else { + // If channel and language information has not been provided, assign + // 'CC1' as channel id and 'und' as language info. + closedCaptions.set('CC1', 'und'); } } } diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js index 603692f83c..fed4a142bc 100644 --- a/test/dash/dash_parser_manifest_unit.js +++ b/test/dash/dash_parser_manifest_unit.js @@ -311,9 +311,9 @@ describe('DashParser Manifest', function() { }, 0, null)); }); - - it('correctly parses closed captions with channel numbers', async () => { - let source = [ + it('correctly parses closed captions with channels and languages', + async () => { + const source = [ '', ' ', ' ', @@ -323,26 +323,45 @@ describe('DashParser Manifest', function() { ' ', ' ', ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', ' ', '', ].join('\n'); fakeNetEngine.setResponseText('dummy://foo', source); - let manifest = await parser.start('dummy://foo', playerInterface); + const manifest = await parser.start('dummy://foo', playerInterface); // First Representation should be dropped. - let period = manifest.periods[0]; - let stream = period.variants[0].video; + const period = manifest.periods[0]; + const stream1 = period.variants[0].video; + const stream2 = period.variants[1].video; + const stream3 = period.variants[2].video; + const expectedClosedCaptions = new Map( [['CC1', shaka.util.LanguageUtils.normalize('eng')], ['CC3', shaka.util.LanguageUtils.normalize('swe')]] ); - expect(stream.closedCaptions).toEqual(expectedClosedCaptions); + expect(stream1.closedCaptions).toEqual(expectedClosedCaptions); + expect(stream2.closedCaptions).toEqual(expectedClosedCaptions); + expect(stream3.closedCaptions).toEqual(expectedClosedCaptions); }); it('correctly parses closed captions without channel numbers', async () => { - let source = [ + const source = [ '', ' ', ' ', @@ -358,8 +377,8 @@ describe('DashParser Manifest', function() { fakeNetEngine.setResponseText('dummy://foo', source); - let manifest = await parser.start('dummy://foo', playerInterface); - let stream = manifest.periods[0].variants[0].video; + const manifest = await parser.start('dummy://foo', playerInterface); + const stream = manifest.periods[0].variants[0].video; const expectedClosedCaptions = new Map( [['CC1', shaka.util.LanguageUtils.normalize('eng')], ['CC3', shaka.util.LanguageUtils.normalize('swe')]] @@ -368,6 +387,30 @@ describe('DashParser Manifest', function() { }); + it('correctly parses closed captions with no channel and language info', + async () => { + const source = [ + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '', + ].join('\n'); + + fakeNetEngine.setResponseText('dummy://foo', source); + + const manifest = await parser.start('dummy://foo', playerInterface); + const stream = manifest.periods[0].variants[0].video; + const expectedClosedCaptions = new Map([['CC1', 'und']]); + expect(stream.closedCaptions).toEqual(expectedClosedCaptions); + }); + + it('correctly parses UTF-8', async () => { let source = [ '',