Video overview
How Mantis stores and streams video as HLS, what it does for you and what it leaves to you.
Mantis streams video the way Netflix and YouTube do: as HLS, a master playlist that points at the same video in several sizes, each cut into short segments. The player picks the size the connection can carry and switches as it changes, so a phone on a train and a laptop on fibre both start fast and keep playing.
Mantis does not transcode on its servers. Your own ffmpeg makes the package, on your
machine, in CI or on a worker, and Mantis stores it in a folder and serves it. That keeps the
cost of a video at the cost of its bytes, and keeps your source files with you.
intro.mp4
│ ffmpeg, on your machine or server
▼
./out/intro/ master.m3u8, poster.jpg, and per size
│ 1080p/ 720p/ 480p/ 360p/ a playlist and 6-second segments
│ upload
▼
videos/<id>/ a folder in your schema
│ a public link, or a signed playback link
▼
the player Safari's <video>, or hls.js everywhere elseThe three steps
Declare a folder
import { defineSchema, fileRule, t, table } from "@shipmantis/sdk";
export default defineSchema(
{
lessons: table({ title: t.text(), video: t.text().optional() }),
},
{
storage: {
videos: {
maxBytes: 1024 * 1024 * 1024,
types: ["video/*", "application/vnd.apple.mpegurl", "image/jpeg"],
rules: { read: fileRule.public() },
},
},
},
);'storage' => [
'videos' => [
'maxBytes' => 1024 * 1024 * 1024,
'types' => ['video/*', 'application/vnd.apple.mpegurl', 'image/jpeg'],
'rules' => ['read' => ['public' => true]],
],
],Push it with php artisan mantis:push, or Mantis::storage()->declare('videos', 1024 * 1024 * 1024)
for a folder only your server reads.
Or press New folder on the project's Files page and pick Videos: it takes exactly these types, up to 1 GB a file.
Upload a video
npx shipmantis video intro.mp4 --folder videosIt transcodes with your ffmpeg, uploads the package and prints the video's id, like
videos/0b6c…. See Upload videos for the SDK, your own packages and big
batches.
Play it
<video src={video.publicUrl} poster={video.posterUrl} controls playsInline /><x-video-player :src="$lesson->videoUrl" />With the player component, and a link built from the video's id.
That plays in Safari; everywhere else, attach the link with hls.js. Folders that aren't public hand out signed playback links instead.
What a package holds
| File | Path | Content type |
|---|---|---|
| Master playlist | videos/<id>/master.m3u8 | application/vnd.apple.mpegurl |
| One playlist per size | videos/<id>/720p/index.m3u8 | application/vnd.apple.mpegurl |
| Six-second segments | videos/<id>/720p/seg_00000.ts | video/mp2t |
| Poster, the frame at one second | videos/<id>/poster.jpg | image/jpeg |
The video's id is its folder and its name, videos/<id>. Store that id in your table, not
the URL: a public link is built from it, and a signed one is asked for with it.
The ladder
| Size | Short side | Video | Audio |
|---|---|---|---|
| 1080p | 1080 px | 5 Mbit/s | 128 kbit/s |
| 720p | 720 px | 2.8 Mbit/s | 128 kbit/s |
| 480p | 480 px | 1.4 Mbit/s | 96 kbit/s |
| 360p | 360 px | 0.8 Mbit/s | 96 kbit/s |
H.264 (main profile) with stereo AAC at 48 kHz, a keyframe every two seconds and a segment every six. Sizes are measured on the short side, so a portrait phone video at 1080×1920 gets the 1080p rung at 1080 px wide. A source is not scaled up past its own size: a 720p source gets 720p, 480p and 360p. The one exception is a source smaller than 360p, which gets a single 360p rung.
How big, how many files
All four sizes together come to about 10.5 Mbit/s, or roughly 80 MB per minute of a 1080p source; a 720p source is about 40 MB a minute. Each minute adds ten segments per size, so a ten-minute 1080p video is about 400 files and 800 MB.
Every playlist and segment counts against the plan like any other file:
| Plan | Uploads | About this much 1080p video |
|---|---|---|
| Free | 5 GB | an hour |
| Pro | 200 GB, then billed by the GB | forty hours, then more |
A segment is a few megabytes, far below any plan's largest file, so length is limited only by the room on the plan.
Public or signed
| Public folder | Any other folder | |
|---|---|---|
| Link | publicUrl, lasting | playbackUrl(id), 1 second to 24 hours |
| Cached at the edge | Yes, an hour | Segments yes, until their six-hour window ends; playlists never |
| Who can watch | Anyone with the link | Anyone with the link until it expires, or one signed-in user |
| Good for | Marketing videos, free lessons, previews | Paid courses, private uploads, anything per user |
In the dashboard
The Files page shows each video as one row: its poster, its name, how many files it holds and its size. A video whose master playlist hasn't arrived yet says no master playlist yet; that is an upload still running or one that stopped halfway. Open the row for the video's own page, which lists every file grouped by size, largest first, 500 files a page.
What Mantis does not do
- Transcode on its servers. Run
ffmpegwhere you upload from. A worker recipe shows the usual setup for user uploads. - DRM or encrypted segments. A package with a
.keyfile is refused: a key in a folder would be served to anyone who can read the segments. Use locked playback links to control who watches. - Live streaming. Packages are video on demand (
#EXT-X-PLAYLIST-TYPE:VOD).
Next: Upload videos · Play videos · Recipes