Skip to content

Commit d73ab01

Browse files
committed
Implement DASH Annex I (URL parameters) for segment requests
1 parent 92aff8f commit d73ab01

36 files changed

Lines changed: 1271 additions & 10 deletions

File tree

src/core/fetchers/segment/segment_fetcher.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>({
9494
requestOptions.requestTimeout < 0 ? undefined : requestOptions.requestTimeout,
9595
connectionTimeout,
9696
cmcdPayload: undefined,
97+
requestData: undefined,
9798
};
9899

99100
/**
@@ -286,6 +287,7 @@ export default function createSegmentFetcher<TLoadedFormat, TSegmentDataType>({
286287
): ReturnType<ISegmentLoader<TLoadedFormat>> {
287288
pipelineRequestOptions.cmcdPayload =
288289
cmcdDataBuilder?.getCmcdDataForSegmentRequest(content);
290+
pipelineRequestOptions.requestData = content.representation.requestData;
289291
return loadSegment(
290292
cdnMetadata,
291293
context,

src/core/fetchers/thumbnails/thumbnail_fetcher.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export default function createThumbnailFetcher(
141141
requestOptions.requestTimeout < 0 ? undefined : requestOptions.requestTimeout,
142142
connectionTimeout,
143143
cmcdPayload: undefined,
144+
requestData: thumbnailTrack.requestData,
144145
};
145146

146147
/**

src/manifest/classes/period.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
IManifestStreamEvent,
2020
IParsedAdaptations,
2121
IParsedPeriod,
22+
IParsedThumbnailTrack,
2223
} from "../../parsers/manifest/index.ts";
2324
import type { ITrackType, IRepresentationFilter } from "../../public_types.ts";
2425
import arrayFind from "../../utils/array_find.ts";
@@ -97,6 +98,7 @@ export default class Period implements IPeriodMetadata {
9798
mimeType: thumbnailTrack.mimeType,
9899
index: thumbnailTrack.index,
99100
cdnMetadata: thumbnailTrack.cdnMetadata,
101+
requestData: thumbnailTrack.requestData,
100102
height: thumbnailTrack.height,
101103
width: thumbnailTrack.width,
102104
horizontalTiles: thumbnailTrack.horizontalTiles,
@@ -264,6 +266,8 @@ export interface IThumbnailTrack {
264266
mimeType: string;
265267
/** CDN(s) on which the thumbnails may be loaded. */
266268
cdnMetadata: ICdnMetadata[] | null;
269+
/** Transport-specific data used when requesting this track's resources. */
270+
requestData?: IParsedThumbnailTrack["requestData"];
267271
/**
268272
* A loaded thumbnail's height in pixels. Note that there can be multiple actual
269273
* thumbnails per loaded thumbnail resource (see `horizontalTiles` and

src/manifest/classes/representation.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ class Representation implements IRepresentationMetadata {
4646
* @see IRepresentationMetadata.bitrate
4747
*/
4848
public bitrate: number;
49+
/** Transport-specific data used when requesting this Representation's resources. */
50+
public requestData?: IParsedRepresentation["requestData"];
4951
/**
5052
* @see IRepresentationMetadata.frameRate
5153
*/
@@ -143,6 +145,7 @@ class Representation implements IRepresentationMetadata {
143145
this.uniqueId = generateRepresentationUniqueId();
144146
this.shouldBeAvoided = false;
145147
this.bitrate = args.bitrate;
148+
this.requestData = args.requestData;
146149
this.baseCodecs = [];
147150
this.trackType = trackType;
148151

src/manifest/classes/update_period_in_place.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default function updatePeriodInPlace(
8181
oldThumbnailTrack.end = newThumbnailTrack.end;
8282
oldThumbnailTrack.tileDuration = newThumbnailTrack.tileDuration;
8383
oldThumbnailTrack.cdnMetadata = newThumbnailTrack.cdnMetadata;
84+
oldThumbnailTrack.requestData = newThumbnailTrack.requestData;
8485
if (updateType === MANIFEST_UPDATE_TYPE.Full) {
8586
oldThumbnailTrack.index._replace(newThumbnailTrack.index);
8687
} else {
@@ -177,6 +178,7 @@ export default function updatePeriodInPlace(
177178
const [newRepresentation] = newRepresentations.splice(newRepresentationIdx, 1);
178179
updatedRepresentations.push(oldRepresentation.getMetadataSnapshot());
179180
oldRepresentation.cdnMetadata = newRepresentation.cdnMetadata;
181+
oldRepresentation.requestData = newRepresentation.requestData;
180182
if (updateType === MANIFEST_UPDATE_TYPE.Full) {
181183
oldRepresentation.index._replace(newRepresentation.index);
182184
} else {

src/parsers/manifest/dash/common/parse_adaptation_sets.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import inferAdaptationType, {
4141
} from "./infer_adaptation_type.ts";
4242
import type { IRepresentationContext } from "./parse_representations.ts";
4343
import parseRepresentations from "./parse_representations.ts";
44+
import { parseUrlQueryInfo } from "./parse_url_query_info.ts";
4445
import resolveBaseURLs from "./resolve_base_urls.ts";
4546

4647
/**
@@ -326,6 +327,11 @@ export default function parseAdaptationSets(
326327
);
327328
}
328329

330+
const adaptationUrlQueryInfo = parseUrlQueryInfo(
331+
adaptationChildren.EssentialProperty,
332+
adaptationChildren.SupplementalProperty,
333+
context.mpdUrl,
334+
);
329335
const reprCtxt: IRepresentationContext = {
330336
availabilityTimeComplete,
331337
availabilityTimeOffset,
@@ -336,10 +342,15 @@ export default function parseAdaptationSets(
336342
isDynamic: context.isDynamic,
337343
isLastPeriod: context.isLastPeriod,
338344
manifestProfiles: context.manifestProfiles,
345+
mpdUrl: context.mpdUrl,
339346
parentSegmentTemplates,
340347
receivedTime: context.receivedTime,
341348
start: context.start,
342349
unsafelyBaseOnPreviousAdaptation: null,
350+
urlQueryInfo:
351+
adaptationUrlQueryInfo === undefined
352+
? context.urlQueryInfo
353+
: context.urlQueryInfo.concat(adaptationUrlQueryInfo),
343354
};
344355

345356
const trickModeProperty = Array.isArray(essentialProperties)
@@ -595,6 +606,7 @@ function createThumbnailTracks(
595606
tracks.push({
596607
id: representation.id,
597608
cdnMetadata: representation.cdnMetadata,
609+
requestData: representation.requestData,
598610
index: representation.index,
599611
mimeType: representation.mimeType,
600612
height: representation.height,

src/parsers/manifest/dash/common/parse_mpd.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import ManifestBoundsCalculator from "./manifest_bounds_calculator.ts";
3939
import parseAvailabilityStartTime from "./parse_availability_start_time.ts";
4040
import type { IXLinkInfos } from "./parse_periods.ts";
4141
import parsePeriods from "./parse_periods.ts";
42+
import { parseUrlQueryInfo } from "./parse_url_query_info.ts";
4243
import type { IResolvedBaseUrl } from "./resolve_base_urls.ts";
4344
import resolveBaseURLs from "./resolve_base_urls.ts";
4445

@@ -277,6 +278,11 @@ function parseCompleteIntermediateRepresentation(
277278
});
278279
const contentProtectionParser = new ContentProtectionParser();
279280
contentProtectionParser.addReferences(rootChildren.ContentProtection);
281+
const mpdUrlQueryInfo = parseUrlQueryInfo(
282+
rootChildren.EssentialProperty,
283+
rootChildren.SupplementalProperty,
284+
args.url,
285+
);
280286
const manifestInfos = {
281287
availabilityStartTime,
282288
baseURLs: mpdBaseUrls,
@@ -286,7 +292,9 @@ function parseCompleteIntermediateRepresentation(
286292
isDynamic,
287293
manifestBoundsCalculator,
288294
manifestProfiles: mpdIR.attributes.profiles,
295+
mpdUrl: args.url,
289296
receivedTime: args.manifestReceivedTime,
297+
urlQueryInfo: mpdUrlQueryInfo === undefined ? [] : [mpdUrlQueryInfo],
290298
unsafelyBaseOnPreviousManifest,
291299
xlinkInfos,
292300
xmlNamespaces: mpdIR.attributes.namespaces,

src/parsers/manifest/dash/common/parse_periods.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import flattenOverlappingPeriods from "./flatten_overlapping_periods.ts";
3737
import getPeriodsTimeInformation from "./get_periods_time_infos.ts";
3838
import type { IAdaptationSetContext } from "./parse_adaptation_sets.ts";
3939
import parseAdaptationSets from "./parse_adaptation_sets.ts";
40+
import type { IDashUrlQueryInfo } from "./parse_url_query_info.ts";
41+
import { parseUrlQueryInfo } from "./parse_url_query_info.ts";
4042
import resolveBaseURLs from "./resolve_base_urls.ts";
4143

4244
const generatePeriodID = idGenerator();
@@ -113,6 +115,11 @@ export default function parsePeriods(
113115
const segmentTemplate =
114116
periodIR.children.SegmentTemplate[periodIR.children.SegmentTemplate.length - 1];
115117
contentProtectionParser.addReferences(periodIR.children.ContentProtection);
118+
const periodUrlQueryInfo = parseUrlQueryInfo(
119+
[],
120+
periodIR.children.SupplementalProperty,
121+
context.mpdUrl,
122+
);
116123
const adapCtxt: IAdaptationSetContext = {
117124
availabilityTimeComplete,
118125
availabilityTimeOffset,
@@ -123,10 +130,15 @@ export default function parsePeriods(
123130
isDynamic,
124131
isLastPeriod,
125132
manifestProfiles,
133+
mpdUrl: context.mpdUrl,
126134
receivedTime,
127135
segmentTemplate,
128136
start: periodStart,
129137
unsafelyBaseOnPreviousPeriod,
138+
urlQueryInfo:
139+
periodUrlQueryInfo === undefined
140+
? context.urlQueryInfo
141+
: context.urlQueryInfo.concat(periodUrlQueryInfo),
130142
};
131143
const { adaptations, thumbnailTracks } = parseAdaptationSets(
132144
periodIR.children.AdaptationSet,
@@ -359,6 +371,10 @@ export interface IPeriodContext extends IInheritedAdaptationContext {
359371
clockOffset?: number | undefined;
360372
/** Duration (mediaPresentationDuration) of the whole MPD, in seconds. */
361373
duration?: number | undefined;
374+
/** URL of the MPD from which Annex I parameters may be inherited. */
375+
mpdUrl?: string | undefined;
376+
/** Annex I URL query instructions inherited from the MPD level. */
377+
urlQueryInfo: IDashUrlQueryInfo[];
362378
/**
363379
* The parser should take this Manifest - which is a previously parsed
364380
* Manifest for the same dynamic content - as a base to speed-up the parsing

src/parsers/manifest/dash/common/parse_representations.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { convertSupplementalCodecsToRFC6381 } from "./convert_supplemental_codec
3030
import { getWEBMHDRInformation } from "./get_hdr_information.ts";
3131
import type { IRepresentationIndexContext } from "./parse_representation_index.ts";
3232
import parseRepresentationIndex from "./parse_representation_index.ts";
33+
import type { IDashUrlQueryInfo } from "./parse_url_query_info.ts";
34+
import { combineUrlQueryInfo, parseUrlQueryInfo } from "./parse_url_query_info.ts";
3335
import resolveBaseURLs from "./resolve_base_urls.ts";
3436

3537
/**
@@ -209,12 +211,48 @@ export default function parseRepresentations(
209211
}));
210212

211213
// Construct Representation Base
214+
const representationUrlQueryInfo = parseUrlQueryInfo(
215+
representation.children.EssentialProperty,
216+
representation.children.SupplementalProperty,
217+
context.mpdUrl,
218+
);
219+
const urlQueryInfo =
220+
representationUrlQueryInfo === undefined
221+
? context.urlQueryInfo
222+
: context.urlQueryInfo.concat(representationUrlQueryInfo);
223+
const segmentUrlQuery = combineUrlQueryInfo(
224+
urlQueryInfo.filter((info) => info.appliesTo.segment),
225+
);
226+
const initUrlQuery = combineUrlQueryInfo(
227+
urlQueryInfo.filter((info) => info.appliesTo.init),
228+
);
212229
const parsedRepresentation: IParsedRepresentation = {
213230
bitrate: representationBitrate,
214231
cdnMetadata,
215232
index: representationIndex,
216233
id: representationID,
217234
};
235+
if (segmentUrlQuery.length > 0 || initUrlQuery.length > 0) {
236+
parsedRepresentation.requestData = {};
237+
if (segmentUrlQuery.length > 0) {
238+
parsedRepresentation.requestData.segment = {
239+
urlQuery: segmentUrlQuery.map((info) => ({
240+
value: info.queryString,
241+
sameOriginOnly: info.sameOriginOnly,
242+
sourceUrl: info.sourceUrl,
243+
})),
244+
};
245+
}
246+
if (initUrlQuery.length > 0) {
247+
parsedRepresentation.requestData.init = {
248+
urlQuery: initUrlQuery.map((info) => ({
249+
value: info.queryString,
250+
sameOriginOnly: info.sameOriginOnly,
251+
sourceUrl: info.sourceUrl,
252+
})),
253+
};
254+
}
255+
}
218256

219257
if (
220258
representation.children.SupplementalProperty.length > 0 &&
@@ -300,6 +338,10 @@ export default function parseRepresentations(
300338
export interface IRepresentationContext extends IInheritedRepresentationIndexContext {
301339
/** Manifest DASH profiles used for signalling some features */
302340
manifestProfiles?: string | undefined;
341+
/** URL of the MPD from which Annex I parameters may be inherited. */
342+
mpdUrl?: string | undefined;
343+
/** Annex I URL query instructions inherited from upper MPD levels. */
344+
urlQueryInfo: IDashUrlQueryInfo[];
303345
/**
304346
* The parser should take this Adaptation - which is from a previously parsed
305347
* Manifest for the same dynamic content - as a base to speed-up the parsing

0 commit comments

Comments
 (0)