stormcloud-video-player 0.8.48 → 0.8.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/stormcloud-vp.min.js +2 -2
- package/lib/index.cjs +107 -5
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +107 -5
- package/lib/index.js.map +1 -1
- package/lib/player/AdTimingService.cjs +5 -5
- package/lib/player/AdTimingService.cjs.map +1 -1
- package/lib/player/AdTimingService.d.cts +6 -1
- package/lib/player/StormcloudVideoPlayer.cjs +107 -5
- package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
- package/lib/players/HlsPlayer.cjs +107 -5
- package/lib/players/HlsPlayer.cjs.map +1 -1
- package/lib/players/index.cjs +107 -5
- package/lib/players/index.cjs.map +1 -1
- package/lib/sdk/hlsAdPlayer.cjs +95 -0
- package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
- package/lib/types-iDjS8f_7.d.cts +133 -0
- package/lib/ui/StormcloudVideoPlayer.cjs +107 -5
- package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -381,6 +381,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
381
381
|
var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
|
|
382
382
|
var AD_CONTAINER_PROP = "__stormcloudAdContainer";
|
|
383
383
|
var AD_VIDEO_PROP = "__stormcloudAdVideo";
|
|
384
|
+
var FRAME_COUNTER_RELIABLE_PROP = "__stormcloudFrameCounterReliable";
|
|
384
385
|
var adVideoElement = (_contentVideo_AD_VIDEO_PROP = contentVideo[AD_VIDEO_PROP]) !== null && _contentVideo_AD_VIDEO_PROP !== void 0 ? _contentVideo_AD_VIDEO_PROP : void 0;
|
|
385
386
|
var adHls;
|
|
386
387
|
var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
|
|
@@ -395,9 +396,12 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
395
396
|
var pendingTimeouts = [];
|
|
396
397
|
var STALL_TIMEOUT_MS = 4e3;
|
|
397
398
|
var STALL_CHECK_INTERVAL_MS = 1e3;
|
|
399
|
+
var BLACKFRAME_MIN_PLAYBACK_S = 1.5;
|
|
398
400
|
var stallWatchdogId;
|
|
399
401
|
var lastAdProgressTime = 0;
|
|
400
402
|
var lastAdProgressPosition = 0;
|
|
403
|
+
var sawDecodedVideoFrame = false;
|
|
404
|
+
var videoFrameCallbackHandle;
|
|
401
405
|
var trackingFired = {
|
|
402
406
|
impression: false,
|
|
403
407
|
start: false,
|
|
@@ -578,6 +582,11 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
578
582
|
console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
|
|
579
583
|
return;
|
|
580
584
|
}
|
|
585
|
+
var hasExplicitDimensions = mf.getAttribute("width") != null && mf.getAttribute("height") != null;
|
|
586
|
+
if (!isHlsMediaFile(mediaFile) && hasExplicitDimensions && (mediaFile.width <= 1 || mediaFile.height <= 1)) {
|
|
587
|
+
console.warn("[HlsAdPlayer] MediaFile ".concat(index, " skipped (degenerate dimensions ").concat(mediaFile.width, "x").concat(mediaFile.height, ', type="').concat(type, '") — likely an audio-only placeholder rendition'));
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
581
590
|
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
582
591
|
mediaFiles.push(mediaFile);
|
|
583
592
|
if (verbose) {
|
|
@@ -1045,6 +1054,14 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1045
1054
|
fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
|
|
1046
1055
|
}
|
|
1047
1056
|
};
|
|
1057
|
+
var onLoadedMetadata = function onLoadedMetadata() {
|
|
1058
|
+
if (!adPlaying || !adVideoElement) return;
|
|
1059
|
+
var videoWidth = adVideoElement.videoWidth, videoHeight = adVideoElement.videoHeight;
|
|
1060
|
+
if (videoWidth <= 1 || videoHeight <= 1) {
|
|
1061
|
+
console.warn("[HlsAdPlayer] Ad creative has no usable video dimensions (".concat(videoWidth, "x").concat(videoHeight, ") - skipping this creative"));
|
|
1062
|
+
handleVideoDecodeFailure();
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1048
1065
|
var onPlaying = function onPlaying() {
|
|
1049
1066
|
startStallWatchdog();
|
|
1050
1067
|
if (!currentAd || trackingFired.start) return;
|
|
@@ -1096,6 +1113,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1096
1113
|
type: "timeupdate",
|
|
1097
1114
|
handler: onTimeUpdate
|
|
1098
1115
|
},
|
|
1116
|
+
{
|
|
1117
|
+
type: "loadedmetadata",
|
|
1118
|
+
handler: onLoadedMetadata
|
|
1119
|
+
},
|
|
1099
1120
|
{
|
|
1100
1121
|
type: "playing",
|
|
1101
1122
|
handler: onPlaying
|
|
@@ -1267,6 +1288,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1267
1288
|
clearInterval(stallWatchdogId);
|
|
1268
1289
|
stallWatchdogId = void 0;
|
|
1269
1290
|
}
|
|
1291
|
+
cancelVideoFrameProbe();
|
|
1270
1292
|
}
|
|
1271
1293
|
function noteAdProgress() {
|
|
1272
1294
|
lastAdProgressTime = Date.now();
|
|
@@ -1285,13 +1307,86 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1285
1307
|
}
|
|
1286
1308
|
handleAdError();
|
|
1287
1309
|
}
|
|
1310
|
+
function getDecodedVideoFrameCount(video) {
|
|
1311
|
+
try {
|
|
1312
|
+
if (typeof video.getVideoPlaybackQuality === "function") {
|
|
1313
|
+
var quality = video.getVideoPlaybackQuality();
|
|
1314
|
+
if (quality && typeof quality.totalVideoFrames === "number") {
|
|
1315
|
+
return quality.totalVideoFrames;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
var legacyCount = video.webkitDecodedFrameCount;
|
|
1319
|
+
if (typeof legacyCount === "number") {
|
|
1320
|
+
return legacyCount;
|
|
1321
|
+
}
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
console.warn("[HlsAdPlayer] Unable to read decoded video frame count:", error);
|
|
1324
|
+
}
|
|
1325
|
+
return void 0;
|
|
1326
|
+
}
|
|
1327
|
+
function isFrameCounterReliable() {
|
|
1328
|
+
return contentVideo[FRAME_COUNTER_RELIABLE_PROP] === true;
|
|
1329
|
+
}
|
|
1330
|
+
function markFrameCounterReliable() {
|
|
1331
|
+
contentVideo[FRAME_COUNTER_RELIABLE_PROP] = true;
|
|
1332
|
+
}
|
|
1333
|
+
function cancelVideoFrameProbe() {
|
|
1334
|
+
if (videoFrameCallbackHandle != null && adVideoElement && typeof adVideoElement.cancelVideoFrameCallback === "function") {
|
|
1335
|
+
try {
|
|
1336
|
+
adVideoElement.cancelVideoFrameCallback(videoFrameCallbackHandle);
|
|
1337
|
+
} catch (error) {
|
|
1338
|
+
console.warn("[HlsAdPlayer] Error cancelling video frame callback:", error);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
videoFrameCallbackHandle = void 0;
|
|
1342
|
+
}
|
|
1343
|
+
function startVideoFrameProbe() {
|
|
1344
|
+
cancelVideoFrameProbe();
|
|
1345
|
+
if (!adVideoElement) return;
|
|
1346
|
+
var rvfc = adVideoElement.requestVideoFrameCallback;
|
|
1347
|
+
if (typeof rvfc !== "function") return;
|
|
1348
|
+
var onPresentedFrame = function onPresentedFrame() {
|
|
1349
|
+
videoFrameCallbackHandle = void 0;
|
|
1350
|
+
if (!adPlaying) return;
|
|
1351
|
+
sawDecodedVideoFrame = true;
|
|
1352
|
+
};
|
|
1353
|
+
try {
|
|
1354
|
+
videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
console.warn("[HlsAdPlayer] Error requesting video frame callback:", error);
|
|
1357
|
+
videoFrameCallbackHandle = void 0;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
function handleVideoDecodeFailure() {
|
|
1361
|
+
console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
|
|
1362
|
+
clearStallWatchdog();
|
|
1363
|
+
if (currentAd) {
|
|
1364
|
+
fireTrackingPixels(currentAd.trackingUrls.error);
|
|
1365
|
+
}
|
|
1366
|
+
if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
handleAdError();
|
|
1370
|
+
}
|
|
1288
1371
|
function startStallWatchdog() {
|
|
1289
1372
|
clearStallWatchdog();
|
|
1290
1373
|
noteAdProgress();
|
|
1374
|
+
sawDecodedVideoFrame = false;
|
|
1375
|
+
startVideoFrameProbe();
|
|
1291
1376
|
stallWatchdogId = window.setInterval(function() {
|
|
1292
1377
|
if (!adPlaying || !adVideoElement) {
|
|
1293
1378
|
return;
|
|
1294
1379
|
}
|
|
1380
|
+
if (!sawDecodedVideoFrame && !adVideoElement.paused) {
|
|
1381
|
+
var decodedFrames = getDecodedVideoFrameCount(adVideoElement);
|
|
1382
|
+
if (decodedFrames !== void 0 && decodedFrames > 0) {
|
|
1383
|
+
sawDecodedVideoFrame = true;
|
|
1384
|
+
markFrameCounterReliable();
|
|
1385
|
+
} else if (decodedFrames === 0 && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && isFrameCounterReliable()) {
|
|
1386
|
+
handleVideoDecodeFailure();
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1295
1390
|
if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
|
|
1296
1391
|
noteAdProgress();
|
|
1297
1392
|
return;
|
|
@@ -6182,17 +6277,17 @@ var AdTimingService = /*#__PURE__*/ function() {
|
|
|
6182
6277
|
{
|
|
6183
6278
|
key: "logAdState",
|
|
6184
6279
|
value: function logAdState(event) {
|
|
6185
|
-
var extra = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}
|
|
6186
|
-
var _ref;
|
|
6280
|
+
var extra = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
|
|
6187
6281
|
if (!this.debug) {
|
|
6188
6282
|
return;
|
|
6189
6283
|
}
|
|
6284
|
+
var _this_callbacks_getAdState = this.callbacks.getAdState(), inAdBreak = _this_callbacks_getAdState.inAdBreak, showAds = _this_callbacks_getAdState.showAds, adPlaying = _this_callbacks_getAdState.adPlaying;
|
|
6190
6285
|
console.log("[StormcloudVideoPlayer][AdState]", _object_spread({
|
|
6191
6286
|
event: event,
|
|
6192
6287
|
timestamp: /* @__PURE__ */ new Date().toISOString(),
|
|
6193
|
-
showAds: showAds
|
|
6194
|
-
adPlaying:
|
|
6195
|
-
inAdBreak: inAdBreak
|
|
6288
|
+
showAds: showAds,
|
|
6289
|
+
adPlaying: adPlaying,
|
|
6290
|
+
inAdBreak: inAdBreak,
|
|
6196
6291
|
activeAdRequestToken: this.activeAdRequestToken
|
|
6197
6292
|
}, extra));
|
|
6198
6293
|
}
|
|
@@ -8546,6 +8641,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
8546
8641
|
},
|
|
8547
8642
|
onFailsafeTimeout: function onFailsafeTimeout() {
|
|
8548
8643
|
return _this.adBreak.handleAdFailure();
|
|
8644
|
+
},
|
|
8645
|
+
getAdState: function getAdState() {
|
|
8646
|
+
return {
|
|
8647
|
+
inAdBreak: _this.adBreak.inAdBreak,
|
|
8648
|
+
showAds: _this.adBreak.showAds,
|
|
8649
|
+
adPlaying: _this.adPlayer.isAdPlaying()
|
|
8650
|
+
};
|
|
8549
8651
|
}
|
|
8550
8652
|
});
|
|
8551
8653
|
this.placeholder = new PlaceholderLayer(this.video, !!this.config.debugAdTiming);
|