Skip to content

Commit

Permalink
feat(DASH): Expose accessibility purpose in track (#5216)
Browse files Browse the repository at this point in the history
Closes #5211
  • Loading branch information
theodab authored May 9, 2023
1 parent fecb11a commit 654a028
Show file tree
Hide file tree
Showing 16 changed files with 113 additions and 2 deletions.
3 changes: 3 additions & 0 deletions externs/shaka/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ shaka.extern.FetchCryptoKeysFunction;
* trickModeVideo: ?shaka.extern.Stream,
* emsgSchemeIdUris: ?Array.<string>,
* roles: !Array.<string>,
* accessibilityPurpose: ?shaka.dash.DashParser.AccessibilityPurpose,
* forced: boolean,
* channelsCount: ?number,
* audioSamplingRate: ?number,
Expand Down Expand Up @@ -424,6 +425,8 @@ shaka.extern.FetchCryptoKeysFunction;
* @property {!Array.<string>} roles
* The roles of the stream as they appear on the manifest,
* e.g. 'main', 'caption', or 'commentary'.
* @property {?shaka.dash.DashParser.AccessibilityPurpose} accessibilityPurpose
* The DASH accessibility descriptor, if one was provided for this stream.
* @property {boolean} forced
* <i>Defaults to false.</i> <br>
* Whether the stream set was forced
Expand Down
4 changes: 4 additions & 0 deletions externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ shaka.extern.BufferedInfo;
* primary: boolean,
* roles: !Array.<string>,
* audioRoles: Array.<string>,
* accessibilityPurpose: ?shaka.dash.DashParser.AccessibilityPurpose,
* forced: boolean,
* videoId: ?number,
* audioId: ?number,
Expand Down Expand Up @@ -301,6 +302,9 @@ shaka.extern.BufferedInfo;
* The roles of the audio in the track, e.g. <code>'main'</code> or
* <code>'commentary'</code>. Will be null for text tracks or variant tracks
* without audio.
* @property {?shaka.dash.DashParser.AccessibilityPurpose} accessibilityPurpose
* The DASH accessibility descriptor, if one was provided for this track.
* For text tracks, this describes the text; otherwise, this is for the audio.
* @property {boolean} forced
* True indicates that this in the forced text language for the content.
* This flag is based on signals from the manifest.
Expand Down
28 changes: 26 additions & 2 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,8 @@ shaka.dash.DashParser = class {
const accessibilities = XmlUtils.findChildren(elem, 'Accessibility');
const LanguageUtils = shaka.util.LanguageUtils;
const closedCaptions = new Map();
/** @type {?shaka.dash.DashParser.AccessibilityPurpose} */
let accessibilityPurpose;
for (const prop of accessibilities) {
const schemeId = prop.getAttribute('schemeIdUri');
const value = prop.getAttribute('value');
Expand Down Expand Up @@ -1015,6 +1017,15 @@ shaka.dash.DashParser = class {
kind = ManifestParserUtils.TextStreamKind.CLOSED_CAPTION;
}
}
} else if (schemeId == 'urn:tva:metadata:cs:AudioPurposeCS:2007') {
// See DASH DVB Document A168 Rev.6 Table 5.
if (value == '1') {
accessibilityPurpose =
shaka.dash.DashParser.AccessibilityPurpose.VISUALLY_IMPAIRED;
} else if (value == '2') {
accessibilityPurpose =
shaka.dash.DashParser.AccessibilityPurpose.HARD_OF_HEARING;
}
}
}

