Skip to content

Commit

Permalink
fix: Fix DASH rejection of streams with ColourPrimaries and MatrixCoe…
Browse files Browse the repository at this point in the history
…fficients (shaka-project#5345)

Add ColourPrimaries and MatrixCoefficients schemes as specified by
https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf.

In particular, `ColourPrimaries` and `MatrixCoefficients` schemes were
considered "unrecognizedEssentialProperty", causing some
streams with valid manifests to discard the video track.
  • Loading branch information
davidezordan committed Jun 26, 2023
1 parent 5487236 commit 226ffa9
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 3 deletions.
21 changes: 18 additions & 3 deletions lib/dash/dash_parser.js
Expand Up @@ -896,7 +896,19 @@ shaka.dash.DashParser = class {

// Parallel for HLS VIDEO-RANGE as defined in DASH-IF IOP v4.3 6.2.5.1.
let videoRange;
const videoRangeScheme = 'urn:mpeg:mpegB:cicp:TransferCharacteristics';

// Ref. https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf
// If signaled, a Supplemental or Essential Property descriptor
// shall be used, with the schemeIdUri set to
// urn:mpeg:mpegB:cicp:<Parameter> as defined in
// ISO/IEC 23001-8 [49] and <Parameter> one of the
// following: ColourPrimaries, TransferCharacteristics,
// or MatrixCoefficients.
const scheme = 'urn:mpeg:mpegB:cicp';
const transferCharacteristicsScheme = `${scheme}:TransferCharacteristics`;
const colourPrimariesScheme = `${scheme}:ColourPrimaries`;
const matrixCoefficientsScheme = `${scheme}:MatrixCoefficients`;

const getVideoRangeFromTransferCharacteristicCICP = (cicp) => {
switch (cicp) {
case 1:
Expand All @@ -922,10 +934,13 @@ shaka.dash.DashParser = class {
const schemeId = prop.getAttribute('schemeIdUri');
if (schemeId == 'http://dashif.org/guidelines/trickmode') {
trickModeFor = prop.getAttribute('value');
} else if (schemeId == videoRangeScheme) {
} else if (schemeId == transferCharacteristicsScheme) {
videoRange = getVideoRangeFromTransferCharacteristicCICP(
parseInt(prop.getAttribute('value'), 10),
);
} else if (schemeId == colourPrimariesScheme ||
schemeId == matrixCoefficientsScheme) {
continue;
} else {
unrecognizedEssentialProperty = true;
}
Expand All @@ -935,7 +950,7 @@ shaka.dash.DashParser = class {
XmlUtils.findChildren(elem, 'SupplementalProperty');
for (const prop of supplementalProperties) {
const schemeId = prop.getAttribute('schemeIdUri');
if (schemeId == videoRangeScheme) {
if (schemeId == transferCharacteristicsScheme) {
videoRange = getVideoRangeFromTransferCharacteristicCICP(
parseInt(prop.getAttribute('value'), 10),
);
Expand Down
120 changes: 120 additions & 0 deletions test/dash/dash_parser_manifest_unit.js
Expand Up @@ -2068,6 +2068,66 @@ describe('DashParser Manifest', () => {
expect(stream.hdr).toBe('PQ');
});

it('supports SupplementalProperty MatrixCoefficients', async () => {
// (DASH-IF IOP v4.3 6.2.5.1.)
const scheme = cicpScheme('MatrixCoefficients');
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="2" mimeType="video/mp4">',
` <SupplementalProperty schemeIdUri="${scheme}" value="9" />`,
' <Representation codecs="hvc1.2.4.L153.B0">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' <AdaptationSet id="3" mimeType="audio/mp4">',
' <Representation id="audio-en">',
' <BaseURL>a-en.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);
expect(manifest.variants.length).toBe(1);
});

it('supports SupplementalProperty ColourPrimaries', async () => {
// (DASH-IF IOP v4.3 6.2.5.1.)
const scheme = cicpScheme('ColourPrimaries');
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="2" mimeType="video/mp4">',
` <SupplementalProperty schemeIdUri="${scheme}" value="9" />`,
' <Representation codecs="hvc1.2.4.L153.B0">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' <AdaptationSet id="3" mimeType="audio/mp4">',
' <Representation id="audio-en">',
' <BaseURL>a-en.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);
expect(manifest.variants.length).toBe(1);
});

it('supports HDR signaling via EssentialProperty', async () => {
// (DASH-IF IOP v4.3 6.2.5.1.)
const hdrScheme = cicpScheme('TransferCharacteristics');
Expand Down Expand Up @@ -2101,6 +2161,66 @@ describe('DashParser Manifest', () => {
expect(stream.hdr).toBe('HLG');
});

it('supports EssentialProperty MatrixCoefficients', async () => {
// (DASH-IF IOP v4.3 6.2.5.1.)
const hdrScheme = cicpScheme('MatrixCoefficients');
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="2" mimeType="video/mp4">',
` <EssentialProperty schemeIdUri="${hdrScheme}" value="9" />`,
' <Representation codecs="hvc1.2.4.L153.B0">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' <AdaptationSet id="3" mimeType="audio/mp4">',
' <Representation id="audio-en">',
' <BaseURL>a-en.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);
expect(manifest.variants.length).toBe(1);
});

it('supports EssentialProperty ColourPrimaries', async () => {
// (DASH-IF IOP v4.3 6.2.5.1.)
const hdrScheme = cicpScheme('ColourPrimaries');
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="2" mimeType="video/mp4">',
` <EssentialProperty schemeIdUri="${hdrScheme}" value="9" />`,
' <Representation codecs="hvc1.2.4.L153.B0">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' <AdaptationSet id="3" mimeType="audio/mp4">',
' <Representation id="audio-en">',
' <BaseURL>a-en.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);
expect(manifest.variants.length).toBe(1);
});

it('supports SDR signalling via EssentialProperty', async () => {
// (DASH-IF IOP v4.3 6.2.5.1.)
const scheme = cicpScheme('TransferCharacteristics');
Expand Down

0 comments on commit 226ffa9

Please sign in to comment.