foxws/laravel-streamer

A Laravel package to interact with Shaka Streamer for media packaging.

Fund package maintenance!
Foxws

Installs: 277

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 1

pkg:composer/foxws/laravel-streamer

0.2.0 2026-02-06 17:33 UTC

This package is auto-updated.

Last update: 2026-02-12 08:14:35 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A Laravel integration for Google's Shaka Streamer, enabling you to package adaptive streaming content (HLS, DASH) with a fluent, Laravel-style API.

use Foxws\Streamer\Facades\Streamer;

Streamer::fromDisk('s3')
    ->open('videos/input.mp4')
    ->addVideoStream('videos/input.mp4', 'video.mp4')
    ->addAudioStream('videos/input.mp4', 'audio.mp4')
    ->withHlsMasterPlaylist('master.m3u8')
    ->withSegmentDuration(6)
    ->export()
    ->toDisk('export')
    ->save();

Features

  • 🎬 Fluent API — Laravel-style chainable methods for packaging media
  • 📁 Filesystem Integration — Read from and write to any Laravel disk (local, S3, etc.)
  • 🎯 Adaptive Bitrate — Create multi-quality HLS & DASH streams
  • 🔒 AES Encryption — Built-in content protection with optional key rotation
  • 📺 Dynamic Manifests — Rewrite HLS playlists and DASH MPDs with signed URLs at serve-time
  • 📡 Events — Hooks for StreamingStarted, StreamingCompleted, and StreamingFailed
  • 📝 PHP 8.3+ — Strict types, readonly properties, and modern PHP throughout

Documentation

Requirements

  • PHP 8.3+
  • Laravel 11 or 12
  • Shaka Streamer binary (pip install shaka-streamer)

Installation

composer require foxws/laravel-streamer

Publish the configuration file:

php artisan vendor:publish --tag="streamer-config"

Verify the binary is accessible:

php artisan streamer:info

Quick Start

Basic Packaging

use Foxws\Streamer\Facades\Streamer;

Streamer::open('input.mp4')
    ->addVideoStream('input.mp4', 'video.mp4')
    ->addAudioStream('input.mp4', 'audio.mp4')
    ->withHlsMasterPlaylist('master.m3u8')
    ->export()
    ->save();

Cross-Disk Workflows

Read from one disk, write to another:

Streamer::fromDisk('s3')
    ->open('videos/input.mp4')
    ->addVideoStream('videos/input.mp4', 'video.mp4')
    ->addAudioStream('videos/input.mp4', 'audio.mp4')
    ->withHlsMasterPlaylist('master.m3u8')
    ->export()
    ->toDisk('export')
    ->toPath('streams/')
    ->withVisibility('public')
    ->save();

Encryption

// AES-128 encryption with auto-generated key
Streamer::open('input.mp4')
    ->addVideoStream('input.mp4', 'video.mp4')
    ->addAudioStream('input.mp4', 'audio.mp4')
    ->withHlsMasterPlaylist('master.m3u8')
    ->withAESEncryption()
    ->export()
    ->save();

// With key rotation (rotates every 60 seconds)
Streamer::open('input.mp4')
    ->addVideoStream('input.mp4', 'video.mp4')
    ->addAudioStream('input.mp4', 'audio.mp4')
    ->withHlsMasterPlaylist('master.m3u8')
    ->withAESEncryption('key', 'cenc')
    ->withKeyRotationDuration(60)
    ->export()
    ->toDisk('s3')
    ->save();

See the AES Encryption Guide for protection schemes, codec-specific examples, and key management.

Dynamic URL Resolvers

Serve HLS and DASH content with signed URLs — useful for S3, CDNs, or multi-tenant apps.

HLS:

use Foxws\Streamer\Http\DynamicHLSPlaylist;
use Illuminate\Support\Facades\Storage;

return (new DynamicHLSPlaylist('s3'))
    ->open("videos/{$video->id}/master.m3u8")
    ->setKeyUrlResolver(fn (string $key) => Storage::disk('s3')->temporaryUrl(
        "videos/{$video->id}/{$key}",
        now()->addHour(),
    ))
    ->setMediaUrlResolver(fn (string $file) => Storage::disk('s3')->temporaryUrl(
        "videos/{$video->id}/{$file}",
        now()->addHours(2),
    ))
    ->setPlaylistUrlResolver(fn (string $playlist) => route('video.playlist', [
        'video' => $video,
        'playlist' => $playlist,
    ]))
    ->toResponse(request());

DASH:

use Foxws\Streamer\Http\DynamicDASHManifest;
use Illuminate\Support\Facades\Storage;

return (new DynamicDASHManifest('s3'))
    ->open("videos/{$video->id}/manifest.mpd")
    ->setMediaUrlResolver(fn (string $file) => Storage::disk('s3')->temporaryUrl(
        "videos/{$video->id}/{$file}",
        now()->addHours(2),
    ))
    ->setInitUrlResolver(fn (string $file) => Storage::disk('s3')->temporaryUrl(
        "videos/{$video->id}/{$file}",
        now()->addHours(2),
    ))
    ->toResponse(request());

