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.js CHANGED
@@ -395,9 +395,11 @@ function createHlsAdPlayer(contentVideo, options) {
395
395
  var pendingTimeouts = [];
396
396
  var STALL_TIMEOUT_MS = 4e3;
397
397
  var STALL_CHECK_INTERVAL_MS = 1e3;
398
+ var BLACKFRAME_MIN_PLAYBACK_S = 1.5;
398
399
  var stallWatchdogId;
399
400
  var lastAdProgressTime = 0;
400
401
  var lastAdProgressPosition = 0;
402
+ var sawDecodedVideoFrame = false;
401
403
  var trackingFired = {
402
404
  impression: false,
403
405
  start: false,
@@ -578,6 +580,11 @@ function createHlsAdPlayer(contentVideo, options) {
578
580
  console.warn("[HlsAdPlayer] MediaFile ".concat(index, ' skipped (audio-only, type="').concat(type, '") — audio ads are not played to avoid a black screen'));
579
581
  return;
580
582
  }
583
+ var hasExplicitDimensions = mf.getAttribute("width") != null && mf.getAttribute("height") != null;
584
+ if (!isHlsMediaFile(mediaFile) && hasExplicitDimensions && (mediaFile.width <= 1 || mediaFile.height <= 1)) {
585
+ 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'));
586
+ return;
587
+ }
581
588
  if (isHlsMediaFile(mediaFile) || isProgressiveMediaFile(mediaFile)) {
582
589
  mediaFiles.push(mediaFile);
583
590
  if (verbose) {
@@ -1045,6 +1052,14 @@ function createHlsAdPlayer(contentVideo, options) {
1045
1052
  fireTrackingPixels(currentAd.trackingUrls.thirdQuartile);
1046
1053
  }
1047
1054
  };
1055
+ var onLoadedMetadata = function onLoadedMetadata() {
1056
+ if (!adPlaying || !adVideoElement) return;
1057
+ var videoWidth = adVideoElement.videoWidth, videoHeight = adVideoElement.videoHeight;
1058
+ if (videoWidth <= 1 || videoHeight <= 1) {
1059
+ console.warn("[HlsAdPlayer] Ad creative has no usable video dimensions (".concat(videoWidth, "x").concat(videoHeight, ") - skipping this creative"));
1060
+ handleVideoDecodeFailure();
1061
+ }
1062
+ };
1048
1063
  var onPlaying = function onPlaying() {
1049
1064
  startStallWatchdog();
1050
1065
  if (!currentAd || trackingFired.start) return;
@@ -1096,6 +1111,10 @@ function createHlsAdPlayer(contentVideo, options) {
1096
1111
  type: "timeupdate",
1097
1112
  handler: onTimeUpdate
1098
1113
  },
1114
+ {
1115
+ type: "loadedmetadata",
1116
+ handler: onLoadedMetadata
1117
+ },
1099
1118
  {
1100
1119
  type: "playing",
1101
1120
  handler: onPlaying
@@ -1285,13 +1304,51 @@ function createHlsAdPlayer(contentVideo, options) {
1285
1304
  }
1286
1305
  handleAdError();
1287
1306
  }
1307
+ function getDecodedVideoFrameCount(video) {
1308
+ try {
1309
+ if (typeof video.getVideoPlaybackQuality === "function") {
1310
+ var quality = video.getVideoPlaybackQuality();
1311
+ if (quality && typeof quality.totalVideoFrames === "number") {
1312
+ return quality.totalVideoFrames;
1313
+ }
1314
+ }
1315
+ var legacyCount = video.webkitDecodedFrameCount;
1316
+ if (typeof legacyCount === "number") {
1317
+ return legacyCount;
1318
+ }
1319
+ } catch (error) {
1320
+ console.warn("[HlsAdPlayer] Unable to read decoded video frame count:", error);
1321
+ }
1322
+ return void 0;
1323
+ }
1324
+ function handleVideoDecodeFailure() {
1325
+ console.warn("[HlsAdPlayer] Ad audio is advancing but no video frames decoded (black screen) - skipping this creative");
1326
+ clearStallWatchdog();
1327
+ if (currentAd) {
1328
+ fireTrackingPixels(currentAd.trackingUrls.error);
1329
+ }
1330
+ if (podIndex < podAds.length - 1 && advanceToNextPodAd()) {
1331
+ return;
1332
+ }
1333
+ handleAdError();
1334
+ }
1288
1335
  function startStallWatchdog() {
1289
1336
  clearStallWatchdog();
1290
1337
  noteAdProgress();
1338
+ sawDecodedVideoFrame = false;
1291
1339
  stallWatchdogId = window.setInterval(function() {
1292
1340
  if (!adPlaying || !adVideoElement) {
1293
1341
  return;
1294
1342
  }
1343
+ if (!sawDecodedVideoFrame && !adVideoElement.paused) {
1344
+ var decodedFrames = getDecodedVideoFrameCount(adVideoElement);
1345
+ if (decodedFrames !== void 0 && decodedFrames > 0) {
1346
+ sawDecodedVideoFrame = true;
1347
+ } else if (decodedFrames === 0 && adVideoElement.currentTime >= BLACKFRAME_MIN_PLAYBACK_S) {
1348
+ handleVideoDecodeFailure();
1349
+ return;
1350
+ }
1351
+ }
1295
1352
  if (adVideoElement.currentTime > lastAdProgressPosition + 0.05) {
1296
1353
  noteAdProgress();
1297
1354
  return;