Skip to content

Commit 3fab47c

Browse files
authored
feat(Ads): Update DASH overlay implementation (#8503)
This matches with the latest draft of SCTE 214-1
1 parent 94bdb7c commit 3fab47c

File tree

2 files changed

+189
-66
lines changed

2 files changed

+189
-66
lines changed

lib/ads/interstitial_ad_manager.js

Lines changed: 88 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -523,95 +523,119 @@ shaka.ads.InterstitialAdManager = class {
523523
const uri = overlayEvent.attributes['uri'];
524524
const mimeType = overlayEvent.attributes['mimeType'];
525525
const loop = overlayEvent.attributes['loop'] == 'true';
526+
const background = overlayEvent.attributes['background'] || null;
526527
const z = TXml.parseAttr(overlayEvent, 'z', TXml.parseInt);
527528
if (!uri || z == 0) {
528529
shaka.log.warning('Unsupported OverlayEvent', region);
529530
return;
530531
}
531532

533+
const viewport = {
534+
x: 1920,
535+
y: 1080,
536+
};
537+
538+
const viewportElement = TXml.findChild(overlayEvent, 'Viewport');
539+
if (viewportElement) {
540+
const viewportX = TXml.parseAttr(viewportElement, 'x', TXml.parseInt);
541+
if (viewportX == null) {
542+
shaka.log.warning('Unsupported OverlayEvent', region);
543+
return;
544+
}
545+
const viewportY = TXml.parseAttr(viewportElement, 'y', TXml.parseInt);
546+
if (viewportY == null) {
547+
shaka.log.warning('Unsupported OverlayEvent', region);
548+
return;
549+
}
550+
viewport.x = viewportX;
551+
viewport.y = viewportY;
552+
}
553+
532554
/** @type {!shaka.extern.AdPositionInfo} */
533-
let overlay = {
555+
const overlay = {
534556
viewport: {
535-
x: 1920,
536-
y: 1080,
557+
x: viewport.x,
558+
y: viewport.y,
537559
},
538560
topLeft: {
539561
x: 0,
540562
y: 0,
541563
},
542564
size: {
543-
x: 1920,
544-
y: 1080,
565+
x: viewport.x,
566+
y: viewport.y,
545567
},
546568
};
547569

548-
const viewport = TXml.findChild(overlayEvent, 'Viewport');
549-
const topLeft = TXml.findChild(overlayEvent, 'TopLeft');
550-
const size = TXml.findChild(overlayEvent, 'Size');
551-
if (viewport && topLeft && size) {
552-
const viewportX = TXml.parseAttr(viewport, 'x', TXml.parseInt);
553-
if (viewportX == null) {
554-
shaka.log.warning('Unsupported OverlayEvent', region);
555-
return;
556-
}
557-
const viewportY = TXml.parseAttr(viewport, 'y', TXml.parseInt);
558-
if (viewportY == null) {
559-
shaka.log.warning('Unsupported OverlayEvent', region);
560-
return;
561-
}
562-
const topLeftX = TXml.parseAttr(topLeft, 'x', TXml.parseInt);
563-
if (topLeftX == null) {
564-
shaka.log.warning('Unsupported OverlayEvent', region);
565-
return;
566-
}
567-
const topLeftY = TXml.parseAttr(topLeft, 'y', TXml.parseInt);
568-
if (topLeftY == null) {
569-
shaka.log.warning('Unsupported OverlayEvent', region);
570-
return;
571-
}
572-
const sizeX = TXml.parseAttr(size, 'x', TXml.parseInt);
573-
if (sizeX == null) {
574-
shaka.log.warning('Unsupported OverlayEvent', region);
575-
return;
576-
}
577-
const sizeY = TXml.parseAttr(size, 'y', TXml.parseInt);
578-
if (sizeY == null) {
579-
shaka.log.warning('Unsupported OverlayEvent', region);
580-
return;
570+
const overlayElement = TXml.findChild(overlayEvent, 'Overlay');
571+
if (viewportElement && overlayElement) {
572+
const topLeft = TXml.findChild(overlayElement, 'TopLeft');
573+
const size = TXml.findChild(overlayElement, 'Size');
574+
if (topLeft && size) {
575+
const topLeftX = TXml.parseAttr(topLeft, 'x', TXml.parseInt);
576+
if (topLeftX == null) {
577+
shaka.log.warning('Unsupported OverlayEvent', region);
578+
return;
579+
}
580+
const topLeftY = TXml.parseAttr(topLeft, 'y', TXml.parseInt);
581+
if (topLeftY == null) {
582+
shaka.log.warning('Unsupported OverlayEvent', region);
583+
return;
584+
}
585+
const sizeX = TXml.parseAttr(size, 'x', TXml.parseInt);
586+
if (sizeX == null) {
587+
shaka.log.warning('Unsupported OverlayEvent', region);
588+
return;
589+
}
590+
const sizeY = TXml.parseAttr(size, 'y', TXml.parseInt);
591+
if (sizeY == null) {
592+
shaka.log.warning('Unsupported OverlayEvent', region);
593+
return;
594+
}
595+
overlay.topLeft.x = topLeftX;
596+
overlay.topLeft.y = topLeftY;
597+
overlay.size.x = sizeX;
598+
overlay.size.y = sizeY;
581599
}
582-
overlay = {
583-
viewport: {
584-
x: viewportX,
585-
y: viewportY,
586-
},
587-
topLeft: {
588-
x: topLeftX,
589-
y: topLeftY,
590-
},
591-
size: {
592-
x: sizeX,
593-
y: sizeY,
594-
},
595-
};
596600
}
597-
const squeezeCurrent = TXml.findChild(overlayEvent, 'SqueezeCurrent');
598601
let currentVideo = null;
599-
if (squeezeCurrent) {
600-
const percentage =
601-
TXml.parseAttr(squeezeCurrent, 'percentage', TXml.parseFloat);
602-
if (percentage) {
602+
const squeezeElement = TXml.findChild(overlayEvent, 'Squeeze');
603+
if (viewportElement && squeezeElement) {
604+
const topLeft = TXml.findChild(squeezeElement, 'TopLeft');
605+
const size = TXml.findChild(squeezeElement, 'Size');
606+
if (topLeft && size) {
607+
const topLeftX = TXml.parseAttr(topLeft, 'x', TXml.parseInt);
608+
if (topLeftX == null) {
609+
shaka.log.warning('Unsupported OverlayEvent', region);
610+
return;
611+
}
612+
const topLeftY = TXml.parseAttr(topLeft, 'y', TXml.parseInt);
613+
if (topLeftY == null) {
614+
shaka.log.warning('Unsupported OverlayEvent', region);
615+
return;
616+
}
617+
const sizeX = TXml.parseAttr(size, 'x', TXml.parseInt);
618+
if (sizeX == null) {
619+
shaka.log.warning('Unsupported OverlayEvent', region);
620+
return;
621+
}
622+
const sizeY = TXml.parseAttr(size, 'y', TXml.parseInt);
623+
if (sizeY == null) {
624+
shaka.log.warning('Unsupported OverlayEvent', region);
625+
return;
626+
}
603627
currentVideo = {
604628
viewport: {
605-
x: 1920,
606-
y: 1080,
629+
x: viewport.x,
630+
y: viewport.y,
607631
},
608632
topLeft: {
609-
x: 0,
610-
y: 0,
633+
x: topLeftX,
634+
y: topLeftY,
611635
},
612636
size: {
613-
x: 1920 * percentage,
614-
y: 1080 * percentage,
637+
x: sizeX,
638+
y: sizeY,
615639
},
616640
};
617641
}
@@ -639,7 +663,7 @@ shaka.ads.InterstitialAdManager = class {
639663
overlay,
640664
displayOnBackground: z == -1,
641665
currentVideo,
642-
background: null,
666+
background,
643667
};
644668
this.addInterstitials([interstitial]);
645669
}

test/ads/interstitial_ad_manager_unit.js

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,10 @@ describe('Interstitial Ad manager', () => {
875875
'<Event duration="1" id="OVERLAY" presentationTime="0">',
876876
'<OverlayEvent mimeType="application/dash+xml" uri="test.mpd">',
877877
'<Viewport x="1920" y="1080"/>',
878+
'<Overlay>',
878879
'<TopLeft x="0" y="720"/>',
879880
'<Size x="480" y="360"/>',
881+
'</Overlay>',
880882
'</OverlayEvent>',
881883
'</Event>',
882884
].join('');
@@ -943,7 +945,11 @@ describe('Interstitial Ad manager', () => {
943945
const eventString = [
944946
'<Event duration="1" id="OVERLAY" presentationTime="0">',
945947
'<OverlayEvent mimeType="application/dash+xml" uri="test.mpd" z="0">',
946-
'<SqueezeCurrent percentage="0.7"/>',
948+
'<Viewport x="1920" y="1080"/>',
949+
'<Squeeze>',
950+
'<TopLeft x="0" y="720"/>',
951+
'<Size x="480" y="360"/>',
952+
'</Squeeze>',
947953
'</OverlayEvent>',
948954
'</Event>',
949955
].join('');
@@ -969,7 +975,11 @@ describe('Interstitial Ad manager', () => {
969975
const eventString = [
970976
'<Event duration="1" id="OVERLAY" presentationTime="0">',
971977
'<OverlayEvent mimeType="application/dash+xml" uri="test.mpd" z="-1">',
972-
'<SqueezeCurrent percentage="0.5"/>',
978+
'<Viewport x="1920" y="1080"/>',
979+
'<Squeeze>',
980+
'<TopLeft x="0" y="0"/>',
981+
'<Size x="960" y="540"/>',
982+
'</Squeeze>',
973983
'</OverlayEvent>',
974984
'</Event>',
975985
].join('');
@@ -1044,6 +1054,95 @@ describe('Interstitial Ad manager', () => {
10441054
};
10451055
expect(interstitials[0]).toEqual(expectedInterstitial);
10461056
});
1057+
1058+
it('supports overlay events with double box format', async () => {
1059+
const eventString = [
1060+
'<Event duration="1" id="OVERLAY" presentationTime="0">',
1061+
'<OverlayEvent mimeType="application/dash+xml" uri="test.mpd" z="-1" ',
1062+
'background="red">',
1063+
'<Viewport x="1920" y="1080"/>',
1064+
'<Overlay>',
1065+
'<TopLeft x="0" y="720"/>',
1066+
'<Size x="480" y="360"/>',
1067+
'</Overlay>',
1068+
'<Squeeze>',
1069+
'<TopLeft x="0" y="0"/>',
1070+
'<Size x="960" y="540"/>',
1071+
'</Squeeze>',
1072+
'</OverlayEvent>',
1073+
'</Event>',
1074+
].join('');
1075+
const eventNode = TXml.parseXmlString(eventString);
1076+
goog.asserts.assert(eventNode, 'Should have a event node!');
1077+
/** @type {shaka.extern.TimelineRegionInfo} */
1078+
const region = {
1079+
startTime: 0,
1080+
endTime: 1,
1081+
id: 'OVERLAY',
1082+
schemeIdUri: 'urn:scte:dash:scte214-events',
1083+
eventNode,
1084+
eventElement: TXml.txmlNodeToDomElement(eventNode),
1085+
value: '',
1086+
timescale: 1,
1087+
};
1088+
await interstitialAdManager.addOverlayRegion(region);
1089+
1090+
expect(onEventSpy).not.toHaveBeenCalled();
1091+
1092+
const interstitials = interstitialAdManager.getInterstitials();
1093+
expect(interstitials.length).toBe(1);
1094+
/** @type {!shaka.extern.AdInterstitial} */
1095+
const expectedInterstitial = {
1096+
id: 'OVERLAY',
1097+
groupId: null,
1098+
startTime: 0,
1099+
endTime: 1,
1100+
uri: 'test.mpd',
1101+
mimeType: 'application/dash+xml',
1102+
isSkippable: false,
1103+
skipOffset: null,
1104+
skipFor: null,
1105+
canJump: true,
1106+
resumeOffset: null,
1107+
playoutLimit: null,
1108+
once: false,
1109+
pre: false,
1110+
post: false,
1111+
timelineRange: true,
1112+
loop: false,
1113+
overlay: {
1114+
viewport: {
1115+
x: 1920,
1116+
y: 1080,
1117+
},
1118+
topLeft: {
1119+
x: 0,
1120+
y: 720,
1121+
},
1122+
size: {
1123+
x: 480,
1124+
y: 360,
1125+
},
1126+
},
1127+
displayOnBackground: true,
1128+
currentVideo: {
1129+
viewport: {
1130+
x: 1920,
1131+
y: 1080,
1132+
},
1133+
topLeft: {
1134+
x: 0,
1135+
y: 0,
1136+
},
1137+
size: {
1138+
x: 960,
1139+
y: 540,
1140+
},
1141+
},
1142+
background: 'red',
1143+
};
1144+
expect(interstitials[0]).toEqual(expectedInterstitial);
1145+
});
10471146
});
10481147

10491148
describe('custom', () => {

0 commit comments

Comments
 (0)