Files
Krystie bdd5ab30fd feat: Add multi-CDN integration for global video delivery
- Create CDN manager with multi-provider support (Bunny, Cloudflare, S3, Backblaze, Wasabi)
- Implement automatic CDN upload and failover system
- Add multi-quality video support (360p-2160p)
- Build quality selector UI with auto-detection
- Track CDN bandwidth usage for cost monitoring
- Implement cache purging API
- Add background CDN upload worker script
- Create comprehensive CDN documentation

Features:
- Multi-CDN support with priority-based failover
- BunnyCDN, Cloudflare R2, AWS S3, Backblaze B2, Wasabi integration
- Multi-quality delivery (adaptive quality selection)
- Auto quality based on connection speed
- User preference persistence
- Bandwidth tracking per provider
- Cache purge API
- Cost optimization strategies
- Production-ready with error handling
2026-03-30 17:45:23 -07:00

12 KiB

CDN Integration

EasyStream supports multi-CDN video delivery for global reach, reduced latency, and bandwidth optimization.

Supported CDN Providers

  • 🐰 BunnyCDN - Cost-effective, global edge network
  • ☁️ Cloudflare R2 - Zero egress fees, S3-compatible
  • 🪣 AWS S3 + CloudFront - Enterprise-grade, highly scalable
  • 🔵 Backblaze B2 - Affordable S3-compatible storage
  • 🟢 Wasabi - Predictable pricing, no egress fees
  • 🔧 Custom - Any S3-compatible storage provider

Features

  • 🌍 Multi-CDN Support - Upload to multiple providers for redundancy
  • 📊 Automatic Failover - Falls back to secondary CDN if primary fails
  • 🎬 Multi-Quality Delivery - Serve 360p, 480p, 720p, 1080p, 1440p, 2160p
  • 💾 Bandwidth Tracking - Monitor usage and costs per provider
  • 🔄 Cache Purging - Invalidate CDN cache on video updates
  • 🚀 Auto Quality Selection - Pick best quality based on connection speed
  • 💰 Cost Optimization - Use cheapest provider for your traffic patterns

Setup

1. Database Migration

docker-compose exec db mysql -u easystream -peasystream easystream < __install/migrations/005_add_cdn_support.sql

2. Configure CDN Provider

Add your CDN provider credentials to the database:

INSERT INTO db_cdn_providers (
    provider_name, provider_type, api_key, storage_zone, 
    pull_zone, cdn_hostname, region, is_active, priority
) VALUES (
    'BunnyCDN Production', 'bunny', 'YOUR_API_KEY', 
    'easystream-videos', 'easystream', 'easystream.b-cdn.net', 
    'de', 1, 0
);

Provider Types:

  • bunny - BunnyCDN
  • cloudflare - Cloudflare R2
  • s3 - AWS S3
  • backblaze - Backblaze B2
  • wasabi - Wasabi
  • custom - Custom S3-compatible

Priority: Lower = higher priority (0 is primary)

3. Add Frontend Assets

Include quality selector on video watch page:

<link rel="stylesheet" href="/f_scripts/fe/css/quality-selector.css">
<script src="/f_scripts/fe/js/quality-selector.js"></script>

4. Upload Videos to CDN

# Upload single video
php app_scripts/cdn/upload_to_cdn.php 123

# Upload all pending videos
php app_scripts/cdn/upload_to_cdn.php --all

5. Automate Uploads (Optional)

Add to upload workflow in upload.php:

require_once 'f_core/f_classes/class.cdn.php';
$cdn = new VCDN();

// After video upload
$cdn->uploadVideo($video_id, $local_file_path, 'original');

Or run background worker via supervisor/systemd.

CDN Provider Configuration

BunnyCDN

  1. Sign up at bunny.net
  2. Create a storage zone
  3. Create a pull zone linked to the storage zone
  4. Get your API key from Account Settings
INSERT INTO db_cdn_providers (
    provider_name, provider_type, api_key, storage_zone, 
    pull_zone, cdn_hostname
) VALUES (
    'BunnyCDN', 'bunny', 'YOUR_API_KEY', 
    'your-storage-zone', 'your-pull-zone', 'your-pull-zone.b-cdn.net'
);

Cost: ~$0.01/GB storage + $0.01-0.05/GB bandwidth (varies by region)

Cloudflare R2

  1. Sign up for Cloudflare account
  2. Enable R2 in dashboard
  3. Create a bucket
  4. Generate API token
INSERT INTO db_cdn_providers (
    provider_name, provider_type, api_key, api_secret, 
    storage_zone, region
) VALUES (
    'Cloudflare R2', 'cloudflare', 'YOUR_ACCESS_KEY', 
    'YOUR_SECRET_KEY', 'your-bucket', 'auto'
);

