MantisDocs

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 else

The three steps

Declare a folder

mantis/schema.ts
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() },
      },
    },
  },
);
database/mantis.php
'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 videos

It 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

FilePathContent type
Master playlistvideos/<id>/master.m3u8application/vnd.apple.mpegurl
One playlist per sizevideos/<id>/720p/index.m3u8application/vnd.apple.mpegurl
Six-second segmentsvideos/<id>/720p/seg_00000.tsvideo/mp2t
Poster, the frame at one secondvideos/<id>/poster.jpgimage/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

SizeShort sideVideoAudio
1080p1080 px5 Mbit/s128 kbit/s
720p720 px2.8 Mbit/s128 kbit/s
480p480 px1.4 Mbit/s96 kbit/s
360p360 px0.8 Mbit/s96 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:

PlanUploadsAbout this much 1080p video
Free5 GBan hour
Pro200 GB, then billed by the GBforty 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 folderAny other folder
LinkpublicUrl, lastingplaybackUrl(id), 1 second to 24 hours
Cached at the edgeYes, an hourSegments yes, until their six-hour window ends; playlists never
Who can watchAnyone with the linkAnyone with the link until it expires, or one signed-in user
Good forMarketing videos, free lessons, previewsPaid 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 ffmpeg where you upload from. A worker recipe shows the usual setup for user uploads.
  • DRM or encrypted segments. A package with a .key file 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

On this page