Skip to content

Commit 6957423

Browse files
authored
Don't fetch segment if endNumber is reached (Dash-Industry-Forum#4745)
* Don't fetch segment if endNumber is reached Closing Dash-Industry-Forum#4710 * Improved handling of startNumber * Moved seg check to if * Improved tests for DashHandler.js
1 parent fc13a55 commit 6957423

File tree

8 files changed

+143
-35
lines changed

8 files changed

+143
-35
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,7 @@ declare namespace dashjs {
989989
startNumber: number;
990990
timescale: number;
991991
width: number;
992+
endNumber: number | null;
992993
}
993994

994995
export interface Segment {

src/dash/DashHandler.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ function DashHandler(config) {
282282
}
283283

284284
let indexToRequest = lastSegment ? lastSegment.index + 1 : 0;
285+
if (representation && lastSegment && representation.endNumber && lastSegment.replacementNumber && lastSegment.replacementNumber > representation.endNumber) {
286+
return null;
287+
}
285288

286289
return _getRequest(mediaInfo, representation, indexToRequest);
287290
}

src/dash/constants/DashConstants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export default {
8484
DVB_MIMETYPE : 'dvb:mimeType',
8585
DVB_FONTFAMILY : 'dvb:fontFamily',
8686
DYNAMIC: 'dynamic',
87+
END_NUMBER: 'endNumber',
8788
ESSENTIAL_PROPERTY: 'EssentialProperty',
8889
EVENT: 'Event',
8990
EVENT_STREAM: 'EventStream',

src/dash/models/DashManifestModel.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,9 @@ function DashManifestModel() {
842842
} else if (baseUrl && baseUrl.availabilityTimeComplete !== undefined) {
843843
voRepresentation.availabilityTimeComplete = baseUrl.availabilityTimeComplete;
844844
}
845+
if (segmentInfo.hasOwnProperty(DashConstants.END_NUMBER)) {
846+
voRepresentation.endNumber = segmentInfo[DashConstants.END_NUMBER];
847+
}
845848
}
846849

847850
voRepresentation.mseTimeOffset = calcMseTimeOffset(voRepresentation);