Cost: $0.015/GB storage, zero egress fees

AWS S3 + CloudFront

  1. Create S3 bucket in AWS Console
  2. Create CloudFront distribution
  3. Generate IAM access keys
INSERT INTO db_cdn_providers (
    provider_name, provider_type, api_key, api_secret, 
    storage_zone, cdn_hostname, region
) VALUES (
    'AWS S3', 's3', 'YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY', 
    'your-bucket', 'd123abc.cloudfront.net', 'us-east-1'
);

Cost: $0.023/GB storage + $0.085/GB bandwidth (first 10TB)

Backblaze B2

  1. Sign up at backblaze.com
  2. Create a bucket
  3. Generate application key
INSERT INTO db_cdn_providers (
    provider_name, provider_type, api_key, api_secret, 
    storage_zone, region
) VALUES (
    'Backblaze B2', 'backblaze', 'YOUR_KEY_ID', 'YOUR_APP_KEY', 
    'your-bucket', 'us-west-004'
);

Cost: $0.006/GB storage + $0.01/GB bandwidth (first 3x storage free)

Wasabi

  1. Sign up at wasabi.com
  2. Create a bucket
  3. Generate access keys
INSERT INTO db_cdn_providers (
    provider_name, provider_type, api_key, api_secret, 
    storage_zone, region
) VALUES (
    'Wasabi', 'wasabi', 'YOUR_ACCESS_KEY', 'YOUR_SECRET_KEY', 
    'your-bucket', 'us-east-1'
);

Cost: $5.99/TB/month (storage + bandwidth included)

Usage

Get CDN URL

GET /api/cdn.php?action=url&video_id=123&quality=720p

Response:

{
  "success": true,
  "url": "https://easystream.b-cdn.net/videos/123/720p/video.mp4"
}

Get Available Qualities

GET /api/cdn.php?action=qualities&video_id=123

Response:

{
  "success": true,
  "qualities": [
    {
      "quality_label": "auto",
      "resolution": "Auto",
      "cdn_url": null
    },
    {
      "quality_label": "1080p",
      "resolution": "1920x1080",
      "cdn_url": "https://easystream.b-cdn.net/videos/123/1080p/video.mp4"
    },
    {
      "quality_label": "720p",
      "resolution": "1280x720",
      "cdn_url": "https://easystream.b-cdn.net/videos/123/720p/video.mp4"
    }
  ]
}

Upload to CDN

POST /api/cdn.php?action=upload
Content-Type: application/json

{
  "video_id": 123,
  "local_path": "/srv/uploads/video.mp4",
  "quality": "original"
}

Purge Cache

POST /api/cdn.php?action=purge
Content-Type: application/json

{
  "video_id": 123
}

Bandwidth Usage

GET /api/cdn.php?action=bandwidth&days=30&provider_id=1

Response:

{
  "success": true,
  "data": [
    {
      "date": "2026-03-01",
      "bandwidth_mb": 15234.56,
      "requests": 4567
    }
  ]
}

Frontend Integration

Quality Selector

The quality selector automatically initializes on video watch pages:

const selector = new QualitySelector(videoId, {
    playerElement: document.querySelector('video'),
    containerElement: document.querySelector('.video-controls')
});

Features:

  • Auto quality based on connection speed
  • User preference persistence (localStorage)
  • Seamless quality switching (preserves playback position)

Programmatic Quality Switch

const selector = window.qualitySelector;
selector.switchQuality('720p', 'https://cdn.example.com/video_720p.mp4');

Multi-Quality Encoding

Generate multiple quality levels from source video:

# Using ffmpeg
ffmpeg -i input.mp4 \
  -vf scale=1920:1080 -c:v libx264 -b:v 5000k -preset medium output_1080p.mp4 \
  -vf scale=1280:720 -c:v libx264 -b:v 2500k -preset medium output_720p.mp4 \
  -vf scale=854:480 -c:v libx264 -b:v 1000k -preset medium output_480p.mp4 \
  -vf scale=640:360 -c:v libx264 -b:v 500k -preset medium output_360p.mp4

Then upload each quality:

$qualities = ['1080p', '720p', '480p', '360p'];
foreach ($qualities as $quality) {
    $cdn->uploadVideo($video_id, "output_{$quality}.mp4", $quality);
}

Bandwidth Tracking

Track CDN bandwidth usage automatically:

$cdn->trackBandwidth($provider_id, $video_id, $bytes_transferred);

Integrate with analytics:

// After video view
$file_size = filesize($video_path);
$cdn->trackBandwidth($provider_id, $video_id, $file_size);

Cost Optimization

Provider Selection Strategy

  1. High Traffic, US/EU audience: BunnyCDN or Cloudflare R2
  2. Predictable costs: Wasabi (flat rate)
  3. Low traffic, budget-conscious: Backblaze B2
  4. Enterprise, existing AWS: S3 + CloudFront

