Sources API
Movi-Player provides different source adapters for various input types.
Available Sources
| Source | Use Case | Import |
|---|---|---|
HttpSource | Remote URLs | movi-player/demuxer |
FileSource | Local files | movi-player/demuxer |
HttpSource
For loading videos from HTTP/HTTPS URLs.
Basic Usage
typescript
import { Demuxer, HttpSource } from "movi-player/demuxer";
const source = new HttpSource("https://example.com/video.mp4");
const demuxer = new Demuxer(source);
await demuxer.open();
console.log("Duration:", demuxer.getDuration());With Player
typescript
import { MoviPlayer } from "movi-player/player";
const player = new MoviPlayer({
source: { type: "url", url: "https://example.com/video.mp4" },
canvas: document.getElementById("canvas") as HTMLCanvasElement,
});
await player.load();HttpSource is created internally — there's no public path for passing a pre-built source instance to MoviPlayer. Use HttpSource directly with Demuxer only when extracting metadata without playing.
CORS Requirements
CORS
HttpSource requires the server to send proper CORS headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD
Access-Control-Expose-Headers: Content-Length, Content-RangeFeatures
- ✅ Range request support (seeking)
- ✅ Automatic chunk caching
- ✅ HEAD request for file size
- ✅ Error recovery
FileSource
For loading local files from the user's device.
Basic Usage
typescript
import { Demuxer, FileSource } from "movi-player/demuxer";
const fileInput = document.getElementById("file") as HTMLInputElement;
fileInput.addEventListener("change", async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) return;
const source = new FileSource(file);
const demuxer = new Demuxer(source);
await demuxer.open();
console.log("File:", file.name);
console.log("Duration:", demuxer.getDuration());
});With Player
typescript
import { MoviPlayer } from "movi-player/player";
fileInput.addEventListener("change", async (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) return;
const player = new MoviPlayer({
source: { type: "file", file },
canvas: document.getElementById("canvas") as HTMLCanvasElement,
});
await player.load();
await player.play();
});Features
- ✅ No CORS needed
- ✅ Instant seeking (no network latency)
- ✅ LRU cache for chunks
- ✅ Memory efficient (2MB chunks)
- ✅ Works offline
Memory Management
FileSource uses intelligent chunking:
typescript
// Internal configuration
const CHUNK_SIZE = 2 * 1024 * 1024; // 2MB chunks
const MAX_CACHED_CHUNKS = 50; // ~100MB max cache
// LRU cache evicts least recently used chunks
// when cache is fullSource Interface
All sources implement the SourceAdapter interface:
typescript
interface SourceAdapter {
// Get total file size
getSize(): Promise<number>;
// Read bytes from offset
read(offset: number, length: number): Promise<Uint8Array>;
// Close and cleanup
close(): void;
}Creating Custom Sources
You can create custom sources:
typescript
import type { SourceAdapter } from "movi-player/demuxer";
class CustomSource implements SourceAdapter {
private data: Uint8Array;
constructor(data: Uint8Array) {
this.data = data;
}
async getSize(): Promise<number> {
return this.data.byteLength;
}
async read(offset: number, length: number): Promise<Uint8Array> {
return this.data.slice(offset, offset + length);
}
close(): void {
// Cleanup
}
}
// Usage
const customSource = new CustomSource(videoData);
const demuxer = new Demuxer(customSource);Source Selection
SourceConfig requires an explicit type discriminant — the player picks the right adapter from it:
typescript
// HTTP URL → HttpSource
await player.load({ type: "url", url: "https://example.com/video.mp4" });
// Local File → FileSource
await player.load({ type: "file", file: selectedFile });
// Encrypted endpoint → EncryptedHttpSource
await player.load({
type: "encrypted",
encrypted: {
videoUrl: "/api/video",
tokenUrl: "/api/token",
videoId: "movie.mp4",
fingerprint: await generateFingerprint(),
sessionToken: jwt,
},
});Error Handling
HttpSource Errors
typescript
try {
const source = new HttpSource(url);
const demuxer = new Demuxer(source);
await demuxer.open();
} catch (error) {
if (error.message.includes("CORS")) {
console.error("CORS error: Server must allow cross-origin requests");
} else if (error.message.includes("404")) {
console.error("File not found");
} else if (error.message.includes("network")) {
console.error("Network error");
}
}FileSource Errors
typescript
try {
const source = new FileSource(file);
const demuxer = new Demuxer(source);
await demuxer.open();
} catch (error) {
if (error.message.includes("format")) {
console.error("Unsupported file format");
} else if (error.message.includes("corrupt")) {
console.error("File may be corrupted");
}
}Performance Comparison
| Metric | HttpSource | FileSource |
|---|---|---|
| Initial load | Network dependent | Instant |
| Seeking | ~100-500ms | <10ms |
| Memory | ~200MB | ~100-400MB |
| Offline | ❌ | ✅ |
| CORS | Required | Not needed |