Usage
The basic flow
Every job follows the same steps: open the input, add streams, choose the manifests, then export and save.
use Foxws\Shaka\Facades\Shaka;
$packager = Shaka::fromDisk('media')->open('videos/clip.mp4');
try {
$packager
->addVideoStream('videos/clip.mp4', 'video.mp4')
->addAudioStream('videos/clip.mp4', 'audio.mp4')
->withMpdOutput('index.mpd')
->withHlsMasterPlaylist('master.m3u8')
->export()
->toDisk('s3')
->toPath('streams/clip/')
->save();
} finally {
$packager->cleanupTemporaryFiles();
}
fromDisk()picks the disk to read from. Without it, your default filesystem disk is used.- The first argument of
addVideoStream()and friends is a path you passed toopen(). The second is the output file name. export()returns the exporter. Nothing runs until you callsave().save()runs Shaka Packager, copies the output to the target disk and deletes the local copy.cleanupTemporaryFiles()removes anything left behind, such as downloaded inputs or the output of a failed run. Always call it infinally, especially in queue workers.
Where the output goes
Shaka Packager writes to a local temporary directory first. save() then copies everything to the target disk:
toDisk()sets the target disk. Without it, the input disk is used.toPath()sets the folder on that disk. Without it, files land in the root of the disk.withVisibility('private')sets the visibility of the uploaded files.
S3 disks upload in parallel, and large files use multipart uploads. On a local disk, files are moved instead of copied. See Configuration to tune this.
DASH and HLS together
Streams are written as fragmented MP4 (CMAF), so one set of segments works for both DASH and HLS. Set both outputs and you get both manifests from a single run, with no extra segments:
->withMpdOutput('index.mpd')
->withHlsMasterPlaylist('master.m3u8')
Set only one of them if you only need one format.
Several qualities
Shaka Packager doesn't encode, so each quality has to exist as its own file. Encode the qualities first, open them all, and add a stream for each:
Shaka::fromDisk('media')
->open(['videos/clip-1080p.mp4', 'videos/clip-720p.mp4', 'videos/clip-480p.mp4'])
->addVideoStream('videos/clip-1080p.mp4', '1080p.mp4')
->addVideoStream('videos/clip-720p.mp4', '720p.mp4')
->addVideoStream('videos/clip-480p.mp4', '480p.mp4')
->addAudioStream('videos/clip-1080p.mp4', 'audio.mp4')
->withMpdOutput('index.mpd')
->withHlsMasterPlaylist('master.m3u8')
->export()
->save();
Adding the same input twice with a different bandwidth doesn't create a new quality. It writes the same stream twice with a different label.
Stream options
The third argument sets stream descriptor fields:
->addAudioStream('videos/clip.mp4', 'audio-nl.mp4', ['language' => 'nl', 'hls_name' => 'Nederlands'])
Only add streams that exist. A file without an audio track fails when you add an audio stream for it. Check with ffprobe or Laravel FFMpeg first if you're not sure.
Subtitles
Open the subtitle file along with the video, then add it as a text stream:
Shaka::fromDisk('media')
->open(['videos/clip.mp4', 'captions/clip.en.vtt'])
->addVideoStream('videos/clip.mp4', 'video.mp4')
->addAudioStream('videos/clip.mp4', 'audio.mp4')
->addTextStream('captions/clip.en.vtt', 'subtitles-en.mp4', ['language' => 'en', 'dash_roles' => 'subtitle'])
->withMpdOutput('index.mpd')
->withHlsMasterPlaylist('master.m3u8')
->export()
->save();
Use an .mp4 output for subtitles rather than .vtt. With a plain .vtt output, the DASH manifest has no segment index, and Shaka Player skips the track.
A path that you didn't open is passed to Shaka Packager as-is, so it must be an absolute local path.
Manifest options
The most common ones:
use Foxws\Shaka\Support\HlsPlaylistType;
->withSegmentDuration(6)
->withHlsPlaylistType(HlsPlaylistType::Vod)
->withDefaultLanguage('en')
->withDefaultTextLanguage('en')
->withAllowCodecSwitching()
Any other Shaka Packager flag can be set with withOption():
->withOption('generate_static_live_mpd', true)
See the Quick Reference for the full list.
After saving
afterSaving() runs after the files are on the target disk:
->export()
->toDisk('s3')
->afterSaving(fn ($exporter, $result) => $video->markAsReady())
->save();
Errors
Foxws\Shaka\Exceptions\RuntimeExceptionmeans Shaka Packager itself failed. The message includes its error output.RuntimeExceptionfromsave()means some files couldn't be copied to the target disk. The message lists them.Foxws\Shaka\Exceptions\InsufficientStorageExceptionmeans a storage guard stopped the job before it started. See Configuration.
Events
| Event | Properties |
|---|---|
Foxws\Shaka\Events\PackagingStarted |
$mediaCollection, $options |
Foxws\Shaka\Events\PackagingCompleted |
$result, $executionTime |
Foxws\Shaka\Events\PackagingFailed |
$exception, $executionTime, $context |
Debugging
See the command without running it:
$command = Shaka::open('videos/clip.mp4')
->addVideoStream('videos/clip.mp4', 'video.mp4')
->withMpdOutput('index.mpd')
->getCommand();
Or call ->export()->dd() to dump it and stop.
