Skip to content

Commit

Permalink
feat: Parse colorGamut and use it in MCap (#6663)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed May 24, 2024
1 parent f374173 commit 329d42a
Show file tree
Hide file tree
Showing 18 changed files with 118 additions and 8 deletions.
4 changes: 4 additions & 0 deletions externs/shaka/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ shaka.extern.SegmentIndex = class {
* frameRate: (number|undefined),
* pixelAspectRatio: (string|undefined),
* hdr: (string|undefined),
* colorGamut: (string|undefined),
* videoLayout: (string|undefined),
* bandwidth: (number|undefined),
* width: (number|undefined),
Expand Down Expand Up @@ -504,6 +505,9 @@ shaka.extern.SegmentIndex = class {
* @property {(string|undefined)} hdr
* <i>Video streams only.</i> <br>
* The Stream's HDR info
* @property {(string|undefined)} colorGamut
* <i>Video streams only.</i> <br>
* The Stream's color gamut info
* @property {(string|undefined)} videoLayout
* <i>Video streams only.</i> <br>
* The Stream's video layout info.
Expand Down
3 changes: 3 additions & 0 deletions externs/shaka/offline.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ shaka.extern.ManifestDB;
* frameRate: (number|undefined),
* pixelAspectRatio: (string|undefined),
* hdr: (string|undefined),
* colorGamut: (string|undefined),
* videoLayout: (string|undefined),
* kind: (string|undefined),
* language: string,
Expand Down Expand Up @@ -166,6 +167,8 @@ shaka.extern.ManifestDB;
* The Stream's pixel aspect ratio
* @property {(string|undefined)} hdr
* The Stream's HDR info
* @property {(string|undefined)} colorGamut
* The Stream's color gamut info
* @property {(string|undefined)} videoLayout
* The Stream's video layout info.
* @property {(string|undefined)} kind
Expand Down
3 changes: 3 additions & 0 deletions externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ shaka.extern.BufferedInfo;
* frameRate: ?number,
* pixelAspectRatio: ?string,
* hdr: ?string,
* colorGamut: ?string,
* videoLayout: ?string,
* mimeType: ?string,
* audioMimeType: ?string,
Expand Down Expand Up @@ -299,6 +300,8 @@ shaka.extern.BufferedInfo;
* The video pixel aspect ratio provided in the manifest, if present.
* @property {?string} hdr
* The video HDR provided in the manifest, if present.
* @property {?string} colorGamut
* The video color gamut provided in the manifest, if present.
* @property {?string} videoLayout
* The video layout provided in the manifest, if present.
* @property {?string} mimeType
Expand Down
32 changes: 30 additions & 2 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,8 @@ shaka.dash.DashParser = class {
// Parallel for HLS VIDEO-RANGE as defined in DASH-IF IOP v4.3 6.2.5.1.
let videoRange;

let colorGamut;

// 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
Expand Down Expand Up @@ -1187,6 +1189,22 @@ shaka.dash.DashParser = class {
return undefined;
};

const getColorGamutFromColourPrimariesCICP = (cicp) => {
switch (cicp) {
case 1:
case 5:
case 6:
case 7:
return 'srgb';
case 9:
return 'rec2020';
case 11:
case 12:
return 'p3';
}
return undefined;
};

const essentialProperties =
TXml.findChildren(elem, 'EssentialProperty');
// ID of real AdaptationSet if this is a trick mode set:
Expand All @@ -1201,8 +1219,11 @@ shaka.dash.DashParser = class {
videoRange = getVideoRangeFromTransferCharacteristicCICP(
parseInt(prop.attributes['value'], 10),
);
} else if (schemeId == colourPrimariesScheme ||
schemeId == matrixCoefficientsScheme) {
} else if (schemeId == colourPrimariesScheme) {
colorGamut = getColorGamutFromColourPrimariesCICP(
parseInt(prop.attributes['value'], 10),
);
} else if (schemeId == matrixCoefficientsScheme) {
continue;
} else if (schemeId == 'urn:mpeg:dash:ssr:2023' &&
this.config_.dash.enableFastSwitching) {
Expand All @@ -1224,6 +1245,10 @@ shaka.dash.DashParser = class {
videoRange = getVideoRangeFromTransferCharacteristicCICP(
parseInt(prop.attributes['value'], 10),
);
} else if (schemeId == colourPrimariesScheme) {
colorGamut = getColorGamutFromColourPrimariesCICP(
parseInt(prop.attributes['value'], 10),
);
}
}

Expand Down Expand Up @@ -1370,6 +1395,8 @@ shaka.dash.DashParser = class {
lastSegmentNumber);
if (parsedRepresentation) {
parsedRepresentation.hdr = parsedRepresentation.hdr || videoRange;
parsedRepresentation.colorGamut =
parsedRepresentation.colorGamut || colorGamut;
parsedRepresentation.fastSwitching = isFastSwitching;
}
return parsedRepresentation;
Expand Down Expand Up @@ -1688,6 +1715,7 @@ shaka.dash.DashParser = class {
spatialAudio,
closedCaptions,
hdr,
colorGamut: undefined,
videoLayout: undefined,
tilesLayout,
accessibilityPurpose,
Expand Down
12 changes: 9 additions & 3 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,7 @@ shaka.hls.HlsParser = class {
const sampleRate = basicInfo.sampleRate;
const closedCaptions = basicInfo.closedCaptions;
const videoRange = basicInfo.videoRange;
const colorGamut = basicInfo.colorGamut;

// Some values we cannot figure out, and aren't important enough to ask
// the user to provide through config values. A lot of these are only
Expand All @@ -781,7 +782,8 @@ shaka.hls.HlsParser = class {

if (type == 'video') {
this.addVideoAttributes_(streamInfo.stream, width, height,
/* frameRate= */ null, videoRange, /* videoLayout= */ null);
/* frameRate= */ null, videoRange, /* videoLayout= */ null,
colorGamut);
}

// Wrap the stream from that stream info with a variant.
Expand Down Expand Up @@ -1830,7 +1832,8 @@ shaka.hls.HlsParser = class {

for (const info of videoInfos) {
this.addVideoAttributes_(
info.stream, width, height, frameRate, videoRange, videoLayout);
info.stream, width, height, frameRate, videoRange, videoLayout,
/** colorGamut= */ null);
}

// In case of audio-only or video-only content or the audio/video is
Expand Down Expand Up @@ -2810,6 +2813,7 @@ shaka.hls.HlsParser = class {
spatialAudio,
closedCaptions,
hdr: undefined,
colorGamut: undefined,
videoLayout: undefined,
tilesLayout: undefined,
accessibilityPurpose: accessibilityPurpose,
Expand Down Expand Up @@ -3986,16 +3990,18 @@ shaka.hls.HlsParser = class {
* @param {?string} frameRate
* @param {?string} videoRange
* @param {?string} videoLayout
* @param {?string} colorGamut
* @private
*/
addVideoAttributes_(stream, width, height, frameRate, videoRange,
videoLayout) {
videoLayout, colorGamut) {
if (stream) {
stream.width = Number(width) || undefined;
stream.height = Number(height) || undefined;
stream.frameRate = Number(frameRate) || undefined;
stream.hdr = videoRange || undefined;
stream.videoLayout = videoLayout || undefined;
stream.colorGamut = colorGamut || undefined;
}
}

Expand Down
13 changes: 11 additions & 2 deletions lib/media/segment_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ shaka.media.SegmentUtils = class {
sampleRate: null,
closedCaptions: new Map(),
videoRange: null,
colorGamut: null,
};
}

Expand Down Expand Up @@ -125,6 +126,7 @@ shaka.media.SegmentUtils = class {
sampleRate: null,
closedCaptions: closedCaptions,
videoRange: null,
colorGamut: null,
};
}

Expand Down Expand Up @@ -199,6 +201,8 @@ shaka.media.SegmentUtils = class {
let sampleRate = null;
/** @type {?string} */
let realVideoRange = null;
/** @type {?string} */
let realColorGamut = null;

/** @type {?string} */
let baseBox;
Expand Down Expand Up @@ -371,8 +375,10 @@ shaka.media.SegmentUtils = class {
})

.box('colr', (box) => {
const {videoRange} = shaka.util.Mp4BoxParsers.parseCOLR(box.reader);
const {videoRange, colorGamut} =
shaka.util.Mp4BoxParsers.parseCOLR(box.reader);
realVideoRange = videoRange;
realColorGamut = colorGamut;
})

.parse(initData || data, /* partialOkay= */ true);
Expand Down Expand Up @@ -404,6 +410,7 @@ shaka.media.SegmentUtils = class {
sampleRate: sampleRate,
closedCaptions: closedCaptions,
videoRange: realVideoRange,
colorGamut: realColorGamut,
};
}

Expand Down Expand Up @@ -520,7 +527,8 @@ shaka.media.SegmentUtils = class {
* channelCount: ?number,
* sampleRate: ?number,
* closedCaptions: Map.<string, string>,
* videoRange: ?string
* videoRange: ?string,
* colorGamut: ?string
* }}
*
* @property {string} type
Expand All @@ -533,5 +541,6 @@ shaka.media.SegmentUtils = class {
* @property {?number} sampleRate
* @property {Map.<string, string>} closedCaptions
* @property {?string} videoRange
* @property {?string} colorGamut
*/
shaka.media.SegmentUtils.BasicInfo;
1 change: 1 addition & 0 deletions lib/mss/mss_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ shaka.mss.MssParser = class {
spatialAudio: false,
closedCaptions: null,
hdr: undefined,
colorGamut: undefined,
videoLayout: undefined,
tilesLayout: undefined,
matchedStreams: [],
Expand Down
1 change: 1 addition & 0 deletions lib/offline/indexeddb/v1_storage_cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ shaka.offline.indexeddb.V1StorageCell = class
frameRate: old.frameRate,
pixelAspectRatio: undefined,
hdr: undefined,
colorGamut: undefined,
videoLayout: undefined,
kind: old.kind,
language: old.language,
Expand Down
1 change: 1 addition & 0 deletions lib/offline/indexeddb/v2_storage_cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ shaka.offline.indexeddb.V2StorageCell = class
frameRate: old.frameRate,
pixelAspectRatio: old.pixelAspectRatio,
hdr: undefined,
colorGamut: undefined,
videoLayout: undefined,
kind: old.kind,
language: old.language,
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 @@ -192,6 +192,7 @@ shaka.offline.ManifestConverter = class {
frameRate: streamDB.frameRate,
pixelAspectRatio: streamDB.pixelAspectRatio,
hdr: streamDB.hdr,
colorGamut: streamDB.colorGamut,
videoLayout: streamDB.videoLayout,
kind: streamDB.kind,
encrypted: streamDB.encrypted,
Expand Down
1 change: 1 addition & 0 deletions lib/offline/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,7 @@ shaka.offline.Storage = class {
frameRate: stream.frameRate,
pixelAspectRatio: stream.pixelAspectRatio,
hdr: stream.hdr,
colorGamut: stream.colorGamut,
videoLayout: stream.videoLayout,
kind: stream.kind,
language: stream.language,
Expand Down
24 changes: 23 additions & 1 deletion lib/util/mp4_box_parsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ shaka.util.Mp4BoxParsers = class {
* @return {!shaka.util.ParsedCOLRBox}
*/
static parseCOLR(reader) {
let colorGamut = null;
let videoRange = null;
const data = reader.readBytes(4);
let colorType = '';
Expand All @@ -563,6 +564,22 @@ shaka.util.Mp4BoxParsers = class {
colorType += String.fromCharCode(data[2]);
colorType += String.fromCharCode(data[3]);
if (colorType === 'nclx') {
const colorPrimaries = reader.readUint16();
switch (colorPrimaries) {
case 1:
case 5:
case 6:
case 7:
colorGamut = 'srgb';
break;
case 9:
colorGamut = 'rec2020';
break;
case 11:
case 12:
colorGamut = 'p3';
break;
}
reader.readUint16(); // colour_primaries
const transferCharacteristics = reader.readUint16();
reader.readUint16(); // matrix_coefficients
Expand All @@ -582,7 +599,10 @@ shaka.util.Mp4BoxParsers = class {
break;
}
}
return {videoRange};
return {
colorGamut,
videoRange,
};
}

/**
Expand Down Expand Up @@ -913,9 +933,11 @@ shaka.util.ParsedHFOVBox;

/**
* @typedef {{
* colorGamut: ?string,
* videoRange: ?string
* }}
*
* @property {?string} colorGamut
* @property {?string} videoRange
*
* @exportDoc
Expand Down
8 changes: 8 additions & 0 deletions lib/util/stream_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,9 @@ shaka.util.StreamUtils = class {
break;
}
}
if (video.colorGamut) {
videoConfig.colorGamut = video.colorGamut;
}
videoConfigs.push(videoConfig);
}
}
Expand Down Expand Up @@ -1293,6 +1296,7 @@ shaka.util.StreamUtils = class {
frameRate: null,
pixelAspectRatio: null,
hdr: null,
colorGamut: null,
videoLayout: null,
mimeType: mimeType,
audioMimeType: audioMimeType,
Expand Down Expand Up @@ -1329,6 +1333,7 @@ shaka.util.StreamUtils = class {
track.pixelAspectRatio = video.pixelAspectRatio || null;
track.videoBandwidth = video.bandwidth || null;
track.hdr = video.hdr || null;
track.colorGamut = video.colorGamut || null;
track.videoLayout = video.videoLayout || null;
}

Expand Down Expand Up @@ -1370,6 +1375,7 @@ shaka.util.StreamUtils = class {
frameRate: null,
pixelAspectRatio: null,
hdr: null,
colorGamut: null,
videoLayout: null,
mimeType: stream.mimeType,
audioMimeType: null,
Expand Down Expand Up @@ -1447,6 +1453,7 @@ shaka.util.StreamUtils = class {
frameRate: null,
pixelAspectRatio: null,
hdr: null,
colorGamut: null,
videoLayout: null,
mimeType: stream.mimeType,
audioMimeType: null,
Expand Down Expand Up @@ -1574,6 +1581,7 @@ shaka.util.StreamUtils = class {
frameRate: null,
pixelAspectRatio: null,
hdr: null,
colorGamut: null,
videoLayout: null,
mimeType: null,
audioMimeType: null,
Expand Down
2 changes: 2 additions & 0 deletions test/dash/dash_parser_manifest_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,8 @@ describe('DashParser Manifest', () => {
/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('dummy://foo', playerInterface);
expect(manifest.variants.length).toBe(1);
const stream = manifest.variants[0].video;
expect(stream.colorGamut).toBe('rec2020');
});

it('supports HDR signaling via EssentialProperty', async () => {
Expand Down
Loading

0 comments on commit 329d42a

Please sign in to comment.