src/dash/utils/TemplateSegmentsGetter.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ function TemplateSegmentsGetter(config, isDynamic) {
7575
index = Math.max(index, 0);
7676

7777
const seg = getIndexBasedSegment(timelineConverter, isDynamic, representation, index);
78+
7879
if (seg) {
80+
if (representation.endNumber && seg.replacementNumber > representation.endNumber) {
81+
return null;
82+
}
83+
7984
seg.replacementTime = Math.round(index * representation.segmentDuration * representation.timescale, 10);
8085

8186
let url = template.media;

src/dash/vo/Representation.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Representation {
7272
this.startNumber = 1;
7373
this.timescale = 1;
7474
this.width = NaN;
75+
this.endNumber = null;
7576
}
7677

7778
hasInitialization() {

test/unit/test/dash/dash.DashHandler.js

Lines changed: 85 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ describe('DashHandler', function () {
3434
const segmentsController = objectsHelper.getDummySegmentsController();
3535
const dashMetrics = new DashMetricsMock();
3636

37+
let dummyRepresentation;
38+
let dummyMediaInfo;
3739

3840
const config = {
3941
eventBus,
@@ -51,6 +53,41 @@ describe('DashHandler', function () {
5153
const dashHandler = DashHandler(context).create(config);
5254
dashHandler.initialize(streamProcessor);
5355

56+
beforeEach(() => {
57+
dummyRepresentation = {
58+
index: 0,
59+
adaptation: {
60+
index: 0,
61+
period: {
62+
mpd: {
63+
manifest: {
64+
Period: [
65+
{
66+
AdaptationSet: [
67+
{
68+
Representation: [
69+
{
70+
bandwidth: 3000
71+
}
72+
]
73+
}
74+
]
75+
}
76+
]
77+
}
78+
},
79+
start: 0,
80+
duration: 30,
81+
index: 0
82+
}
83+
},
84+
segmentInfoType: 'SegmentTimeline',
85+
timescale: 1,
86+
segmentDuration: 2
87+
};
88+
dummyMediaInfo = {};
89+
})
90+
5491
it('should generate an init segment for a representation', () => {
5592
const representation = voHelper.getDummyRepresentation(testType);
5693

@@ -93,9 +130,55 @@ describe('DashHandler', function () {
93130
expect(mediaSegment).to.be.null; // jshint ignore:line
94131
});
95132

133+
describe('getNextSegmentRequest', () => {
134+
let segRequestStub;
135+
136+
beforeEach(() => {
137+
segRequestStub = sinon.stub(segmentsController, 'getSegmentByIndex').callsFake((representation, index) => {
138+
return {
139+
replacementNumber: index,
140+
index,
141+
duration: representation.segmentDuration,
142+
representation,
143+
media: 'http://someurl',
144+
endNumber: 2
145+
}
146+
});
147+
})
148+
149+
afterEach(() => {
150+
segRequestStub.restore();
151+
});
152+
153+
it('it returns a segment request', () => {
154+
const mediaSegment = dashHandler.getNextSegmentRequest({}, {segmentInfoType: DashConstants.SEGMENT_TEMPLATE, adaptation: {index: 1} });
155+
expect(mediaSegment).not.to.be.null; // jshint ignore:line
156+
})
157+
158+
it('returns null if the next segment is after @endNumber', () => {
159+
const dashHandler = DashHandler(context).create(config);
160+
const representation = {segmentInfoType: DashConstants.SEGMENT_TEMPLATE, adaptation: {index: 1}, endNumber: 2 };
161+
dashHandler.initialize(streamProcessor);
162+
dashHandler.getNextSegmentRequest({}, representation);
163+
dashHandler.getNextSegmentRequest({}, representation);
164+
dashHandler.getNextSegmentRequest({}, representation);
165+
dashHandler.getNextSegmentRequest({}, representation);
166+
const mediaSegment = dashHandler.getNextSegmentRequest({}, representation);
167+
expect(mediaSegment).to.be.null; // jshint ignore:line
168+
})
169+
170+
it('returns null if representation is null', () => {
171+
const mediaSegment = dashHandler.getNextSegmentRequest({}, null);
172+
expect(mediaSegment).to.be.null; // jshint ignore:line
173+
})
174+
175+
it('returns null if representation.segmentInfoType is null', () => {
176+
const mediaSegment = dashHandler.getNextSegmentRequest({}, {segmentInfoType: null});
177+
expect(mediaSegment).to.be.null; // jshint ignore:line
178+
})
179+
})
180+
96181
describe('getValidTimeAheadOfTargetTime()', () => {
97-
let dummyRepresentation;
98-
let dummyMediaInfo;
99182
let segRequestStub;
100183

101184
beforeEach(() => {
@@ -111,39 +194,6 @@ describe('DashHandler', function () {
111194
media: 'http://someurl'
112195
}
113196
});
114-
115-
dummyRepresentation = {
116-
index: 0,
117-
adaptation: {
118-
index: 0,
119-
period: {
120-
mpd: {
121-
manifest: {
122-
Period: [
123-
{
124-
AdaptationSet: [
125-
{
126-
Representation: [
127-
{
128-
bandwidth: 3000
129-
}
130-
]
131-
}
132-
]
133-
}
134-
]
135-
}
136-
},
137-
start: 0,
138-
duration: 30,
139-
index: 0
140-
}
141-
},
142-
segmentInfoType: 'SegmentTimeline',
143-
timescale: 1,
144-
segmentDuration: 2
145-
};
146-
dummyMediaInfo = {};
147197
})
148198

149199
afterEach(() => {

test/unit/test/dash/dash.utils.TemplateSegmentsGetter.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,50 @@ describe('TemplateSegmentsGetter', () => {
9595
let seg = templateSegmentsGetter.getSegmentByIndex(representation, 1 + 100 / 5);
9696
expect(seg).to.be.null; // jshint ignore:line
9797
});
98+
99+
it('should not return null if segment is equal to endNumber', () => {
100+
const representation = voHelper.getDummyRepresentation(Constants.VIDEO);
101+
representation.segmentAvailabilityWindow = {start: 0, end: 100};
102+
representation.segmentDuration = 1;
103+
representation.startNumber = 0;
104+
representation.endNumber = 3;
105+
106+
let seg = templateSegmentsGetter.getSegmentByIndex(representation, 3);
107+
expect(seg.index).to.equal(3);
108+
})
109+
110+
it('should not return null if segment is equal to endNumber and startNumber is 2', () => {
111+
const representation = voHelper.getDummyRepresentation(Constants.VIDEO);
112+
representation.segmentAvailabilityWindow = {start: 0, end: 100};
113+
representation.segmentDuration = 1;
114+
representation.startNumber = 2;
115+
representation.endNumber = 5;
116+
117+
let seg = templateSegmentsGetter.getSegmentByIndex(representation, 3);
118+
expect(seg.index).to.equal(3);
119+
})
120+
121+
it('should return null if segment is after endNumber', () => {
122+
const representation = voHelper.getDummyRepresentation(Constants.VIDEO);
123+
representation.segmentAvailabilityWindow = {start: 0, end: 100};
124+
representation.segmentDuration = 1;
125+
representation.startNumber = 0;
126+
representation.endNumber = 2;
127+
128+
let seg = templateSegmentsGetter.getSegmentByIndex(representation, 3);
129+
expect(seg).to.be.null; // jshint ignore:line
130+
})
131+
132+
it('should return null if segment is after endNumber and startNumber is 2', () => {
133+
const representation = voHelper.getDummyRepresentation(Constants.VIDEO);
134+
representation.segmentAvailabilityWindow = {start: 0, end: 100};
135+
representation.segmentDuration = 1;
136+
representation.startNumber = 2;
137+
representation.endNumber = 5;
138+
139+
let seg = templateSegmentsGetter.getSegmentByIndex(representation, 4);
140+
expect(seg).to.be.null; // jshint ignore:line
141+
})
98142
});
99143

100144
describe('getSegmentByTime', () => {

0 commit comments

Comments
 (0)