Skip to content

Commit

Permalink
fix: Fix support for supplemental codecs (Dolby Vision)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Dec 5, 2024
1 parent ccc90b6 commit da9b144
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 78 deletions.
26 changes: 18 additions & 8 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1973,6 +1973,24 @@ shaka.dash.DashParser = class {

// Parse Representations into Streams.
const representations = TXml.findChildren(elem, 'Representation');
if (!this.config_.dash.ignoreSupplementalCodecs) {
// Duplicate representations with their supplementalCodecs
let supplementalRepresentations = representations.filter((rep) => {
return TXml.getAttributeNS(
rep, shaka.dash.DashParser.SCTE214_, 'supplementalCodecs') != null;
});
supplementalRepresentations = supplementalRepresentations.map((rep) => {
const supplementalCodecs =
TXml.getAttributeNS(
rep, shaka.dash.DashParser.SCTE214_, 'supplementalCodecs');
const obj = shaka.util.ObjectUtils.cloneObject(rep);
obj.attributes['codecs'] = supplementalCodecs.split(' ').join(',');
return obj;
});
if (supplementalRepresentations.length) {
representations.push(...supplementalRepresentations);
}
}
const streams = representations.map((representation) => {
const parsedRepresentation = this.parseRepresentation_(context,
contentProtection, kind, language, label, main, roleValues,
Expand Down Expand Up @@ -2541,7 +2559,6 @@ shaka.dash.DashParser = class {
createFrame_(elem, parent, getBaseUris) {
goog.asserts.assert(parent || getBaseUris,
'Must provide either parent or getBaseUris');
const SCTE214 = shaka.dash.DashParser.SCTE214_;
const SegmentUtils = shaka.media.SegmentUtils;
const ManifestParserUtils = shaka.util.ManifestParserUtils;
const TXml = shaka.util.TXml;
Expand Down Expand Up @@ -2599,13 +2616,6 @@ shaka.dash.DashParser = class {
const allCodecs = [
elem.attributes['codecs'] || parent.codecs,
];
if (!this.config_.dash.ignoreSupplementalCodecs) {
const supplementalCodecs =
TXml.getAttributeNS(elem, SCTE214, 'supplementalCodecs');
if (supplementalCodecs) {
allCodecs.push(supplementalCodecs);
}
}
const codecs = SegmentUtils.codecsFiltering(allCodecs).join(',');
const frameRate =
TXml.parseAttr(elem, 'frameRate', evalDivision) || parent.frameRate;
Expand Down
58 changes: 44 additions & 14 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ goog.provide('shaka.hls.HlsParser');
goog.require('goog.Uri');
goog.require('goog.asserts');
goog.require('shaka.abr.Ewma');
goog.require('shaka.hls.Attribute');
goog.require('shaka.hls.ManifestTextParser');
goog.require('shaka.hls.Playlist');
goog.require('shaka.hls.PlaylistType');
Expand Down Expand Up @@ -957,6 +958,35 @@ shaka.hls.HlsParser = class {
this.processSessionData_(sessionDataTags);
await this.processContentSteering_(contentSteeringTags);

if (!this.config_.hls.ignoreSupplementalCodecs) {
// Duplicate variant tags with supplementalCodecs
const newVariantTags = [];
for (const tag of variantTags) {
const supplementalCodecsString =
tag.getAttributeValue('SUPPLEMENTAL-CODECS');
if (!supplementalCodecsString) {
continue;
}
const supplementalCodecs = supplementalCodecsString.split(/\s*,\s*/)
.map((codec) => {
return codec.split('/')[0];
});
const newAttributes = tag.attributes.map((attr) => {
const name = attr.name;
let value = attr.value;
if (name == 'CODECS') {
value = supplementalCodecs.join(',');
}
return new shaka.hls.Attribute(name, value);
});
newVariantTags.push(
new shaka.hls.Tag(tag.id, tag.name, newAttributes, null));
}
if (newVariantTags.length) {
variantTags.push(...newVariantTags);
}
}

this.parseCodecs_(variantTags);

this.parseClosedCaptions_(mediaTags);
Expand Down Expand Up @@ -1813,9 +1843,6 @@ shaka.hls.HlsParser = class {
getCodecsForVariantTag_(tag) {
let codecsString = tag.getAttributeValue('CODECS') || '';

const supplementalCodecsString =
tag.getAttributeValue('SUPPLEMENTAL-CODECS');

this.codecInfoInManifest_ = codecsString.length > 0;

if (!this.codecInfoInManifest_ && !this.config_.hls.disableCodecGuessing) {
Expand All @@ -1836,15 +1863,6 @@ shaka.hls.HlsParser = class {
/** @type {!Array.<string>} */
const codecs = codecsString.split(/\s*,\s*/);

if (!this.config_.hls.ignoreSupplementalCodecs &&
supplementalCodecsString) {
const supplementalCodecs = supplementalCodecsString.split(/\s*,\s*/)
.map((codec) => {
return codec.split('/')[0];
});
codecs.push(...supplementalCodecs);
}

return shaka.media.SegmentUtils.codecsFiltering(codecs);
}

Expand Down Expand Up @@ -2040,7 +2058,18 @@ shaka.hls.HlsParser = class {
videoInfo ? videoInfo.getUris().sort().join(',') : '';
const audioStreamUri =
audioInfo ? audioInfo.getUris().sort().join(',') : '';
const variantUriKey = videoStreamUri + ' - ' + audioStreamUri;
const codecs = [];
if (audioStream && audioStream.codecs) {
codecs.push(audioStream.codecs);
}
if (videoStream && videoStream.codecs) {
codecs.push(videoStream.codecs);
}
const variantUriKey = [
videoStreamUri,
audioStreamUri,
codecs.sort(),
].join('-');

if (audioStream && videoStream) {
if (!DrmUtils.areDrmCompatible(audioDrmInfos, videoDrmInfos)) {
Expand Down Expand Up @@ -2360,7 +2389,8 @@ shaka.hls.HlsParser = class {
verbatimMediaPlaylistUris.push(uri);
}

const key = verbatimMediaPlaylistUris.sort().join(',');
const key = verbatimMediaPlaylistUris.sort().join(',') +
allCodecs.sort().join(',');
if (this.uriToStreamInfosMap_.has(key)) {
return this.uriToStreamInfosMap_.get(key);
}
Expand Down
36 changes: 8 additions & 28 deletions test/dash/dash_parser_manifest_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ describe('DashParser Manifest', () => {
*/
const cicpScheme = (parameter) => `urn:mpeg:mpegB:cicp:${parameter}`;

const originalIsTypeSupported = window.MediaSource.isTypeSupported;
let originalIsTypeSupportedManaged;
if (window.ManagedMediaSource) {
originalIsTypeSupportedManaged = window.ManagedMediaSource.isTypeSupported;
}

beforeAll(async () => {
mp4Index = await shaka.test.Util.fetch(mp4IndexSegmentUri);
});
Expand Down Expand Up @@ -69,26 +63,11 @@ describe('DashParser Manifest', () => {
disableStream: (stream) => {},
addFont: shaka.test.Util.spyFunc(addFontSpy),
};
window.MediaSource.isTypeSupported = (mimeType) => {
const type = mimeType.split('/')[0];
return type == 'video' || type == 'audio';
};
if (window.ManagedMediaSource) {
window.ManagedMediaSource.isTypeSupported = (mimeType) => {
const type = mimeType.split('/')[0];
return type == 'video' || type == 'audio';
};
}
});

afterEach(() => {
// Dash parser stop is synchronous.
parser.stop();
window.MediaSource.isTypeSupported = originalIsTypeSupported;
if (window.ManagedMediaSource) {
window.ManagedMediaSource.isTypeSupported =
originalIsTypeSupportedManaged;
}
});

/**
Expand Down Expand Up @@ -3705,12 +3684,14 @@ describe('DashParser Manifest', () => {
/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('dummy://foo', playerInterface);

expect(manifest.variants.length).toBe(1);
expect(manifest.variants.length).toBe(2);
expect(manifest.textStreams.length).toBe(0);

const variant = manifest.variants[0];
const video = variant && variant.video;
expect(video.codecs).toBe('dav1.10.01');
const video1 = manifest.variants[0] && manifest.variants[0].video;
expect(video1.codecs).toBe('av01.0.04M.10.0.111.09.16.09.0');

const video2 = manifest.variants[1] && manifest.variants[1].video;
expect(video2.codecs).toBe('dav1.10.01');
});

it('ignore scte214:supplementalCodecs by config', async () => {
Expand Down Expand Up @@ -3744,8 +3725,7 @@ describe('DashParser Manifest', () => {
expect(manifest.variants.length).toBe(1);
expect(manifest.textStreams.length).toBe(0);

const variant = manifest.variants[0];
const video = variant && variant.video;
expect(video.codecs).toBe('av01.0.04M.10.0.111.09.16.09.0');
const video1 = manifest.variants[0] && manifest.variants[0].video;
expect(video1.codecs).toBe('av01.0.04M.10.0.111.09.16.09.0');
});
});
36 changes: 8 additions & 28 deletions test/hls/hls_parser_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,9 @@ describe('HlsParser', () => {
/** @type {!boolean} */
let sequenceMode;

const originalIsTypeSupported = window.MediaSource.isTypeSupported;
let originalIsTypeSupportedManaged;
if (window.ManagedMediaSource) {
originalIsTypeSupportedManaged = window.ManagedMediaSource.isTypeSupported;
}

afterEach(() => {
shaka.log.alwaysWarn = originalAlwaysWarn;
parser.stop();
window.MediaSource.isTypeSupported = originalIsTypeSupported;
if (window.ManagedMediaSource) {
window.ManagedMediaSource.isTypeSupported =
originalIsTypeSupportedManaged;
}
});

beforeEach(async () => {
Expand Down Expand Up @@ -113,16 +102,6 @@ describe('HlsParser', () => {

parser = new shaka.hls.HlsParser();
parser.configure(config);
window.MediaSource.isTypeSupported = (mimeType) => {
const type = mimeType.split('/')[0];
return type == 'video' || type == 'audio';
};
if (window.ManagedMediaSource) {
window.ManagedMediaSource.isTypeSupported = (mimeType) => {
const type = mimeType.split('/')[0];
return type == 'video' || type == 'audio';
};
}
});

/**
Expand Down Expand Up @@ -6100,12 +6079,14 @@ describe('HlsParser', () => {
/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('test:/master', playerInterface);

expect(manifest.variants.length).toBe(1);
expect(manifest.variants.length).toBe(2);
expect(manifest.textStreams.length).toBe(0);

const variant = manifest.variants[0];
const video = variant && variant.video;
expect(video.codecs).toBe('dav1.10.01');
const video1 = manifest.variants[0] && manifest.variants[0].video;
expect(video1.codecs).toBe('av01.0.04M.10.0.111.09.16.09.0');

const video2 = manifest.variants[1] && manifest.variants[1].video;
expect(video2.codecs).toBe('dav1.10.01');
});

it('ignore SUPPLEMENTAL-CODECS by config', async () => {
Expand Down Expand Up @@ -6142,8 +6123,7 @@ describe('HlsParser', () => {
expect(manifest.variants.length).toBe(1);
expect(manifest.textStreams.length).toBe(0);

const variant = manifest.variants[0];
const video = variant && variant.video;
expect(video.codecs).toBe('av01.0.04M.10.0.111.09.16.09.0');
const video1 = manifest.variants[0] && manifest.variants[0].video;
expect(video1.codecs).toBe('av01.0.04M.10.0.111.09.16.09.0');
});
});

0 comments on commit da9b144

Please sign in to comment.