Skip to content

Commit

Permalink
fix: both and could be present, causing issues in proxy-manifest build
Browse files Browse the repository at this point in the history
  • Loading branch information
zapfire88 committed Feb 20, 2024
1 parent d894523 commit fc0fb87
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 69 deletions.
25 changes: 15 additions & 10 deletions src/manifests/handlers/dash/segment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,31 @@ export default async function dashSegmentHandler(
const urlSearchParams = new URLSearchParams(event.queryStringParameters);
const pathStem = path.basename(event.path).replace('.mp4', '');
// Get the number part after "segment_"
const [, reqSegmentIndexStr, representationIdStr, bitrateStr, timeStr] =
const [, reqSegmentIndexOrTimeStr, representationIdStr, bitrateStr] =
pathStem.split('_');
// Build correct Source Segment url
// segment templates may contain a width parameter "$Number%0[width]d$", and then we need to zero-pad them to that length
let segmentUrl = url
.replace(/\$Number%0(\d+)d\$/, (_, width) =>
reqSegmentIndexStr.padStart(Number(width), '0')
)
.replace('$Number$', reqSegmentIndexStr);
const reqSegmentIndexInt = parseInt(reqSegmentIndexStr);
let segmentUrl = url;

if (url.includes('$Time$')) {
segmentUrl = segmentUrl.replace('$Time$', reqSegmentIndexOrTimeStr);
} else {
segmentUrl = segmentUrl
.replace(/\$Number%0(\d+)d\$/, (_, width) =>
reqSegmentIndexOrTimeStr.padStart(Number(width), '0')
)
.replace('$Number$', reqSegmentIndexOrTimeStr);
}
const reqSegmentIndexInt = parseInt(reqSegmentIndexOrTimeStr);

// Replace RepresentationID in url if present
if (representationIdStr) {
segmentUrl = segmentUrl.replace(
'$RepresentationID$',
representationIdStr
);
}
if (timeStr) {
segmentUrl = segmentUrl.replace('$Time$', timeStr);
}

if (bitrateStr) {
urlSearchParams.set('bitrate', bitrateStr);
}
Expand Down
41 changes: 34 additions & 7 deletions src/manifests/utils/dashManifestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default function (): DASHManifestTools {

// Media attr
const mediaUrl = segmentTemplate.$.media;

const hasTime = mediaUrl.toString().includes('$Time$');
// Convert relative segment offsets to absolute ones
// Also clones params to avoid mutating input argument
const [urlQuery, changed] = convertRelativeToAbsoluteSegmentOffsets(
Expand All @@ -99,12 +99,27 @@ export default function (): DASHManifestTools {
);

if (changed) staticQueryUrl = new URLSearchParams(urlQuery);

segmentTemplate.$.media = proxyPathBuilder(
const proxy = proxyPathBuilder(
mediaUrl.match(/^http/) ? mediaUrl : baseUrl + mediaUrl,
urlQuery,
'proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$'
// 'proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$'
hasTime
? {
base: 'proxy-segment/segment_$Time$_$RepresentationID$_$Bandwidth$',
time: true,
representationId: true,
bandwidth: true
}
: {
base: 'proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$',
number: true,
representationId: true,
bandwidth: true
}
// ? 'proxy-segment/segment_$Time$_$RepresentationID$_$Bandwidth$'
// : `proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$`
);
segmentTemplate.$.media = proxy.url;
// Initialization attr.
const initUrl = segmentTemplate.$.initialization;
if (!initUrl.match(/^http/)) {
Expand All @@ -128,7 +143,7 @@ export default function (): DASHManifestTools {
representation.SegmentTemplate.map((segmentTemplate) => {
// Media attr.
const mediaUrl = segmentTemplate.$.media;

const hasTime = mediaUrl.toString().includes('$Time$');
// Convert relative segment offsets to absolute ones
// Also clones params to avoid mutating input argument
const [urlQuery, changed] =
Expand All @@ -145,11 +160,23 @@ export default function (): DASHManifestTools {
urlQuery.set('bitrate', representation.$.bandwidth);
}

segmentTemplate.$.media = proxyPathBuilder(
const proxy = proxyPathBuilder(
mediaUrl,
urlQuery,
'proxy-segment/segment_$Number$.mp4'
hasTime
? {
base: 'proxy-segment/segment_$Time$.mp4',
time: true
}
: {
base: 'proxy-segment/segment_$Number$.mp4',
number: true
}
// ? 'proxy-segment/segment_$Time$_$RepresentationID$_$Bandwidth$'
// : `proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$`
// 'proxy-segment/segment_$Number$.mp4'
);
segmentTemplate.$.media = proxy.url;
// Initialization attr.
const masterDashUrl = originalUrlQuery.get('url');
const initUrl = segmentTemplate.$.initialization;
Expand Down
30 changes: 15 additions & 15 deletions src/manifests/utils/hlsManifestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ export default function (): HLSManifestTools {
if (stateKey) {
urlQuery.set('state', stateKey);
}
streamItem.set(
'uri',
proxyPathBuilder(currentUri, urlQuery, 'proxy-media.m3u8')
);
const proxy = proxyPathBuilder(currentUri, urlQuery, {
base: 'proxy-media.m3u8'
});
streamItem.set('uri', proxy.url);
return streamItem;
});

Expand All @@ -119,10 +119,10 @@ export default function (): HLSManifestTools {
if (stateKey) {
urlQuery.set('state', stateKey);
}
mediaItem.set(
'uri',
proxyPathBuilder(currentUri, originalUrlQuery, 'proxy-media.m3u8')
);
const proxy = proxyPathBuilder(currentUri, urlQuery, {
base: 'proxy-media.m3u8'
});
mediaItem.set('uri', proxy.url);
return mediaItem;
});

Expand Down Expand Up @@ -159,14 +159,14 @@ export default function (): HLSManifestTools {
}

const params = segmentUrlParamString(sourceSegURL, corruption);
item.set(
'uri',
proxyPathBuilder(
item.get('uri'),
new URLSearchParams(params),
'../../segments/proxy-segment'
)
const proxy = proxyPathBuilder(
item.get('uri'),
new URLSearchParams(params),
{
base: '../../segments/proxy-segment'
}
);
item.set('uri', proxy.url);
}
return m3u.toString();
}
Expand Down
40 changes: 16 additions & 24 deletions src/shared/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@ describe('shared.utils', () => {
);

// Act
const actual = proxyPathBuilder(
itemUri,
urlSearchParams,
'proxy-media.m3u8'
);
const actual = proxyPathBuilder(itemUri, urlSearchParams, {
base: 'proxy-media.m3u8'
});
const expected = `proxy-media.m3u8?url=${encodeURIComponent(
'https://mock.stream.origin.se/hls/vods/asset41/video-variants/variant_3.m3u8'
)}&delay=${encodeURIComponent('[{i:3,ms:200}]')}`;

// Assert
expect(actual).toEqual(expected);
expect(actual.url).toEqual(expected);
});

it('should return correct format with value in all parameters, when source url is already an absolut url', () => {
Expand All @@ -32,17 +30,15 @@ describe('shared.utils', () => {
);

// Act
const actual = proxyPathBuilder(
itemUri,
urlSearchParams,
'proxy-media.m3u8'
);
const actual = proxyPathBuilder(itemUri, urlSearchParams, {
base: 'proxy-media.m3u8'
});
const expected = `proxy-media.m3u8?url=${encodeURIComponent(
'https://different.origin.se/hls/variant_3.m3u8'
)}&delay=${encodeURIComponent('[{i:3,ms:200}]')}`;

// Assert
expect(actual).toEqual(expected);
expect(actual.url).toEqual(expected);
});

it("should return correct format with value in all parameters, when source url string has '../'", () => {
Expand All @@ -53,17 +49,15 @@ describe('shared.utils', () => {
);

// Act
const actual = proxyPathBuilder(
itemUri,
urlSearchParams,
'proxy-media.m3u8'
);
const actual = proxyPathBuilder(itemUri, urlSearchParams, {
base: 'proxy-media.m3u8'
});
const expected = `proxy-media.m3u8?url=${encodeURIComponent(
'https://mock.stream.origin.se/hls/pathB/path3/variant_3.m3u8'
)}&delay=${encodeURIComponent('[{i:3,ms:200}]')}`;

// Assert
expect(actual).toEqual(expected);
expect(actual.url).toEqual(expected);
});

it('should handle empty parameters', () => {
Expand All @@ -72,15 +66,13 @@ describe('shared.utils', () => {
const urlSearchParams = null;

// Act
const actual = proxyPathBuilder(
itemUri,
urlSearchParams,
'proxy-media.m3u8'
);
const actual = proxyPathBuilder(itemUri, urlSearchParams, {
base: 'proxy-media.m3u8'
});
const expected = '';

// Assert
expect(actual).toEqual(expected);
expect(actual.url).toEqual(expected);
});
});
});
22 changes: 13 additions & 9 deletions src/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,15 @@ export function refineALBEventQuery(
return queryStringParameters;
}

type ProxyBasenames =
| 'proxy-media.m3u8'
| '../../segments/proxy-segment'
| 'proxy-segment/segment_$Number$.mp4'
| 'proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$'
| 'proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$';
type ProxyBasenames = {
base: string;
url?: string;
number?: boolean;
numberWidth?: boolean;
time?: boolean;
representationId?: boolean;
bandwidth?: boolean;
};

/**
* Adjust paths based on directory navigation
Expand Down Expand Up @@ -220,9 +223,9 @@ export function proxyPathBuilder(
itemUri: string,
urlSearchParams: URLSearchParams,
proxy: ProxyBasenames
): string {
): ProxyBasenames {
if (!urlSearchParams) {
return '';
return { base: '', url: '' };
}
const allQueries = new URLSearchParams(urlSearchParams);
let sourceItemURL = '';
Expand All @@ -239,7 +242,8 @@ export function proxyPathBuilder(
allQueries.set('url', sourceItemURL);
}
const allQueriesString = allQueries.toString();
return `${proxy}${allQueriesString ? `?${allQueriesString}` : ''}`;
proxy.url = `${proxy.base}${allQueriesString ? `?${allQueriesString}` : ''}`;
return proxy;
}

export function segmentUrlParamString(
Expand Down
4 changes: 2 additions & 2 deletions src/testvectors/dash/dash1_compressed/proxy-manifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<SegmentTemplate
timescale="48000"
initialization="https://mock.mock.com/stream/relative_base/audiotrack/init/$RepresentationID$.m4s"
media="proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$?url=https%3A%2F%2Fmock.mock.com%2Fstream%2Frelative_base%2Faudiotrack%2F%24RepresentationID%24%2F%24Time%24.m4s&amp;statusCode=%5B%7Bi%3A0%2Ccode%3A404%7D%2C%7Bi%3A2%2Ccode%3A401%7D%5D&amp;timeout=%5B%7Bi%3A3%7D%5D&amp;delay=%5B%7Bi%3A2%2Cms%3A2000%7D%5D">
media="proxy-segment/segment_$Time$_$RepresentationID$_$Bandwidth$?url=https%3A%2F%2Fmock.mock.com%2Fstream%2Frelative_base%2Faudiotrack%2F%24RepresentationID%24%2F%24Time%24.m4s&amp;statusCode=%5B%7Bi%3A0%2Ccode%3A404%7D%2C%7Bi%3A2%2Ccode%3A401%7D%5D&amp;timeout=%5B%7Bi%3A3%7D%5D&amp;delay=%5B%7Bi%3A2%2Cms%3A2000%7D%5D">
<SegmentTimeline>
<S t="80746389121167" d="184320" r="78" />
</SegmentTimeline>
Expand Down Expand Up @@ -62,7 +62,7 @@
<SegmentTemplate
timescale="600"
initialization="https://mock.mock.com/stream/relative_base/videotrack/init/$RepresentationID$.m4s"
media="proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$?url=https%3A%2F%2Fmock.mock.com%2Fstream%2Frelative_base%2Fvideotrack%2F%24RepresentationID%24%2F%24Time%24.m4s&amp;statusCode=%5B%7Bi%3A0%2Ccode%3A404%7D%2C%7Bi%3A2%2Ccode%3A401%7D%5D&amp;timeout=%5B%7Bi%3A3%7D%5D&amp;delay=%5B%7Bi%3A2%2Cms%3A2000%7D%5D">
media="proxy-segment/segment_$Time$_$RepresentationID$_$Bandwidth$?url=https%3A%2F%2Fmock.mock.com%2Fstream%2Frelative_base%2Fvideotrack%2F%24RepresentationID%24%2F%24Time%24.m4s&amp;statusCode=%5B%7Bi%3A0%2Ccode%3A404%7D%2C%7Bi%3A2%2Ccode%3A401%7D%5D&amp;timeout=%5B%7Bi%3A3%7D%5D&amp;delay=%5B%7Bi%3A2%2Cms%3A2000%7D%5D">
<SegmentTimeline>
<S t="1009329864060" d="2304" r="78" />
</SegmentTimeline>
Expand Down
4 changes: 2 additions & 2 deletions src/testvectors/dash/dash_period_baseurl/proxy-manifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" minBufferTime="PT1.500S" type="static" mediaPresentationDuration="PT0H0M10.000S" maxSegmentDuration="PT0H0M1.000S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd">
<Period id="0" start="PT0H0M0.000S">
<AdaptationSet mimeType="video/mp4" codecs="avc1.4D401E" frameRate="30000/1001" lang="und">
<SegmentTemplate timescale="1000" media="proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$?url=http%3A%2F%2Fvm2.dashif.org%2Flivesim-dev%2Fperiods_60%2Fvideo_%24Number%24.mp4" initialization="http://vm2.dashif.org/livesim-dev/periods_60/video_init.mp4" startNumber="1" presentationTimeOffset="0">
<SegmentTemplate timescale="1000" media="proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$?url=http%3A%2F%2Fvm2.dashif.org%2Flivesim-dev%2Fperiods_60%2Fvideo_%24Number%24.mp4" initialization="http://vm2.dashif.org/livesim-dev/periods_60/video_init.mp4" startNumber="1" presentationTimeOffset="0">
<SegmentTimeline>
<S t="0" d="10000"/>
<S t="10000" d="10000"/>
Expand All @@ -17,7 +17,7 @@
</SegmentTemplate>
</AdaptationSet>
<AdaptationSet mimeType="audio/mp4" lang="und">
<SegmentTemplate timescale="1000" media="proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$_$Time$?url=http%3A%2F%2Fvm2.dashif.org%2Flivesim-dev%2Fperiods_60%2Faudio_%24Number%24.mp4" initialization="http://vm2.dashif.org/livesim-dev/periods_60/audio_init.mp4" startNumber="1" presentationTimeOffset="0">
<SegmentTemplate timescale="1000" media="proxy-segment/segment_$Number$_$RepresentationID$_$Bandwidth$?url=http%3A%2F%2Fvm2.dashif.org%2Flivesim-dev%2Fperiods_60%2Faudio_%24Number%24.mp4" initialization="http://vm2.dashif.org/livesim-dev/periods_60/audio_init.mp4" startNumber="1" presentationTimeOffset="0">
<SegmentTimeline>
<S t="0" d="10000"/>
<S t="10000" d="10000"/>
Expand Down

0 comments on commit fc0fb87

Please sign in to comment.