Skip to content

Commit

Permalink
feat(DASH): Add support for urn:mpeg:dash:ssr:2023 with SegmentTempla…
Browse files Browse the repository at this point in the history
…te $Number$ (#6745)
  • Loading branch information
avelad authored Jul 9, 2024
1 parent 9fcaf4d commit 3cb40bf
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 14 deletions.
93 changes: 79 additions & 14 deletions lib/dash/segment_template.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ shaka.dash.SegmentTemplate = class {
generateSegmentIndex: () => {
return SegmentTemplate.generateSegmentIndexFromDuration_(
shallowCopyOfContext, info, segmentLimit, initSegmentReference,
periodDurationMap, aesKey, lastSegmentNumber);
periodDurationMap, aesKey, lastSegmentNumber,
context.representation.segmentSequenceCadence);
},
};
} else {
Expand Down Expand Up @@ -253,6 +254,14 @@ shaka.dash.SegmentTemplate = class {
const index = MpdUtils.inheritAttribute(
context, SegmentTemplate.fromInheritance_, 'index');

const k = MpdUtils.inheritAttribute(
context, SegmentTemplate.fromInheritance_, 'k');

let numChunks = 0;
if (k) {
numChunks = parseInt(k, 10);
}

return {
segmentDuration: segmentInfo.segmentDuration,
timescale: segmentInfo.timescale,
Expand All @@ -265,6 +274,7 @@ shaka.dash.SegmentTemplate = class {
indexTemplate: index,
mimeType: context.representation.mimeType,
codecs: context.representation.codecs,
numChunks: numChunks,
};
}

Expand Down Expand Up @@ -358,12 +368,13 @@ shaka.dash.SegmentTemplate = class {
* @param {!Object.<string, number>} periodDurationMap
* @param {shaka.extern.aesKey|undefined} aesKey
* @param {?number} lastSegmentNumber
* @param {number} segmentSequenceCadence
* @return {!Promise.<shaka.media.SegmentIndex>}
* @private
*/
static generateSegmentIndexFromDuration_(
context, info, segmentLimit, initSegmentReference, periodDurationMap,
aesKey, lastSegmentNumber) {
aesKey, lastSegmentNumber, segmentSequenceCadence) {
goog.asserts.assert(info.mediaTemplate,
'There should be a media template with duration');

Expand Down Expand Up @@ -483,16 +494,6 @@ shaka.dash.SegmentTemplate = class {
const segmentMediaTime = segmentPeriodTime +
info.scaledPresentationTimeOffset;

const getUris = () => {
let time = segmentMediaTime * timescale;
if ('BigInt' in window && time > Number.MAX_SAFE_INTEGER) {
time = BigInt(segmentMediaTime) * BigInt(timescale);
}
const mediaUri = MpdUtils.fillUriTemplate(
template, id, position, /* subNumber= */ null, bandwidth, time);
return ManifestParserUtils.resolveUris(getBaseUris(), [mediaUri]);
};

// Relative to the presentation.
const segmentStart = segmentPeriodTime + periodStart;
const trueSegmentEnd = segmentStart + segmentDuration;
Expand All @@ -505,6 +506,67 @@ shaka.dash.SegmentTemplate = class {
goog.asserts.assert(segmentStart < segmentEnd,
'Generated a segment outside of the period!');

const partialSegmentRefs = [];

const numChunks = info.numChunks;
if (numChunks) {
const partialDuration = (segmentEnd - segmentStart) / numChunks;

for (let i = 0; i < numChunks; i++) {
const start = segmentStart + partialDuration * i;
const end = start + partialDuration;
const subNumber = i + 1;
const getPartialUris = () => {
let time = segmentMediaTime * timescale;
if ('BigInt' in window && time > Number.MAX_SAFE_INTEGER) {
time = BigInt(segmentMediaTime) * BigInt(timescale);
}
const mediaUri = MpdUtils.fillUriTemplate(
template, id, position, subNumber, bandwidth, time);
return ManifestParserUtils.resolveUris(getBaseUris(), [mediaUri]);
};
const partial = new shaka.media.SegmentReference(
start,
end,
getPartialUris,
/* startByte= */ 0,
/* endByte= */ null,
initSegmentReference,
timestampOffset,
/* appendWindowStart= */ periodStart,
/* appendWindowEnd= */ getPeriodEnd(),
/* partialReferences= */ [],
/* tilesLayout= */ '',
/* tileDuration= */ null,
/* syncTime= */ null,
shaka.media.SegmentReference.Status.AVAILABLE,
aesKey);
partial.codecs = context.representation.codecs;
partial.mimeType = context.representation.mimeType;
if (segmentSequenceCadence == 0) {
if (i > 0) {
partial.markAsNonIndependent();
}
} else if ((i % segmentSequenceCadence) != 0) {
partial.markAsNonIndependent();
}
partialSegmentRefs.push(partial);
}
}

const getUris = () => {
if (numChunks) {
return [];
}
let time = segmentMediaTime * timescale;
if ('BigInt' in window && time > Number.MAX_SAFE_INTEGER) {
time = BigInt(segmentMediaTime) * BigInt(timescale);
}
const mediaUri = MpdUtils.fillUriTemplate(
template, id, position, /* subNumber= */ null, bandwidth, time);
return ManifestParserUtils.resolveUris(getBaseUris(), [mediaUri]);
};

const ref = new shaka.media.SegmentReference(
segmentStart,
segmentEnd,
Expand All @@ -515,7 +577,7 @@ shaka.dash.SegmentTemplate = class {
timestampOffset,
/* appendWindowStart= */ periodStart,
/* appendWindowEnd= */ getPeriodEnd(),
/* partialReferences= */ [],
partialSegmentRefs,
/* tilesLayout= */ '',
/* tileDuration= */ null,
/* syncTime= */ null,
Expand Down Expand Up @@ -1058,7 +1120,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
* mediaTemplate: ?string,
* indexTemplate: ?string,
* mimeType: string,
* codecs: string
* codecs: string,
* numChunks: number
* }}
*
* @description
Expand All @@ -1084,5 +1147,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
* The mimeType.
* @property {string} codecs
* The codecs.
* @property {number} numChunks
* The number of chunks in each segment.
*/
shaka.dash.SegmentTemplate.SegmentTemplateInfo;
37 changes: 37 additions & 0 deletions test/dash/dash_parser_manifest_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2878,6 +2878,43 @@ describe('DashParser Manifest', () => {
const fourthPartialReference = firstReference.partialReferences[3];
expect(fourthPartialReference.isIndependent()).toBeFalsy();
});

it('with SegmentTemplate and $Number$', async () => {
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="1" mimeType="video/mp4">',
' <Representation bandwidth="1" codecs="avc1.4d401f">',
' <SegmentTemplate startNumber="1" k="4"',
' media="l-$Number$-p$SubNumber$.mp4"',
' initialization="init.mp4" timescale="50" duration="100">',
' </SegmentTemplate>',
' <SegmentSequenceProperties>',
' <SAP type="1" cadence="1" />',
' </SegmentSequenceProperties>',
' </Representation>',
' </AdaptationSet>',
' </Period>',
'</MPD>',
].join('\n');

fakeNetEngine.setResponseText('dummy://foo', manifestText);
/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('dummy://foo', playerInterface);
const stream = manifest.variants[0].video;
await stream.createSegmentIndex();
goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');

const firstReference = stream.segmentIndex.get(0);
const firstPartialReference = firstReference.partialReferences[0];
expect(firstPartialReference.isIndependent()).toBeTruthy();
const secondPartialReference = firstReference.partialReferences[1];
expect(secondPartialReference.isIndependent()).toBeTruthy();
const thirdPartialReference = firstReference.partialReferences[2];
expect(thirdPartialReference.isIndependent()).toBeTruthy();
const fourthPartialReference = firstReference.partialReferences[3];
expect(fourthPartialReference.isIndependent()).toBeTruthy();
});
});

describe('supports ContentSteering', () => {
Expand Down
1 change: 1 addition & 0 deletions test/dash/dash_parser_segment_template_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -926,5 +926,6 @@ function makeTemplateInfo(timeline) {
'indexTemplate': null,
'mimeType': 'video/mp4',
'codecs': 'avc1.42E01E',
'numChunks': 0,
};
}

0 comments on commit 3cb40bf

Please sign in to comment.