stormcloud-video-player 0.8.48 → 0.8.49

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/lib/index.cjs CHANGED
@@ -615,9 +615,11 @@ function createHlsAdPlayer(contentVideo, options) {
615
615
  var pendingTimeouts = [];
616
616
  var STALL_TIMEOUT_MS = 4e3;
617
617
  var STALL_CHECK_INTERVAL_MS = 1e3;
618
+ var BLACKFRAME_MIN_PLAYBACK_S = 1.5;
618
619
  var stallWatchdogId;
619
620
  var lastAdProgressTime = 0;
620
621
  var lastAdProgressPosition = 0;
622
+ var sawDecodedVideoFrame = false;
621
623
  var trackingFired = {
622
624
  impression: false,
623
625
  start: false,
@@ -798,6 +800,11 @@ function createHlsAdPlayer(contentVideo, options) {
798
800
  console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
799
801
  return;
800
802
  }
803
+ var hasExplicitDimensions = mf.getAttribute("width") != null && mf.getAttribute("height") != null;
804
+ if (!isHlsMediaFile(mediaFile) && hasExplicitDimensions && (mediaFile.width <= 1 || mediaFile.height <= 1)) {
805
+ 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'));
806
+ return;
807
+ }
801
808
  if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
802
809
  mediaFiles.push(mediaFile);
803
810
  if (verbose) {
@@ -1265,6 +1272,14 @@ function createHlsAdPlayer(contentVideo, options) {
1265
1272
  fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
1266
1273
  }
1267
1274
  };
1275
+ var onLoadedMetadata = function onLoadedMetadata() {
1276
+ if (!adPlaying || !adVideoElement) return;
1277
+ var videoWidth = adVideoElement.videoWidth, videoHeight = adVideoElement.videoHeight;
1278
+ if (videoWidth <= 1 || videoHeight <= 1) {
1279
+ console.warn("[HlsAdPlayer] Ad creative has no usable video dimensions (".concat(videoWidth, "x").concat(videoHeight, ") - skipping this creative"));
1280
+ handleVideoDecodeFailure();
1281
+ }
1282
+ };
1268
1283
  var onPlaying = function onPlaying() {
1269
1284
  startStallWatchdog();
1270
1285
  if (!currentAd || trackingFired.start) return;
@@ -1316,6 +1331,10 @@ function createHlsAdPlayer(contentVideo, options) {
1316
1331
  type: "timeupdate",
1317
1332
  handler: onTimeUpdate
1318
1333
  },
1334
+ {
1335
+ type: "loadedmetadata",
1336
+ handler: onLoadedMetadata
1337
+ },
1319
1338
  {
1320
1339
  type: "playing",
1321
1340
  handler: onPlaying
@@ -1505,13 +1524,51 @@ function createHlsAdPlayer(contentVideo, options) {
1505
1524
  }
1506
1525
  handleAdError();
1507
1526
  }
1527
+ function getDecodedVideoFrameCount(video) {
1528
+ try {
1529
+ if (typeof video.getVideoPlaybackQuality === "function") {
1530
+ var quality = video.getVideoPlaybackQuality();
1531
+ if (quality && typeof quality.totalVideoFrames === "number") {
1532
+ return quality.totalVideoFrames;
1533
+ }
1534
+ }
1535
+ var legacyCount = video.webkitDecodedFrameCount;
1536
+ if (typeof legacyCount === "number") {
1537
+ return legacyCount;
1538
+ }
1539
+ } catch (error) {
1540
+ console.warn("[HlsAdPlayer] Unable to read decoded video frame count:", error);
1541
+ }
1542
+ return void 0;
1543
+ }
1544
+ function handleVideoDecodeFailure() {
1545
+ console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1546
+ clearStallWatchdog();
1547
+ if (currentAd) {
1548
+ fireTrackingPixels(currentAd.trackingUrls.error);
1549
+ }
1550
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1551
+ return;
1552
+ }
1553
+ handleAdError();
1554
+ }
1508
1555
  function startStallWatchdog() {
1509
1556
  clearStallWatchdog();
1510
1557
  noteAdProgress();
1558
+ sawDecodedVideoFrame = false;
1511
1559
  stallWatchdogId = window.setInterval(function() {
1512
1560
  if (!adPlaying || !adVideoElement) {
1513
1561
  return;
1514
1562
  }
1563
+ if (!sawDecodedVideoFrame && !adVideoElement.paused) {
1564
+ var decodedFrames = getDecodedVideoFrameCount(adVideoElement);
1565
+ if (decodedFrames !== void 0 && decodedFrames > 0) {
1566
+ sawDecodedVideoFrame = true;
1567
+ } else if (decodedFrames === 0 && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1568
+ handleVideoDecodeFailure();
1569
+ return;
1570
+ }
1571
+ }
1515
1572
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1516
1573
  noteAdProgress();
1517
1574
  return;