Skip to content

Video Playback in Creative-Engine

Components

CreativeVideoBlock.vue

The main video rendering component. Handles both MP4 and HLS playback.

Rendering modes:

  • streaming: false -- native <video> element with progressive MP4 source
  • streaming: true -- @cavai/minimal-video VideoPlayer component (HLS.js wrapper)

Resolution calculation:

  • Adapts video resolution based on device pixel ratio (1x to 1.2x scaling)
  • Maximum width capped at 1920px
  • Dimensions forced to even pixel values (required for video encoding compatibility)

Layout modes:

  • scale -- cover with crop (CSS object-fit: cover)
  • preserve -- contain with letterbox (CSS object-fit: contain)
  • stretch -- fill (CSS object-fit: fill)

CreativeVideoControls.vue

Play/Pause and Mute/Unmute toggle buttons overlaid on the video.

  • Rendered as a separate <section class="video-controls"> outside Vue templates
  • Uses mix-blend-mode and dual layers for a shadow effect
  • Created/destroyed when the video block mounts/unmounts

Playback Logic

Autoplay

Video autoplays when all conditions are met:

  1. autoplay is enabled in block properties
  2. The creative is in view (intersection observer)
  3. allowAutoStart is true in video state

Pause Conditions

Playback pauses when any of these are reached:

  • Loop count: pauseMeasure: 'loop' with pauseAfter: N -- pauses after N complete loops
  • Time limit: pauseMeasure: 'sec' with pauseAfter: N -- pauses after N seconds of total play time
  • Infinity: pauseMeasure: 'infinity' -- loops forever (default)

Pause Out of View

When pauseOutOfView is enabled, the video pauses when the creative scrolls out of the viewport and resumes when it comes back into view.

Video Restart (Flow Operator)

The Restart operator in the flow system sets shouldRestart: true in video state. This resets allowAutoStart and restarts playback from the beginning.

Video State

Stored in DataStore.videoState:

typescript
{
  state: 'paused' | 'playing' | 'ended',
  isMuted: boolean,
  allowAutoStart: boolean,
  shouldRestart: boolean
}

changeVideo (Dynamic Video Swap)

Flow operators and scripts can swap the video at runtime using changeVideo.

How it works:

  1. A ChangeVideoOp (or script) sets a new streamId on the video block
  2. The changeVideo watch handler in CreativeBody.vue fires
  3. streamParser(streamId) fetches the HLS manifest for the new video
  4. Stream data (including dimensions and HLS segments) is applied to the block
  5. The video player reloads with the new source

Historical bug (fixed in CE PR #728): Before the fix, changeVideo only passed streamId without streamData, so the engine forced streaming = false and fell back to full MP4 download. The fix fetches the HLS manifest during the swap, enabling streaming for dynamically changed videos.

Metrics

Video playback fires analytics events:

  • playCount -- tracked on first play only
  • playPercentage -- reported at 0%, 25%, 50%, 75%, 100% thresholds
  • Sent via Analytics.sendVideoBackgroundFlow(metrics)

These metrics are separate from VAST tracking events -- they fire for all video playback (not just VAST delivery).

Internal documentation