Craft Streaming Video Plugin

A Craft CMS plugin that automatically generates HLS (HTTP Live Streaming) variants for video assets, enabling adaptive streaming with multiple quality levels.

The plugin handles generating the variants, and includes a basic template that renders the video using hls.js. It doesn't apply any styling to the video, that is left up to the developer. You can also use GraphQL to handle the entire frontend yourself.

This plugin is useful for websites hosting longer videos, which don't want to use video services to embed videos due to privacy or design concerns.

Features

  • 🎥 Automatic HLS Generation: Converts uploaded videos to HLS format with multiple quality variants
  • 📱 Adaptive Streaming: Automatically switches quality based on viewer's bandwidth and device
  • 🎛️ Multiple Quality Levels: Generates 1080p, 720p, 480p, 240p, and 144p variants (plus source quality)
  • 📐 Aspect Ratio Preservation: Maintains original video proportions for any format (not just 16:9)
  • 🔧 Smart Resolution Detection: Only generates variants at or below the source video resolution
  • 🌐 Cross-Platform Storage: Works with local storage, AWS S3, and other Craft volume types
  • 🎮 Frontend Integration: Includes Twig template and GraphQL support

Requirements

  • Craft CMS 5.0 or later
  • PHP 8.2 or later
  • FFmpeg installed on the server

Installation

1. Install the Plugin

# Via Composer
composer require buesing/craft-streaming-video

# Install via Craft CLI
php craft plugin/install streaming-video

2. Install FFmpeg

The plugin requires FFmpeg to be installed on your server.

DDEV

Add to your .ddev/config.yaml:

webimage_extra_packages:
  - ffmpeg

Then restart DDEV:

ddev restart

Other Environments

  • Ubuntu/Debian: sudo apt-get install ffmpeg
  • CentOS/RHEL: sudo yum install ffmpeg
  • macOS: brew install ffmpeg
  • Docker: Include FFmpeg in your container image

3. Make sure CORS is enabled

If assets are hosted on another origin than the main site, ensure CORS access is properly configured for HLS streaming to work.

How It Works

  1. Upload Detection: When a video asset is uploaded or saved, the plugin automatically detects it
  2. Queue Processing: An HLS preparation job is queued to avoid blocking the upload
  3. Quality Generation: FFmpeg generates multiple quality variants based on the source resolution. During generation, the template falls back to the normal video file. hlsPlaylistUrl will return null during that time.
  4. File Storage: HLS files are stored in a separate __hls__/{asset-uid}/ folder in the same volume
  5. Cleanup: When an asset is deleted, all associated HLS files are automatically removed

Usage

Frontend Templates

Basic Video Player

{% set video = entry.video.one() %}
{% if video and video.hlsPlaylistUrl %}
    {% include '_streamingvideo/player.twig' with { asset: video } %}
{% else %}
    <video controls>
        <source src="{{ video.url }}" type="{{ video.mimeType }}">
    </video>
{% endif %}

All Player Options

The player template supports the following options:

OptionTypeDefaultDescription
assetAssetThe Craft Asset element (required)
autoplayboolfalseAutoplay the video
mutedboolfalseMute the video
loopboolfalseLoop the video
playsinlineboolfalsePlay inline on mobile devices
posterAsset or stringnullCraft Asset (uses its URL) or a URL string for the poster image
classnamestring''CSS class(es) for the video element
disablepictureinpictureboolfalseDisable Picture-in-Picture button
idstringrandomThe video element's ID (random if not provided)

Example:

{# Using a Craft Asset as poster #}
{% include '@streamingvideo/player.twig' with {
  asset: entry.video.one(),
  poster: entry.posterImage.one(),
  autoplay: true,
  muted: true,
  loop: false,
  playsinline: true,
  classname: 'rounded shadow',
  disablepictureinpicture: true,
  id: 'my-custom-video-player'
} %}

{# Using a URL as poster #}
{% include '@streamingvideo/player.twig' with {
  asset: entry.video.one(),
  poster: 'https://example.com/poster.jpg'
} %}

GraphQL

The plugin adds an hlsPlaylistUrl field to the Asset GraphQL type:

query {
  entries {
    ... on MySection {
      videoField {
        url
        hlsPlaylistUrl
        title
      }
    }
  }
}

The field will only be available once all variants have finished rendering. Until then, you can show a fallback or the original video.

Checking Stream Availability

{% set video = entry.video.one() %}
{% if video.canStreamVideo %}
    <p>This video supports streaming</p>
    {% if video.hlsPlaylistUrl %}
        <p>HLS streaming is available</p>
    {% else %}
        <p>HLS encoding in progress...</p>
    {% endif %}
{% endif %}

Configuration

Quality Variants

The plugin generates the following quality variants by default:

QualityResolutionVideo BitrateAudio Bitrate
1080p1920×10805000k128k
720p1280×7203000k128k
480p854×4801500k96k
240p~427×240800k64k
144p~256×144400k64k
SourceOriginal8000k192k

Note: Only variants with resolution ≤ source video are generated

Processing Existing Videos

If you're adding this plugin to an existing site with video assets, you'll need to resave all existing video assets to trigger HLS conversion:

# Standard Craft installation
php craft resave/assets

# Using DDEV
ddev craft resave/assets

This will process all existing video assets and generate HLS streaming variants in the background.

[!WARNING]
Depending on how many videos you have saved, and how long they are, this can take a long time and use a lot of hard drive space. Make sure to monitor your hard drive when resaving assets.

Troubleshooting

FFmpeg Not Found

Error: ffmpeg: not found

Solution: Install FFmpeg on your server (see Installation section above)

Permission Issues

Error: Failed to create temp directory

Solution: Ensure the web server has write permissions to Craft's temp directory

Large File Processing

For very large video files, you may need to:

  1. Increase PHP memory limit: ini_set('memory_limit', '1G')
  2. Increase max execution time: ini_set('max_execution_time', 0)
  3. Configure your queue system for long-running jobs

Debug Information

Check Craft's logs at storage/logs/queue.log for detailed processing information:

# Follow logs in real-time
tail -f storage/logs/* | grep streamingvideo

License

This plugin is licensed under the Craft License.

Support

For issues and feature requests, please use the GitHub issue tracker.

Standard

Plus $19/year after one year.

Installation Instructions

To install this plugin, copy the command above to your terminal.

Reviews

This plugin doesn't have any reviews.

Active Installs
0
Version
1.0.0
License
Craft
Compatibility
Craft 5
Last release
August 20, 2025
Activity (30 days)
0
Closed Issues
0
Open Issues
0
Merged PRs
0
Open PRs