See URL Resolvers for more details.

Events

Listen to streaming lifecycle events:

Event Payload
StreamingStarted MediaCollection $mediaCollection, array $options
StreamingCompleted StreamerResult $result, float $executionTime
StreamingFailed Exception $exception, float $executionTime

Post-Export Inspection

After saving, you can inspect the result:

$exporter = Streamer::open('input.mp4')
    ->addVideoStream('input.mp4', 'video.mp4')
    ->addAudioStream('input.mp4', 'audio.mp4')
    ->withHlsMasterPlaylist('master.m3u8')
    ->export();

$exporter->afterSaving(function ($exporter, $result) {
    $summary = $exporter->getCopySummary();
    // ['total' => 12, 'copied' => 12, 'failed' => 0, 'totalSize' => 8421376]

    $keys = $result->getUploadedEncryptionKeys();
});

$exporter->toDisk('s3')->save();

API Reference

Streamer Facade → MediaOpener

Method Description
fromDisk($disk) Set the source filesystem disk
open($paths) Open one or more media files
openFromDisk($disk, $paths) Set disk and open files in one call
get() Get the MediaCollection
export() Start the export chain (returns MediaExporter)
dynamicHLSPlaylist(?string $disk) Create a DynamicHLSPlaylist instance
dynamicDASHManifest(?string $disk) Create a DynamicDASHManifest instance
cleanupTemporaryFiles() Delete all temporary directories

Stream Configuration (via MediaOpenerStreamer)

Method Description
addVideoStream($input, $output, $options) Add a video stream
addAudioStream($input, $output, $options) Add an audio stream
addTextStream($input, $output, $options) Add a text/subtitle stream
addStream(array $stream) Add a raw Shaka stream descriptor (in, stream, output, …)
withHlsMasterPlaylist($path) Set HLS output
withMpdOutput($path) Set DASH/MPD output
withSegmentDuration(int $seconds) Set segment duration
withManifestFormat(array $formats) Set manifest formats (e.g. ['dash', 'hls'])
withResolutions(array $resolutions) Set encoding resolutions
withVideoCodecs(array $codecs) Set video codecs (e.g. ['h264', 'hw:vp9'])
withAudioCodecs(array $codecs) Set audio codecs (e.g. ['aac', 'opus'])
withSegmentPerFile(bool $enabled) Enable segment-per-file output
withLowLatencyDashMode(bool $enabled) Enable low-latency DASH
withStreamingMode(string $mode) Set mode ('vod' or 'live')
withEncryption(array $config) Set raw encryption config
withAESEncryption($keyFilename, $scheme, $label) Auto-generate AES encryption key
withKeyRotationDuration(int $seconds) Enable key rotation (requires 'cenc' or 'cbcs')
withOption($key, $value) Set a custom pipeline option
withOptions(array $options) Set multiple custom pipeline options
getCommand() Get the built config array (for debugging)

MediaExporter (returned by export())

Method Description
toDisk($disk) Set target disk for output
toPath(string $path) Set target subdirectory
withVisibility(string $visibility) Set file visibility ('public', 'private')
afterSaving(callable $callback) Register post-save callback
save(?string $path) Execute packaging and copy files to disk
getCommand() Get the built config array
dd() Dump config and die
getCopySummary() Get {total, copied, failed, totalSize}
getCopiedFiles() Get array of successfully copied files
getFailedFiles() Get array of failed file copies
hasCopyFailures() Check if any files failed to copy

DynamicHLSPlaylist

Method Description
open(string $path) Open a playlist file
setKeyUrlResolver(callable) Resolve encryption key URLs
setMediaUrlResolver(callable) Resolve media segment URLs
setPlaylistUrlResolver(callable) Resolve sub-playlist URLs
get() Get processed playlist content
all() Get all processed playlists (master + variants)
toResponse($request) Return as application/vnd.apple.mpegurl response

DynamicDASHManifest

Method Description
open(string $path) Open a manifest file
setMediaUrlResolver(callable) Resolve media segment URLs
setInitUrlResolver(callable) Resolve initialization segment URLs
get() Get processed manifest content
toResponse($request) Return as application/dash+xml response

Configuration

Key options in config/streamer.php:

Option Default Description
streamer.streamer_binary 'shaka-streamer' Path to the Shaka Streamer binary
timeout 14400 (4h) Process timeout in seconds
temporary_files_root storage_path('app/streamer/temp') Directory for temporary files
cache_files_root '/dev/shm' Fast storage for small files (keys, manifests)
log_channel null Log channel for streamer output

See Configuration for all options and environment variables.

Testing

composer test

Contributing

Please see CONTRIBUTING for details.

Security

If you discover a security vulnerability, please report it via a private channel (e.g. email or GitHub Security Advisories) rather than publicly disclosing it.

Acknowledgments

This package was inspired by and learned from:

License

The MIT License (MIT). Please see License File for more information.