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.cjs
CHANGED
|
@@ -601,6 +601,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
601
601
|
var mainHlsInstance = options === null || options === void 0 ? void 0 : options.mainHlsInstance;
|
|
602
602
|
var AD_CONTAINER_PROP = "__stormcloudAdContainer";
|
|
603
603
|
var AD_VIDEO_PROP = "__stormcloudAdVideo";
|
|
604
|
+
var FRAME_COUNTER_RELIABLE_PROP = "__stormcloudFrameCounterReliable";
|
|
604
605
|
var adVideoElement = (_contentVideo_AD_VIDEO_PROP = contentVideo[AD_VIDEO_PROP]) !== null && _contentVideo_AD_VIDEO_PROP !== void 0 ? _contentVideo_AD_VIDEO_PROP : void 0;
|
|
605
606
|
var adHls;
|
|
606
607
|
var adContainerEl = (_contentVideo_AD_CONTAINER_PROP = contentVideo[AD_CONTAINER_PROP]) !== null && _contentVideo_AD_CONTAINER_PROP !== void 0 ? _contentVideo_AD_CONTAINER_PROP : void 0;
|
|
@@ -615,9 +616,12 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
615
616
|
var pendingTimeouts = [];
|
|
616
617
|
var STALL_TIMEOUT_MS = 4e3;
|
|
617
618
|
var STALL_CHECK_INTERVAL_MS = 1e3;
|
|
619
|
+
var BLACKFRAME_MIN_PLAYBACK_S = 1.5;
|
|
618
620
|
var stallWatchdogId;
|
|
619
621
|
var lastAdProgressTime = 0;
|
|
620
622
|
var lastAdProgressPosition = 0;
|
|
623
|
+
var sawDecodedVideoFrame = false;
|
|
624
|
+
var videoFrameCallbackHandle;
|
|
621
625
|
var trackingFired = {
|
|
622
626
|
impression: false,
|
|
623
627
|
start: false,
|
|
@@ -798,6 +802,11 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
798
802
|
console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
|
|
799
803
|
return;
|
|
800
804
|
}
|
|
805
|
+
var hasExplicitDimensions = mf.getAttribute("width") != null && mf.getAttribute("height") != null;
|
|
806
|
+
if (!isHlsMediaFile(mediaFile) && hasExplicitDimensions && (mediaFile.width <= 1 || mediaFile.height <= 1)) {
|
|
807
|
+
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'));
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
801
810
|
if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
|
|
802
811
|
mediaFiles.push(mediaFile);
|
|
803
812
|
if (verbose) {
|
|
@@ -1265,6 +1274,14 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1265
1274
|
fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
|
|
1266
1275
|
}
|
|
1267
1276
|
};
|
|
1277
|
+
var onLoadedMetadata = function onLoadedMetadata() {
|
|
1278
|
+
if (!adPlaying || !adVideoElement) return;
|
|
1279
|
+
var videoWidth = adVideoElement.videoWidth, videoHeight = adVideoElement.videoHeight;
|
|
1280
|
+
if (videoWidth <= 1 || videoHeight <= 1) {
|
|
1281
|
+
console.warn("[HlsAdPlayer] Ad creative has no usable video dimensions (".concat(videoWidth, "x").concat(videoHeight, ") - skipping this creative"));
|
|
1282
|
+
handleVideoDecodeFailure();
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1268
1285
|
var onPlaying = function onPlaying() {
|
|
1269
1286
|
startStallWatchdog();
|
|
1270
1287
|
if (!currentAd || trackingFired.start) return;
|
|
@@ -1316,6 +1333,10 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1316
1333
|
type: "timeupdate",
|
|
1317
1334
|
handler: onTimeUpdate
|
|
1318
1335
|
},
|
|
1336
|
+
{
|
|
1337
|
+
type: "loadedmetadata",
|
|
1338
|
+
handler: onLoadedMetadata
|
|
1339
|
+
},
|
|
1319
1340
|
{
|
|
1320
1341
|
type: "playing",
|
|
1321
1342
|
handler: onPlaying
|
|
@@ -1487,6 +1508,7 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1487
1508
|
clearInterval(stallWatchdogId);
|
|
1488
1509
|
stallWatchdogId = void 0;
|
|
1489
1510
|
}
|
|
1511
|
+
cancelVideoFrameProbe();
|
|
1490
1512
|
}
|
|
1491
1513
|
function noteAdProgress() {
|
|
1492
1514
|
lastAdProgressTime = Date.now();
|
|
@@ -1505,13 +1527,86 @@ function createHlsAdPlayer(contentVideo, options) {
|
|
|
1505
1527
|
}
|
|
1506
1528
|
handleAdError();
|
|
1507
1529
|
}
|
|
1530
|
+
function getDecodedVideoFrameCount(video) {
|
|
1531
|
+
try {
|
|
1532
|
+
if (typeof video.getVideoPlaybackQuality === "function") {
|
|
1533
|
+
var quality = video.getVideoPlaybackQuality();
|
|
1534
|
+
if (quality && typeof quality.totalVideoFrames === "number") {
|
|
1535
|
+
return quality.totalVideoFrames;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
var legacyCount = video.webkitDecodedFrameCount;
|
|
1539
|
+
if (typeof legacyCount === "number") {
|
|
1540
|
+
return legacyCount;
|
|
1541
|
+
}
|
|
1542
|
+
} catch (error) {
|
|
1543
|
+
console.warn("[HlsAdPlayer] Unable to read decoded video frame count:", error);
|
|
1544
|
+
}
|
|
1545
|
+
return void 0;
|
|
1546
|
+
}
|
|
1547
|
+
function isFrameCounterReliable() {
|
|
1548
|
+
return contentVideo[FRAME_COUNTER_RELIABLE_PROP] === true;
|
|
1549
|
+
}
|
|
1550
|
+
function markFrameCounterReliable() {
|
|
1551
|
+
contentVideo[FRAME_COUNTER_RELIABLE_PROP] = true;
|
|
1552
|
+
}
|
|
1553
|
+
function cancelVideoFrameProbe() {
|
|
1554
|
+
if (videoFrameCallbackHandle != null && adVideoElement && typeof adVideoElement.cancelVideoFrameCallback === "function") {
|
|
1555
|
+
try {
|
|
1556
|
+
adVideoElement.cancelVideoFrameCallback(videoFrameCallbackHandle);
|
|
1557
|
+
} catch (error) {
|
|
1558
|
+
console.warn("[HlsAdPlayer] Error cancelling video frame callback:", error);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
videoFrameCallbackHandle = void 0;
|
|
1562
|
+
}
|
|
1563
|
+
function startVideoFrameProbe() {
|
|
1564
|
+
cancelVideoFrameProbe();
|
|
1565
|
+
if (!adVideoElement) return;
|
|
1566
|
+
var rvfc = adVideoElement.requestVideoFrameCallback;
|
|
1567
|
+
if (typeof rvfc !== "function") return;
|
|
1568
|
+
var onPresentedFrame = function onPresentedFrame() {
|
|
1569
|
+
videoFrameCallbackHandle = void 0;
|
|
1570
|
+
if (!adPlaying) return;
|
|
1571
|
+
sawDecodedVideoFrame = true;
|
|
1572
|
+
};
|
|
1573
|
+
try {
|
|
1574
|
+
videoFrameCallbackHandle = rvfc.call(adVideoElement, onPresentedFrame);
|
|
1575
|
+
} catch (error) {
|
|
1576
|
+
console.warn("[HlsAdPlayer] Error requesting video frame callback:", error);
|
|
1577
|
+
videoFrameCallbackHandle = void 0;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
function handleVideoDecodeFailure() {
|
|
1581
|
+
console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
|
|
1582
|
+
clearStallWatchdog();
|
|
1583
|
+
if (currentAd) {
|
|
1584
|
+
fireTrackingPixels(currentAd.trackingUrls.error);
|
|
1585
|
+
}
|
|
1586
|
+
if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1589
|
+
handleAdError();
|
|
1590
|
+
}
|
|
1508
1591
|
function startStallWatchdog() {
|
|
1509
1592
|
clearStallWatchdog();
|
|
1510
1593
|
noteAdProgress();
|
|
1594
|
+
sawDecodedVideoFrame = false;
|
|
1595
|
+
startVideoFrameProbe();
|
|
1511
1596
|
stallWatchdogId = window.setInterval(function() {
|
|
1512
1597
|
if (!adPlaying || !adVideoElement) {
|
|
1513
1598
|
return;
|
|
1514
1599
|
}
|
|
1600
|
+
if (!sawDecodedVideoFrame && !adVideoElement.paused) {
|
|
1601
|
+
var decodedFrames = getDecodedVideoFrameCount(adVideoElement);
|
|
1602
|
+
if (decodedFrames !== void 0 && decodedFrames > 0) {
|
|
1603
|
+
sawDecodedVideoFrame = true;
|
|
1604
|
+
markFrameCounterReliable();
|
|
1605
|
+
} else if (decodedFrames === 0 && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S && isFrameCounterReliable()) {
|
|
1606
|
+
handleVideoDecodeFailure();
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1515
1610
|
if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
|
|
1516
1611
|
noteAdProgress();
|
|
1517
1612
|
return;
|
|
@@ -6396,17 +6491,17 @@ var AdTimingService = /*#__PURE__*/ function() {
|
|
|
6396
6491
|
{
|
|
6397
6492
|
key: "logAdState",
|
|
6398
6493
|
value: function logAdState(event) {
|
|
6399
|
-
var extra = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}
|
|
6400
|
-
var _ref;
|
|
6494
|
+
var extra = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {};
|
|
6401
6495
|
if (!this.debug) {
|
|
6402
6496
|
return;
|
|
6403
6497
|
}
|
|
6498
|
+
var _this_callbacks_getAdState = this.callbacks.getAdState(), inAdBreak = _this_callbacks_getAdState.inAdBreak, showAds = _this_callbacks_getAdState.showAds, adPlaying = _this_callbacks_getAdState.adPlaying;
|
|
6404
6499
|
console.log("[StormcloudVideoPlayer][AdState]", _object_spread({
|
|
6405
6500
|
event: event,
|
|
6406
6501
|
timestamp: /* @__PURE__ */ new Date().toISOString(),
|
|
6407
|
-
showAds: showAds
|
|
6408
|
-
adPlaying:
|
|
6409
|
-
inAdBreak: inAdBreak
|
|
6502
|
+
showAds: showAds,
|
|
6503
|
+
adPlaying: adPlaying,
|
|
6504
|
+
inAdBreak: inAdBreak,
|
|
6410
6505
|
activeAdRequestToken: this.activeAdRequestToken
|
|
6411
6506
|
}, extra));
|
|
6412
6507
|
}
|
|
@@ -8756,6 +8851,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
|
|
|
8756
8851
|
},
|
|
8757
8852
|
onFailsafeTimeout: function onFailsafeTimeout() {
|
|
8758
8853
|
return _this.adBreak.handleAdFailure();
|
|
8854
|
+
},
|
|
8855
|
+
getAdState: function getAdState() {
|
|
8856
|
+
return {
|
|
8857
|
+
inAdBreak: _this.adBreak.inAdBreak,
|
|
8858
|
+
showAds: _this.adBreak.showAds,
|
|
8859
|
+
adPlaying: _this.adPlayer.isAdPlaying()
|
|
8860
|
+
};
|
|
8759
8861
|
}
|
|
8760
8862
|
});
|
|
8761
8863
|
this.placeholder = new PlaceholderLayer(this.video, !!this.config.debugAdTiming);
|