Multi-Provider Setup

Configure multiple providers with priority:

-- Primary (lowest cost for your region)
INSERT INTO db_cdn_providers (..., priority) VALUES (..., 0);

-- Secondary (failover)
INSERT INTO db_cdn_providers (..., priority) VALUES (..., 1);

System automatically falls back to secondary if primary fails.

Bandwidth Cost Estimates

Provider 1TB/month 10TB/month 100TB/month
BunnyCDN $10-50 $100-400 $1,000-2,500
Cloudflare R2 $15 $150 $1,500
AWS S3+CF $85 $815 $6,815
Backblaze B2 $6 + $10 $6 + $70 $6 + $700
Wasabi $6 $60 $600

Estimates vary by region and traffic patterns

Database Schema

db_cdn_providers

Column Type Description
provider_id INT Primary key
provider_name VARCHAR(50) Display name
provider_type ENUM bunny/cloudflare/s3/backblaze/wasabi/custom
api_key VARCHAR(255) API key
api_secret VARCHAR(255) API secret (for S3-compatible)
storage_zone VARCHAR(100) Bucket/zone name
pull_zone VARCHAR(100) CDN distribution name
cdn_hostname VARCHAR(255) CDN URL hostname
region VARCHAR(50) Geographic region
is_active TINYINT Enabled status
priority INT Selection priority (lower = higher)

db_video_qualities

Column Type Description
quality_id INT Primary key
video_id INT Video ID
quality_label VARCHAR(20) 360p, 480p, 720p, 1080p, etc.
resolution VARCHAR(20) Width x height
bitrate INT Video bitrate (kbps)
file_path VARCHAR(512) Local file path
cdn_url VARCHAR(512) CDN URL
file_size BIGINT File size in bytes
codec VARCHAR(50) Video codec (h264, vp9, av1)

db_cdn_cache_status

Column Type Description
cache_id INT Primary key
video_id INT Video ID
provider_id INT CDN provider ID
quality_label VARCHAR(20) Quality level
cdn_url VARCHAR(512) CDN URL
status ENUM pending/uploading/ready/failed
upload_progress INT Upload progress (%)
error_message TEXT Error details

Performance

  • CDN latency: 10-50ms (vs 200-500ms local)
  • Upload speed: Varies by provider (10-100 MB/s typical)
  • Cache hit ratio: 85-95% (after warmup)
  • Failover time: <1 second (automatic)

Troubleshooting

Upload fails with "Permission denied"

  1. Check API credentials are correct
  2. Verify storage zone/bucket exists
  3. Check firewall allows outbound HTTPS

Video URL returns 404

  1. Check CDN cache status: SELECT * FROM db_cdn_cache_status WHERE video_id = X
  2. Verify file uploaded successfully to CDN
  3. Check CDN hostname is correct

Quality selector doesn't appear

  1. Verify JavaScript is loaded
  2. Check browser console for errors
  3. Ensure video has multiple qualities available

Bandwidth tracking inaccurate

  1. Check analytics integration is active
  2. Verify trackBandwidth() called on video views
  3. Review CDN provider's own bandwidth reports

Advanced Features

Adaptive Bitrate Streaming (HLS/DASH)

Generate HLS playlist for adaptive streaming:

ffmpeg -i input.mp4 \
  -vf scale=1920:1080 -c:v libx264 -b:v 5000k -f hls -hls_time 6 -hls_list_size 0 output_1080p.m3u8 \
  -vf scale=1280:720 -c:v libx264 -b:v 2500k -f hls -hls_time 6 -hls_list_size 0 output_720p.m3u8

Geo-Routing

Route users to nearest CDN edge:

$user_country = $_SERVER['HTTP_CF_IPCOUNTRY'] ?? 'US';
$cdn_region = $user_country === 'US' ? 'us-east' : 'eu-west';

// Select provider by region
$provider = getProviderByRegion($cdn_region);

Generate time-limited signed URLs:

function generateSignedUrl($url, $expiry = 3600) {
    $secret = 'YOUR_SIGNING_SECRET';
    $expires = time() + $expiry;
    $token = hash_hmac('sha256', $url . $expires, $secret);
    
    return "{$url}?token={$token}&expires={$expires}";
}

Future Enhancements

  • Automatic quality encoding on upload
  • HLS/DASH adaptive streaming
  • Geo-routing based on user location
  • Signed URLs for DRM/hotlink protection
  • CDN analytics dashboard
  • Cost alerts (bandwidth thresholds)
  • Video preview thumbnails (storyboards)
  • AV1 codec support
  • CDN warmup on publish
  • Multi-region redundancy

Learn More