Expand Down Expand Up @@ -1057,7 +1068,7 @@ shaka.dash.DashParser = class {
const streams = representations.map((representation) => {
const parsedRepresentation = this.parseRepresentation_(context,
contentProtection, kind, language, label, main, roleValues,
closedCaptions, representation);
closedCaptions, representation, accessibilityPurpose);
if (parsedRepresentation) {
parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
}
Expand Down Expand Up @@ -1133,12 +1144,14 @@ shaka.dash.DashParser = class {
* @param {!Array.<string>} roles
* @param {Map.<string, string>} closedCaptions
* @param {!Element} node
* @param {?shaka.dash.DashParser.AccessibilityPurpose} accessibilityPurpose
*
* @return {?shaka.extern.Stream} The Stream, or null when there is a
* non-critical parsing error.
* @private
*/
parseRepresentation_(context, contentProtection, kind, language, label,
isPrimary, roles, closedCaptions, node) {
isPrimary, roles, closedCaptions, node, accessibilityPurpose) {
const XmlUtils = shaka.util.XmlUtils;
const ContentType = shaka.util.ManifestParserUtils.ContentType;

Expand Down Expand Up @@ -1320,6 +1333,7 @@ shaka.dash.DashParser = class {
hdr,
tilesLayout,
matchedStreams: [],
accessibilityPurpose,
};
}

Expand Down Expand Up @@ -2072,6 +2086,16 @@ shaka.dash.DashParser.AdaptationInfo;
shaka.dash.DashParser.GenerateSegmentIndexFunction;


/**
* @enum {string}
* @export
*/
shaka.dash.DashParser.AccessibilityPurpose = {
VISUALLY_IMPAIRED: 'visually impaired',
HARD_OF_HEARING: 'hard of hearing',
};


/**
* @typedef {{
* generateSegmentIndex: shaka.dash.DashParser.GenerateSegmentIndexFunction
Expand Down
1 change: 1 addition & 0 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2321,6 +2321,7 @@ shaka.hls.HlsParser = class {
closedCaptions,
hdr: undefined,
tilesLayout: undefined,
accessibilityPurpose: null,
};
}

Expand Down
1 change: 1 addition & 0 deletions lib/mss/mss_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ shaka.mss.MssParser = class {
timescale: context.timescale,
codecPrivateData: null,
},
accessibilityPurpose: null,
};

// This is specifically for text tracks.
Expand Down
1 change: 1 addition & 0 deletions lib/offline/manifest_converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ shaka.offline.ManifestConverter = class {
spatialAudio: streamDB.spatialAudio,
closedCaptions: streamDB.closedCaptions,
tilesLayout: streamDB.tilesLayout,
accessibilityPurpose: null,
};

return stream;
Expand Down
4 changes: 4 additions & 0 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
audioSamplingRate: null,
spatialAudio: false,
closedCaptions: null,
accessibilityPurpose: null,
},
bandwidth: 100,
allowedByApplication: true,
Expand Down Expand Up @@ -4860,6 +4861,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
audioSamplingRate: null,
spatialAudio: false,
closedCaptions: null,
accessibilityPurpose: null,
};

const fullMimeType = shaka.util.MimeUtils.getFullType(
Expand Down Expand Up @@ -5011,6 +5013,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
spatialAudio: false,
closedCaptions: null,
tilesLayout: '1x1',
accessibilityPurpose: null,
};

this.manifest_.imageStreams.push(stream);
Expand Down Expand Up @@ -5430,6 +5433,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
audioSamplingRate: null,
spatialAudio: false,
closedCaptions: null,
accessibilityPurpose: null,
};
manifest.textStreams.push(textStream);
closedCaptionsSet.add(id);
Expand Down
1 change: 1 addition & 0 deletions lib/util/periods.js
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,7 @@ shaka.util.PeriodCombiner = class {
audioSamplingRate: null,
spatialAudio: false,
closedCaptions: null,
accessibilityPurpose: null,
};
}

Expand Down
5 changes: 5 additions & 0 deletions lib/util/stream_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,7 @@ shaka.util.StreamUtils = class {
originalAudioId: null,
originalTextId: null,
originalImageId: null,
accessibilityPurpose: null,
};

if (video) {
Expand All @@ -1130,6 +1131,7 @@ shaka.util.StreamUtils = class {
track.spatialAudio = audio.spatialAudio;
track.label = audio.label;
track.audioRoles = audio.roles;
track.accessibilityPurpose = audio.accessibilityPurpose;
}

return track;
Expand Down Expand Up @@ -1179,6 +1181,7 @@ shaka.util.StreamUtils = class {
originalAudioId: null,
originalTextId: stream.originalId,
originalImageId: null,
accessibilityPurpose: stream.accessibilityPurpose,
};

return track;
Expand Down Expand Up @@ -1253,6 +1256,7 @@ shaka.util.StreamUtils = class {
originalAudioId: null,
originalTextId: null,
originalImageId: stream.originalId,
accessibilityPurpose: null,
};

return track;
Expand Down Expand Up @@ -1373,6 +1377,7 @@ shaka.util.StreamUtils = class {
originalAudioId: null,
originalTextId: null,
originalImageId: null,
accessibilityPurpose: null,
};

return track;
Expand Down
43 changes: 43 additions & 0 deletions test/dash/dash_parser_manifest_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -1864,6 +1864,49 @@ describe('DashParser Manifest', () => {
expect(stream).toBeUndefined();
});

it('reads accessibility purpose elements', async () => {
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="1" contentType="text">',
' <Accessibility ',
' schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007"',
' value="2" />',
' <Representation id="text-en" mimeType="text/webvtt">',
' <BaseURL>t-en.vtt</BaseURL>',
' </Representation>',
' </AdaptationSet>',
' <AdaptationSet id="1" mimeType="video/mp4">',
' <Representation id="video-sd" width="640" height="480">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' <AdaptationSet id="1" mimeType="audio/mp4">',
' <Accessibility ',
' schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007"',
' value="1" />',
' <Representation id="audio-sd" width="640" height="480">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' </Period>',
'</MPD>',
].join('\n');

fakeNetEngine.setResponseText('dummy://foo', manifestText);
/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('dummy://foo', playerInterface);
const textStream = manifest.textStreams[0];
expect(textStream.accessibilityPurpose)
.toBe(shaka.dash.DashParser.AccessibilityPurpose.HARD_OF_HEARING);
const variant = manifest.variants[0];
expect(variant.video.accessibilityPurpose).toBeUndefined();
expect(variant.audio.accessibilityPurpose)
.toBe(shaka.dash.DashParser.AccessibilityPurpose.VISUALLY_IMPAIRED);
});

it('converts Accessibility element to "kind"', async () => {
const manifestText = [
'<MPD minBufferTime="PT75S">',
Expand Down
1 change: 1 addition & 0 deletions test/media/adaptation_set_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ describe('AdaptationSet', () => {
forced: false,
trickModeVideo: null,
type: '',
accessibilityPurpose: null,
};
}
});
Expand Down
4 changes: 4 additions & 0 deletions test/offline/manifest_convert_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ describe('ManifestConverter', () => {
spatialAudio: false,
closedCaptions: null,
tilesLayout: undefined,
accessibilityPurpose: null,
};
}

Expand Down Expand Up @@ -438,6 +439,7 @@ describe('ManifestConverter', () => {
spatialAudio: false,
closedCaptions: null,
tilesLayout: undefined,
accessibilityPurpose: null,
};
}

Expand Down Expand Up @@ -486,6 +488,7 @@ describe('ManifestConverter', () => {
spatialAudio: false,
closedCaptions: null,
tilesLayout: undefined,
accessibilityPurpose: null,
};
}

Expand Down Expand Up @@ -531,6 +534,7 @@ describe('ManifestConverter', () => {
spatialAudio: streamDb.spatialAudio,
closedCaptions: streamDb.closedCaptions,
tilesLayout: streamDb.tilesLayout,
accessibilityPurpose: null,
};

expect(stream).toEqual(expectedStream);
Expand Down
2 changes: 2 additions & 0 deletions test/offline/storage_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,7 @@ filterDescribe('Storage', storageSupport, () => {
originalAudioId: audioId.toString(),
originalTextId: null,
originalImageId: null,
accessibilityPurpose: null,
};
}

Expand Down Expand Up @@ -1447,6 +1448,7 @@ filterDescribe('Storage', storageSupport, () => {
originalAudioId: null,
originalTextId: id.toString(),
originalImageId: null,
accessibilityPurpose: null,
};
}

Expand Down
Loading

0 comments on commit 654a028

Please sign in to comment.