Mediakit -> Mediabunny

This commit is contained in:
Vanilagy
2025-06-16 15:46:44 +02:00
parent 05881ff1f5
commit 99f813c938
27 changed files with 126 additions and 126 deletions

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

+1 -1
View File
@@ -3,7 +3,7 @@ import footnote from 'markdown-it-footnote';
// https://vitepress.dev/reference/site-config
export default withMermaid({
title: 'Mediakit',
title: 'Mediabunny',
description: 'A VitePress Site',
cleanUrls: true,
themeConfig: {
+2 -2
View File
@@ -4,7 +4,7 @@ title: Examples
hero:
text: Examples
tagline: Demos showcasing various features of Mediakit
tagline: Demos showcasing various features of Mediabunny
features:
- title: Metadata extraction
@@ -16,7 +16,7 @@ features:
link: /examples/thumbnail-generation
target: _self
- title: Media player (advanced)
details: "A full video & audio media player, implemented from scratch with Mediakit, with microsecond playback accuracy."
details: "A full video & audio media player, implemented from scratch with Mediabunny, with microsecond playback accuracy."
link: /examples/media-player
target: _self
- title: File compression
+4 -4
View File
@@ -1,6 +1,6 @@
# Converting media files
The [reading](./reading-media-files) and [writing](./writing-media-files) primitives in Mediakit provide everything you need to convert media files. However, since this is such a common operation and the details can be tricky, Mediakit ships with a built-in file conversion abstraction.
The [reading](./reading-media-files) and [writing](./writing-media-files) primitives in Mediabunny provide everything you need to convert media files. However, since this is such a common operation and the details can be tricky, Mediabunny ships with a built-in file conversion abstraction.
It has the following features:
@@ -30,7 +30,7 @@ import {
WebMOutputFormat,
BufferTarget,
Conversion,
} from 'mediakit';
} from 'mediabunny';
const input = new Input({ ... });
const output = new Output({
@@ -189,9 +189,9 @@ If you want to get rid of the audio track, use `discard: true`.
### Resampling audio
The `numberOfChannels` property controls the channel count of the output audio (e.g., 1 for mono, 2 for stereo). If this value differs from the number of channels in the input track, Mediakit will perform up/downmixing of the channel data using [the same algorithm as the Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Basic_concepts_behind_Web_Audio_API#audio_channels).
The `numberOfChannels` property controls the channel count of the output audio (e.g., 1 for mono, 2 for stereo). If this value differs from the number of channels in the input track, Mediabunny will perform up/downmixing of the channel data using [the same algorithm as the Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Basic_concepts_behind_Web_Audio_API#audio_channels).
The `sampleRate` property controls the sample rate in Hz (e.g., 44100, 48000). If this value differs from the input track's sample rate, Mediakit will resample the audio.
The `sampleRate` property controls the sample rate in Hz (e.g., 44100, 48000). If this value differs from the input track's sample rate, Mediabunny will resample the audio.
### Transcoding audio
+7 -7
View File
@@ -1,6 +1,6 @@
# Input formats
Mediakit supports a wide variety of commonly used container formats for reading input files. These *input formats* are used in two ways:
Mediabunny supports a wide variety of commonly used container formats for reading input files. These *input formats* are used in two ways:
- When creating an `Input`, they are used to specify the list of supported container formats. See [Creating a new input](./reading-media-files#creating-a-new-input) for more.
- Given an existing `Input`, its `getFormat` method returns the *actual* format of the file as an `InputFormat`.
@@ -30,12 +30,12 @@ import {
MP3, // MP3 input format singleton
WAVE, // WAVE input format singleton
OGG, // Ogg input format singleton
} from 'mediakit';
} from 'mediabunny';
```
You can use these singletons when creating an input:
```ts
import { Input, MP3, WAVE, OGG } from 'mediakit';
import { Input, MP3, WAVE, OGG } from 'mediabunny';
const input = new Input({
formats: [MP3, WAVE, OGG],
@@ -45,14 +45,14 @@ const input = new Input({
You can also use them for checking the actual format of an `Input`:
```ts
import { MP3 } from 'mediakit';
import { MP3 } from 'mediabunny';
const isMp3 = input.getFormat() === MP3;
```
There is a special `ALL_FORMATS` constant exported by Mediakit which contains every input format singleton. Use this constant if you want to support as many formats as possible:
There is a special `ALL_FORMATS` constant exported by Mediabunny which contains every input format singleton. Use this constant if you want to support as many formats as possible:
```ts
import { Input, ALL_FORMATS } from 'mediakit';
import { Input, ALL_FORMATS } from 'mediabunny';
const input = new Input({
formats: ALL_FORMATS,
@@ -79,7 +79,7 @@ In addition to singletons, input format classes are structured hierarchically:
This means you can also perform input format checks using `instanceof` instead of `===` comparisons. For example:
```ts
import { Mp3InputFormat } from 'mediakit';
import { Mp3InputFormat } from 'mediabunny';
// Check if the file is MP3:
input.getFormat() instanceof Mp3InputFormat;
+8 -8
View File
@@ -1,31 +1,31 @@
# Introduction
Install Mediakit using your favorite package manager:
Install Mediabunny using your favorite package manager:
::: code-group
```bash [npm]
npm install mediakit
npm install mediabunny
```
```bash [yarn]
yarn add mediakit
yarn add mediabunny
```
```bash [pnpm]
pnpm add mediakit
pnpm add mediabunny
```
```bash [bun]
bun add mediakit
bun add mediabunny
```
:::
Both ESM and CommonJS are supported:
```ts
import * as Mediakit from 'mediakit';
const Mediakit = require('mediakit');
import * as Mediabunny from 'mediabunny';
const Mediabunny = require('mediabunny');
```
Alternativly, you can simply include the library using a script tag in your HTML:
```html
<script src="path/to/mediakit.js"></script>
<script src="path/to/mediabunny.js"></script>
```
You can download the built distribution file from the [releases page](https://github.com/Vanilagy/mp4-muxer/releases).
+5 -5
View File
@@ -82,7 +82,7 @@ This sink can be used to extract raw, [encoded packets](./packets-and-samples#en
Start by constructing the sink from any `InputTrack`:
```ts
import { EncodedPacketSink } from 'mediakit';
import { EncodedPacketSink } from 'mediabunny';
const sink = new EncodedPacketSink(track);
```
@@ -169,7 +169,7 @@ All operations of this sink use [presentation order](#decode-vs-presentation-ord
Create the sink like so:
```ts
import { VideoSampleSink } from 'mediakit';
import { VideoSampleSink } from 'mediabunny';
const sink = new VideoSampleSink(videoTrack);
```
@@ -296,7 +296,7 @@ This sink yields `HTMLCanvasElement` whenever possible, and falls back to `Offsc
Create the sink like so:
```ts
import { CanvasSink } from 'mediakit';
import { CanvasSink } from 'mediabunny';
const sink = new CanvasSink(videoTrack, options);
```
@@ -414,7 +414,7 @@ Use this sink to extract decoded [audio samples](./packets-and-samples#audiosamp
Create the sink like so:
```ts
import { AudioSampleSink } from 'mediakit';
import { AudioSampleSink } from 'mediabunny';
const sink = new AudioSampleSink(audioTrack);
```
@@ -457,7 +457,7 @@ While `AudioSampleSink` extracts raw decoded audio samples, you can use `AudioBu
Create the sink like so:
```ts
import { AudioBufferSink } from 'mediakit';
import { AudioBufferSink } from 'mediabunny';
const sink = new AudioBufferSink(audioTrack);
```
+13 -13
View File
@@ -98,7 +98,7 @@ type AudioEncodingConfig = {
### Subjective qualities
Mediakit provides five subjective quality options as an alternative to manually providing a bitrate. From a subjective quality, a bitrate will be calculated internally based on the codec and track information (width, height, sample rate, ...).
Mediabunny provides five subjective quality options as an alternative to manually providing a bitrate. From a subjective quality, a bitrate will be calculated internally based on the codec and track information (width, height, sample rate, ...).
```ts
import {
@@ -107,7 +107,7 @@ import {
QUALITY_MEDIUM,
QUALITY_HIGH,
QUALITY_VERY_HIGH,
} from 'mediakit';
} from 'mediabunny';
```
## Video sources
@@ -119,7 +119,7 @@ Video sources feed data to video tracks on an `Output`. They all extend the abst
This source takes [video samples](./packets-and-samples#videosample), encodes them, and passes the encoded data to the output.
```ts
import { VideoSampleSource } from 'mediakit';
import { VideoSampleSource } from 'mediabunny';
const sampleSource = new VideoSampleSource({
codec: 'avc',
@@ -137,7 +137,7 @@ await sampleSource.add(videoSample, { keyFrame: true });
This source simplifies a common pattern: A single canvas is repeatedly updated in a render loop and each frame is added to the output file.
```ts
import { CanvasSource, QUALITY_MEDIUM } from 'mediakit';
import { CanvasSource, QUALITY_MEDIUM } from 'mediabunny';
const canvasSource = new CanvasSource(canvasElement, {
codec: 'av1',
@@ -157,7 +157,7 @@ await canvasSource.add(0.3, 0.1, { keyFrame: true });
This is a source for use with the [Media Capture and Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API). Use this source if you want to pipe a real-time video source (such as a webcam or screen recording) to an output file.
```ts
import { MediaStreamVideoTrackSource } from 'mediakit';
import { MediaStreamVideoTrackSource } from 'mediabunny';
// Get the user's screen
const stream = await navigator.mediaDevices.getDisplayMedia({ video: true });
@@ -180,7 +180,7 @@ If this source is the only MediaStreamTrack source in the `Output`, then the fir
The most barebones of all video sources, this source can be used to directly pipe [encoded packets](./packets-and-samples#encodedpacket) of video data to the output. This source requires that you take care of the encoding process yourself, which enables you to use the WebCodecs API manually or to plug in your own encoding stack. Alternatively, you may retrieve the encoded packets directly by reading them from another media file, allowing you to skip decoding and reencoding video data.
```ts
import { EncodedVideoPacketSource } from 'mediakit';
import { EncodedVideoPacketSource } from 'mediabunny';
// You must specify the codec name:
const packetSource = new EncodedVideoPacketSource('vp9');
@@ -224,7 +224,7 @@ The decode order for these frames will be:
```md
Frame 1 -> Frame 3 -> Frame 2
```
Some file formats have an explicit notion of both a "decode timestamp" and a "presentation timestamp" to model B-frames or out-of-order decoding. However, Mediakit packets only specify their *presentation timestamp*. Decode order is determined by the order in which you add the packets, so in our example, you must add the packets like this:
Some file formats have an explicit notion of both a "decode timestamp" and a "presentation timestamp" to model B-frames or out-of-order decoding. However, Mediabunny packets only specify their *presentation timestamp*. Decode order is determined by the order in which you add the packets, so in our example, you must add the packets like this:
```ts
await packetSource.add(packetForFrame1); // 0.0s
await packetSource.add(packetForFrame3); // 0.2s
@@ -274,7 +274,7 @@ Audio sources feed data to audio tracks on an `Output`. They all extend the abst
This source takes [audio samples](./packets-and-samples#audiosample), encodes them, and passes the encoded data to the output.
```ts
import { AudioSampleSource } from 'mediakit';
import { AudioSampleSource } from 'mediabunny';
const sampleSource = new AudioSampleSource({
codec: 'aac',
@@ -289,7 +289,7 @@ await sampleSource.add(audioSample);
This source directly accepts instances of `AudioBuffer` as data, simplifying usage with the Web Audio API. The first AudioBuffer will be played at timestamp 0, and any subsequent AudioBuffer will be appended after all previous AudioBuffers.
```ts
import { AudioBufferSource, QUALITY_MEDIUM } from 'mediakit';
import { AudioBufferSource, QUALITY_MEDIUM } from 'mediabunny';
const bufferSource = new AudioBufferSource({
codec: 'opus',
@@ -306,7 +306,7 @@ await bufferSource.add(audioBuffer3);
This is a source for use with the [Media Capture and Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API). Use this source if you want to pipe a real-time audio source (such as a microphone or audio from the user's computer) to an output file.
```ts
import { MediaStreamAudioTrackSource } from 'mediakit';
import { MediaStreamAudioTrackSource } from 'mediabunny';
// Get the user's microphone
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
@@ -329,7 +329,7 @@ If this source is the only MediaStreamTrack source in the `Output`, then the fir
The most barebones of all audio sources, this source can be used to directly pipe [encoded packets](./packets-and-samples#encodedpacket) of audio data to the output. This source requires that you take care of the encoding process yourself, which enables you to use the WebCodecs API manually or to plug in your own encoding stack. Alternatively, you may retrieve the encoded packets directly by reading them from another media file, allowing you to skip decoding and reencoding audio data.
```ts
import { EncodedAudioPacketSource } from 'mediakit';
import { EncodedAudioPacketSource } from 'mediabunny';
// You must specify the codec name:
const packetSource = new EncodedAudioPacketSource('aac');
@@ -360,7 +360,7 @@ Subtitle sources feed data to subtitle tracks on an `Output`. They all extend th
This source feeds subtitle cues to the output from a text file in which the subtitles are defined.
```ts
import { TextSubtitleSource } from 'mediakit';
import { TextSubtitleSource } from 'mediabunny';
const textSource = new TextSubtitleSource('webvtt');
@@ -396,7 +396,7 @@ textSource.close();
You can also add cues individually in small chunks:
```ts
import { TextSubtitleSource } from 'mediakit';
import { TextSubtitleSource } from 'mediabunny';
const textSource = new TextSubtitleSource('webvtt');
+8 -8
View File
@@ -2,7 +2,7 @@
## Introduction
An _output format_ specifies the container format of the data written by an `Output`. Mediakit supports many commonly used container formats, each having format-specific options.
An _output format_ specifies the container format of the data written by an `Output`. Mediabunny supports many commonly used container formats, each having format-specific options.
Many formats also offer *data callbacks*, which are special callbacks that fire for specific data regions in the output file.
@@ -45,7 +45,7 @@ type TrackCountLimits = {
This output format creates MP4 files.
```ts
import { Output, Mp4OutputFormat } from 'mediakit';
import { Output, Mp4OutputFormat } from 'mediabunny';
const output = new Output({
format: new Mp4OutputFormat(options),
@@ -99,7 +99,7 @@ type IsobmffOutputFormatOptions = {
This output format creates QuickTime files (.mov).
```ts
import { Output, MovOutputFormat } from 'mediakit';
import { Output, MovOutputFormat } from 'mediabunny';
const output = new Output({
format: new MovOutputFormat(options),
@@ -113,7 +113,7 @@ The available options are the same `IsobmffOutputFormatOptions` used by [MP4](#m
This output format creates WebM files.
```ts
import { Output, WebmOutputFormat } from 'mediakit';
import { Output, WebmOutputFormat } from 'mediabunny';
const output = new Output({
format: new WebmOutputFormat(options),
@@ -150,7 +150,7 @@ type MkvOutputFormatOptions = {
This output format creates Matroska files (.mkv).
```ts
import { Output, MkvOutputFormat } from 'mediakit';
import { Output, MkvOutputFormat } from 'mediabunny';
const output = new Output({
format: new MkvOutputFormat(options),
@@ -164,7 +164,7 @@ The available options are the same `MkvOutputFormatOptions` used by [WebM](#webm
This output format creates Ogg files.
```ts
import { Output, OggOutputFormat } from 'mediakit';
import { Output, OggOutputFormat } from 'mediabunny';
const output = new Output({
format: new OggOutputFormat(options),
@@ -189,7 +189,7 @@ type OggOutputFormatOptions = {
This output format creates MP3 files.
```ts
import { Output, Mp3OutputFormat } from 'mediakit';
import { Output, Mp3OutputFormat } from 'mediabunny';
const output = new Output({
format: new Mp3OutputFormat(options),
@@ -210,7 +210,7 @@ type Mp3OutputFormatOptions = {
This output format creates WAVE (.wav) files.
```ts
import { Output, WavOutputFormat } from 'mediakit';
import { Output, WavOutputFormat } from 'mediabunny';
const output = new Output({
format: new WavOutputFormat(options),
+11 -11
View File
@@ -2,7 +2,7 @@
## Introduction
Media data in Mediakit is present in two different forms:
Media data in Mediabunny is present in two different forms:
- **Packet:** Encoded media data, the result of an encoding process
- **Sample:** Raw, uncompressed, presentable media data
@@ -30,7 +30,7 @@ flowchart LR
### Connection to WebCodecs
Packets and samples in Mediakit correspond directly with concepts of the [WebCodecs API](https://w3c.github.io/webcodecs/):
Packets and samples in Mediabunny correspond directly with concepts of the [WebCodecs API](https://w3c.github.io/webcodecs/):
- `EncodedPacket`\
-> `EncodedVideoChunk` for video packets\
-> `EncodedAudioChunk` for audio packets
@@ -39,14 +39,14 @@ Packets and samples in Mediakit correspond directly with concepts of the [WebCod
- `AudioSample`
-> `AudioData`
Since Mediakit makes heavy use of WebCodecs API, its own classes are typically used as wrappers around the WebCodecs classes. However, this wrapping comes with a few benefits:
Since Mediabunny makes heavy use of WebCodecs API, its own classes are typically used as wrappers around the WebCodecs classes. However, this wrapping comes with a few benefits:
1. **Independence:** This library remains functional even if the WebCodecs API isn't available. Encoders and decoders can be polyfilled using [custom coders](./supported-formats-and-codecs#custom-coders), and the library can run in non-browser contexts such as Node.js.
1. **Extensibility:** The wrappers serve as a namespace for additional operations, such as `toAudioBuffer()` on `AudioSample`, or `draw()` on `VideoSample`.
1. **Consistency:** While WebCodecs uses integer microsecond timestamps, Mediakit uses floating-point second timestamps everywhere. With these wrappers, all timing information is always in seconds and the user doesn't need to think about unit conversions.
1. **Consistency:** While WebCodecs uses integer microsecond timestamps, Mediabunny uses floating-point second timestamps everywhere. With these wrappers, all timing information is always in seconds and the user doesn't need to think about unit conversions.
Conversion is easy:
```ts
import { EncodedPacket, VideoSample, AudioSample } from 'mediakit';
import { EncodedPacket, VideoSample, AudioSample } from 'mediabunny';
// EncodedPacket to WebCodecs chunks:
encodedPacket.toEncodedVideoChunk(); // => EncodedVideoChunk
@@ -100,7 +100,7 @@ You probably won't ever need to set `sequenceNumber` or `byteLength` in the cons
For example, here we're creating a packet from some encoded video data:
```ts
import { EncodedPacket } from 'mediakit';
import { EncodedPacket } from 'mediabunny';
const encodedVideoData = new Uint8Array([...]);
const encodedPacket = new EncodedPacket(encodedVideoData, 'key', 5, 1/24);
@@ -108,7 +108,7 @@ const encodedPacket = new EncodedPacket(encodedVideoData, 'key', 5, 1/24);
Alternatively, if you're coming from WebCodecs encoded chunks, you can create an `EncodedPacket` from them:
```ts
import { EncodedPacket } from 'mediakit';
import { EncodedPacket } from 'mediabunny';
// From EncodedVideoChunk:
const encodedPacket = EncodedPacket.fromEncodedChunk(encodedVideoChunk);
@@ -214,7 +214,7 @@ The constructor of `VideoSample` is very similar to [`VideoFrame`'s constructor]
This constructor creates a `VideoSample` from a `CanvasImageSource`:
```ts
import { VideoSample } from 'mediakit';
import { VideoSample } from 'mediabunny';
// Creates a sample from a canvas element
const sample = new VideoSample(canvas, {
@@ -237,7 +237,7 @@ const sample = new VideoSample(videoFrame);
This constructor creates a `VideoSample` from raw pixel data given in an `ArrayBuffer`:
```ts
import { VideoSample } from 'mediakit';
import { VideoSample } from 'mediabunny';
// Creates a sample from pixel data in the RGBX format
const sample = new VideoSample(buffer, {
@@ -382,7 +382,7 @@ An audio sample represents a section of audio data. It can be created directly f
Audio samples can be constructed either from an `AudioData` instance or an initialization object:
```ts
import { AudioSample } from 'mediakit';
import { AudioSample } from 'mediabunny';
// From AudioData:
const sample = new AudioSample(audioData);
@@ -502,7 +502,7 @@ for (let i = 0; i < audioSample.numberOfChannels; i++) {
```
::: info
The behavior of `allocationSize` and `copyTo` exactly mirrors that of the WebCodecs API. However, the WebCodecs API specification only mandates support for converting to `f32-planar`, while Mediakit's implementation supports conversion into all formats. Therefore, Mediakit's methods are more powerful.
The behavior of `allocationSize` and `copyTo` exactly mirrors that of the WebCodecs API. However, the WebCodecs API specification only mandates support for converting to `f32-planar`, while Mediabunny's implementation supports conversion into all formats. Therefore, Mediabunny's methods are more powerful.
:::
### Closing audio samples
+15 -15
View File
@@ -1,6 +1,6 @@
# Reading media files
Mediakit allows you to read media files with great control and efficiency. You can use it to extract metadata (such as duration or resolution), as well as to read actual media data from video and audio tracks with frame-accurate timing. Many commonly used [input file formats](./input-formats) are supported. Using [input sources](#input-sources), data can be read from multiple sources, such as directly from memory, from the user's disk, or even over the network.
Mediabunny allows you to read media files with great control and efficiency. You can use it to extract metadata (such as duration or resolution), as well as to read actual media data from video and audio tracks with frame-accurate timing. Many commonly used [input file formats](./input-formats) are supported. Using [input sources](#input-sources), data can be read from multiple sources, such as directly from memory, from the user's disk, or even over the network.
Files are always read partially ("lazily"), meaning only the bytes required to extract the requested information will be read, keeping performance high and memory usage low. Therefore, most methods for reading data are asynchronous and return promises.
@@ -10,11 +10,11 @@ Not all data is extracted equally. Methods that are prefixed with `compute` inst
## Creating a new input
Reading media files in Mediakit revolves around a central class, `Input`, from which all reading operations begin. One instance of `Input` represents one media file that we want to read.
Reading media files in Mediabunny revolves around a central class, `Input`, from which all reading operations begin. One instance of `Input` represents one media file that we want to read.
Start by creating a new instance of `Input`. Here, we're creating it with a [File](https://developer.mozilla.org/en-US/docs/Web/API/File) instance, meaning we'll be reading data directly from the user's disk:
```ts
import { Input, ALL_FORMATS, BlobSource } from 'mediakit';
import { Input, ALL_FORMATS, BlobSource } from 'mediabunny';
const input = new Input({
formats: ALL_FORMATS,
@@ -24,9 +24,9 @@ const input = new Input({
`source` specifies where the `Input` reads data from. See [Input sources](#input-sources) for a full list of available input sources.
`formats` specifies the list of formats that the `Input` should support. This field is mainly used for tree shaking optimizations: Using `ALL_FORMATS` means we can load files of [any format that Mediakit supports](./supported-formats-and-codecs#container-formats), but requires that we include the parsers for each of these formats. If we know we'll only be reading MP3 or WAVE files, then something like this will reduce the overall bundle size drastically:
`formats` specifies the list of formats that the `Input` should support. This field is mainly used for tree shaking optimizations: Using `ALL_FORMATS` means we can load files of [any format that Mediabunny supports](./supported-formats-and-codecs#container-formats), but requires that we include the parsers for each of these formats. If we know we'll only be reading MP3 or WAVE files, then something like this will reduce the overall bundle size drastically:
```ts
import { Input, MP3, WAVE } from 'mediakit';
import { Input, MP3, WAVE } from 'mediabunny';
const input = new Input({
formats: [MP3, WAVE],
@@ -105,7 +105,7 @@ You can query metadata related to the track's codec:
```ts
track.codec; // => MediaCodec | null
```
This field is `null` when the track's codec couldn't be recognized or is not supported by Mediakit. See [Codecs](./supported-formats-and-codecs#codecs) for the full list of supported codecs.
This field is `null` when the track's codec couldn't be recognized or is not supported by Mediabunny. See [Codecs](./supported-formats-and-codecs#codecs) for the full list of supported codecs.
You can also extract the full codec parameter string from the track, as specified in the [WebCodecs Codec Registry](https://www.w3.org/TR/webcodecs-codec-registry/):
```ts
@@ -272,7 +272,7 @@ For example, here's the decoder configuration for an AAC audio track:
## Reading media data
Mediakit has the concept of *media sinks*, which are the way to read media data from an `InputTrack`. Media sinks differ in their API and in their level of abstraction, meaning you can pick whichever sink best fits your use case.
Mediabunny has the concept of *media sinks*, which are the way to read media data from an `InputTrack`. Media sinks differ in their API and in their level of abstraction, meaning you can pick whichever sink best fits your use case.
See [Media sinks](./media-sinks) for a full list of sinks.
@@ -280,7 +280,7 @@ See [Media sinks](./media-sinks) for a full list of sinks.
Here we iterate over all samples (frames) of a video track:
```ts
import { VideoSampleSink } from 'mediakit';
import { VideoSampleSink } from 'mediabunny';
const videoTrack = await input.getPrimaryVideoTrack();
const sink = new VideoSampleSink(videoTrack);
@@ -304,7 +304,7 @@ await sink.getSample(42);
We may want to extract downscaled thumbnails from a video track:
```ts
import { CanvasSink } from 'mediakit';
import { CanvasSink } from 'mediabunny';
const videoTrack = await input.getPrimaryVideoTrack();
const sink = new CanvasSink(videoTrack, {
@@ -327,7 +327,7 @@ for await (const result of sink.canvasesAtTimestamps(thumbnailTimestamps)) {
We may loop over a section of an audio track and play it using the Web Audio API:
```ts
import { AudioBufferSink } from 'mediakit';
import { AudioBufferSink } from 'mediabunny';
const audioTrack = await input.getPrimaryAudioTrack();
const sink = new AudioBufferSink(audioTrack);
@@ -342,7 +342,7 @@ for await (const { buffer, timestamp } of sink.buffers(5, 10)) {
Or we may take the decoding process into our own hands:
```ts
import { EncodedPacketSink } from 'mediakit';
import { EncodedPacketSink } from 'mediabunny';
const videoTrack = await input.getPrimaryVideoTrack();
const sink = new EncodedPacketSink(videoTrack);
@@ -384,7 +384,7 @@ This library offers a couple of sources:
This source uses an in-memory `ArrayBuffer` as the underlying source of data.
```ts
import { BufferSource } from 'mediakit';
import { BufferSource } from 'mediabunny';
// You can construct a BufferSource directly from ArrayBuffer:
const source = new BufferSource(arrayBuffer);
@@ -399,7 +399,7 @@ This source is the fastest but requires the entire input file to be held in memo
This source is backed by an underlying [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) object. Since [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) extends `Blob`, this source is perfect for reading data directly from disk.
```ts
import { BlobSource } from 'mediakit';
import { BlobSource } from 'mediabunny';
fileInput.addEventListener('change', (event) => {
const file = event.target.files[0];
@@ -417,7 +417,7 @@ It still works, but keep in mind it's going to be much higher-latency than readi
This source fetches data from a URL. This is useful for reading files over the network.
```ts
import { UrlSource } from 'mediakit';
import { UrlSource } from 'mediabunny';
const source = new UrlSource('https://example.com/bigbuckbunny.mp4');
```
@@ -461,7 +461,7 @@ This is a general-purpose input source you can use to read data from anywhere. A
For example, here we're reading a file from disk using the Node.js file system:
```ts
import { StreamSource } from 'mediakit';
import { StreamSource } from 'mediabunny';
import { open } from 'node:fs/promises';
const fileHandle = await open('bigbuckbunny.mp4', 'r');
+14 -14
View File
@@ -2,7 +2,7 @@
## Container formats
Mediakit supports many commonly used media container formats, all of which are supported bidirectionally (reading & writing):
Mediabunny supports many commonly used media container formats, all of which are supported bidirectionally (reading & writing):
- ISOBMFF-based formats (.mp4, .m4v, .m4a, ...)
- QuickTime File Format (.mov)
@@ -14,12 +14,12 @@ Mediakit supports many commonly used media container formats, all of which are s
## Codecs
Mediakit supports a wide range of video, audio, and subtitle codecs. More specifically, it supports all codecs specified by the WebCodecs API and a few additional PCM codecs out of the box.
Mediabunny supports a wide range of video, audio, and subtitle codecs. More specifically, it supports all codecs specified by the WebCodecs API and a few additional PCM codecs out of the box.
The availability of the codecs provided by the WebCodecs API depends on the browser and thus cannot be guaranteed by this library. Mediakit provides [special utility functions](#querying-codec-encodability) to check which codecs are able to be encoded. You can also specify [custom coders](#custom-coders) to provide your own encoder/decoder implementation if the browser doesn't support the codec natively.
The availability of the codecs provided by the WebCodecs API depends on the browser and thus cannot be guaranteed by this library. Mediabunny provides [special utility functions](#querying-codec-encodability) to check which codecs are able to be encoded. You can also specify [custom coders](#custom-coders) to provide your own encoder/decoder implementation if the browser doesn't support the codec natively.
::: info
Mediakit ships with built-in decoders and encoders for all audio PCM codecs, meaning they are always supported.
Mediabunny ships with built-in decoders and encoders for all audio PCM codecs, meaning they are always supported.
:::
### Video codecs
@@ -94,12 +94,12 @@ Not all codecs can be used with all containers. The following table specifies th
## Querying codec encodability
Mediakit provides utility functions that you can use to check if the browser can encode a given codec. Additionally, you
Mediabunny provides utility functions that you can use to check if the browser can encode a given codec. Additionally, you
can check if a codec is encodable with a specific _configuration_.
`canEncode` tests whether a codec can be encoded using typical settings:
```ts
import { canEncode } from 'mediakit';
import { canEncode } from 'mediabunny';
canEncode('avc'); // => Promise<boolean>
canEncode('opus'); // => Promise<boolean>
@@ -108,7 +108,7 @@ Video codecs are checked using 1280x720 @1Mbps, while audio codecs are checked u
You can also check encodability using specific configurations:
```ts
import { canEncodeVideo, canEncodeAudio } from 'mediakit';
import { canEncodeVideo, canEncodeAudio } from 'mediabunny';
canEncodeVideo('hevc', {
width: 1920, height: 1080, bitrate: 1e7
@@ -128,7 +128,7 @@ import {
getEncodableVideoCodecs,
getEncodableAudioCodecs,
getEncodableSubtitleCodecs,
} from 'mediakit';
} from 'mediabunny';
getEncodableCodecs(); // => Promise<MediaCodec[]>
getEncodableVideoCodecs(); // => Promise<VideoCodec[]>
@@ -151,7 +151,7 @@ import {
getFirstEncodableVideoCodec,
getFirstEncodableAudioCodec,
getFirstEncodableSubtitleCodec,
} from 'mediakit';
} from 'mediabunny';
getFirstEncodableVideoCodec(['avc', 'vp9', 'av1']); // => Promise<VideoCodec | null>
getFirstEncodableAudioCodec(['opus', 'aac']); // => Promise<AudioCodec | null>
@@ -169,7 +169,7 @@ These functions are especially useful in conjunction with an [output format](./o
import {
Mp4OutputFormat,
getFirstEncodableVideoCodec,
} from 'mediakit';
} from 'mediabunny';
const outputFormat = new Mp4OutputFormat();
const containableVideoCodecs = outputFormat.getSupportedVideoCodecs();
@@ -186,19 +186,19 @@ Whether a codec can be decoded depends on the specific codec configuration of an
## Custom coders
Mediakit allows you to register your own custom encoders and decoders - useful if you want to polyfill a codec that's not supported in all browsers, or want to use Mediakit outside of an environment with WebCodecs (such as Node.js).
Mediabunny allows you to register your own custom encoders and decoders - useful if you want to polyfill a codec that's not supported in all browsers, or want to use Mediabunny outside of an environment with WebCodecs (such as Node.js).
Encoders and decoders can be registered for [all video and audio codecs](#codecs) supported by the library. It is not possible to add new codecs.
::: warning
Mediakit requires customs encoders and decoders to follow very specific implementation rules. Pay special attention to the parts labeled with "**must**" to ensure compatibility.
Mediabunny requires customs encoders and decoders to follow very specific implementation rules. Pay special attention to the parts labeled with "**must**" to ensure compatibility.
:::
### Custom encoders
To create a custom video or audio encoder, you'll need to create a class which extends `CustomVideoEncoder` or `CustomAudioEncoder`. Then, you **must** register this class using `registerEncoder`:
```ts
import { CustomAudioEncoder, registerEncoder } from 'mediakit';
import { CustomAudioEncoder, registerEncoder } from 'mediabunny';
class MyAwesomeMp3Encoder extends CustomAudioEncoder {
// ...
@@ -261,7 +261,7 @@ The packets passed to `onPacket` **must** be in [decode order](./media-sinks.md#
To create a custom video or audio decoder, you'll need to create a class which extends `CustomVideoDecoder` or `CustomAudioDecoder`. Then, you **must** register this class using `registerDecoder`:
```ts
import { CustomAudioDecoder, registerDecoder } from 'mediakit';
import { CustomAudioDecoder, registerDecoder } from 'mediabunny';
class MyAwesomeMp3Decoder extends CustomAudioDecoder {
// ...
+7 -7
View File
@@ -1,16 +1,16 @@
# Writing media files
Mediakit enables you to create media files with very fine levels of control. You can add an arbitrary number of video, audio and subtitle tracks to a media file, and precisely control the timing of media data. This library supports [many output file formats](./output-formats). Using [output targets](#output-targets), you can decide if you want to build up the entire file in memory or stream it out in chunks as it's being created - allowing you to create very large files.
Mediabunny enables you to create media files with very fine levels of control. You can add an arbitrary number of video, audio and subtitle tracks to a media file, and precisely control the timing of media data. This library supports [many output file formats](./output-formats). Using [output targets](#output-targets), you can decide if you want to build up the entire file in memory or stream it out in chunks as it's being created - allowing you to create very large files.
Mediakit provides many ways to supply media data for output tracks, nicely integrating with the WebCodecs API, but also allowing you to use your own encoding stack if you wish. These [media sources](./media-sources) come in multiple levels of abstraction, enabling easy use for common use cases while still giving you fine-grained control if you need it.
Mediabunny provides many ways to supply media data for output tracks, nicely integrating with the WebCodecs API, but also allowing you to use your own encoding stack if you wish. These [media sources](./media-sources) come in multiple levels of abstraction, enabling easy use for common use cases while still giving you fine-grained control if you need it.
## Creating an output
Media file creation in Mediakit revolves around a central class, `Output`. One instance of `Output` represents one media file you want to create.
Media file creation in Mediabunny revolves around a central class, `Output`. One instance of `Output` represents one media file you want to create.
Start by creating a new instance of `Output` using the desired configuration of the file you want to create:
```ts
import { Output, Mp4OutputFormat, BufferTarget } from 'mediakit';
import { Output, Mp4OutputFormat, BufferTarget } from 'mediabunny';
// In this example, we'll be creating an MP4 file in memory:
const output = new Output({
@@ -82,7 +82,7 @@ As an example, let's add two tracks to our output:
- An audio track driven by the user's microphone input, encoded using AAC
```ts
import { CanvasSource, MediaStreamAudioTrackSource } from 'mediakit';
import { CanvasSource, MediaStreamAudioTrackSource } from 'mediabunny';
// Assuming `canvasElement` exists
const videoSource = new CanvasSource(canvasElement, {
@@ -202,7 +202,7 @@ The _output target_ determines where the data created by the `Output` will be wr
This target writes all data to a single, contiguous, in-memory `ArrayBuffer`. This buffer will automatically grow as the file becomes larger. Usage is straightforward:
```ts
import { Output, BufferTarget } from 'mediakit';
import { Output, BufferTarget } from 'mediabunny';
const output = new Output({
target: new BufferTarget(),
@@ -224,7 +224,7 @@ This target passes you the data written by the `Output` in small chunks, requiri
`StreamTarget` makes use of the Streams API, meaning you'll need to pass it an instance of `WritableStream`:
```ts
import { Output, StreamTarget, StreamTargetChunk } from 'mediakit';
import { Output, StreamTarget, StreamTargetChunk } from 'mediabunny';
const writable = new WritableStream({
write(chunk: StreamTargetChunk) {
@@ -7,7 +7,7 @@ import {
Mp4OutputFormat,
Conversion,
QUALITY_VERY_LOW,
} from 'mediakit';
} from 'mediabunny';
const selectMediaButton = document.querySelector('button') as HTMLButtonElement;
const fileNameElement = document.querySelector('#file-name') as HTMLParagraphElement;
+4 -4
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File compression example | Mediakit</title>
<title>File compression example | Mediabunny</title>
<script type="module" src="../base.ts"></script>
<script type="module" src="./file-compression.ts"></script>
<link rel="stylesheet" href="../base.css">
@@ -12,7 +12,7 @@
<body class="flex flex-col items-center py-10 bg-zinc-50 text-zinc-800 dark:bg-zinc-900 dark:text-zinc-200 px-2">
<h1 class="text-3xl font-bold text-teal-800 dark:text-teal-200 text-center">File compression example</h1>
<p class="max-w-lg text-center">Select or drop a media file, and Mediakit will convert it to a heavily-compressed MP4 file.</p>
<p class="max-w-lg text-center">Select or drop a media file, and Mediabunny will convert it to a heavily-compressed MP4 file.</p>
<div class="flex gap-2 mt-4">
<button class="rounded-lg bg-zinc-200 dark:bg-zinc-750 hover:bg-zinc-300 dark:hover:bg-zinc-700 px-5 py-2">
@@ -38,8 +38,8 @@
<p class="text-xs font-medium mt-1" id="compression-facts" style="display: none;"></p>
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediakit</p>
<img src="../../assets/mediabunny-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediabunny</p>
</div>
<a
+3 -3
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live recording example | Mediakit</title>
<title>Live recording example | Mediabunny</title>
<script type="module" src="../base.ts"></script>
<script type="module" src="./live-recording.ts"></script>
<link rel="stylesheet" href="../base.css">
@@ -39,8 +39,8 @@
</div>
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediakit</p>
<img src="../../assets/mediabunny-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediabunny</p>
</div>
<a
+1 -1
View File
@@ -5,7 +5,7 @@ import {
Output,
QUALITY_MEDIUM,
StreamTarget,
} from 'mediakit';
} from 'mediabunny';
const toggleRecordingButton = document.querySelector('#toggle-button') as HTMLButtonElement;
const horizontalRule = document.querySelector('hr') as HTMLHRElement;
+4 -4
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Media player example | Mediakit</title>
<title>Media player example | Mediabunny</title>
<script type="module" src="../base.ts"></script>
<script type="module" src="./media-player.ts"></script>
<link rel="stylesheet" href="../base.css">
@@ -12,7 +12,7 @@
<body class="flex flex-col items-center py-10 bg-zinc-50 text-zinc-800 dark:bg-zinc-900 dark:text-zinc-200 px-2 h-svh">
<h1 class="text-3xl font-bold text-purple-800 dark:text-purple-200 text-center">Media player example</h1>
<p class="max-w-lg text-center">Select or drop a media file, and a fully custom, Mediakit-powered player will appear.</p>
<p class="max-w-lg text-center">Select or drop a media file, and a fully custom, Mediabunny-powered player will appear.</p>
<div class="flex gap-2 mt-4">
<button class="rounded-lg bg-zinc-200 dark:bg-zinc-750 hover:bg-zinc-300 dark:hover:bg-zinc-700 px-5 py-2">
@@ -74,8 +74,8 @@
</div>
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediakit</p>
<img src="../../assets/mediabunny-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediabunny</p>
</div>
<a
+1 -1
View File
@@ -6,7 +6,7 @@ import {
Input,
WrappedAudioBuffer,
WrappedCanvas,
} from 'mediakit';
} from 'mediabunny';
const selectMediaButton = document.querySelector('button') as HTMLButtonElement;
const fileNameElement = document.querySelector('#file-name') as HTMLParagraphElement;
+4 -4
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Metadata extraction example | Mediakit</title>
<title>Metadata extraction example | Mediabunny</title>
<script type="module" src="../base.ts"></script>
<script type="module" src="./metadata-extraction.ts"></script>
<link rel="stylesheet" href="../base.css">
@@ -12,7 +12,7 @@
<body class="flex flex-col items-center py-10 bg-zinc-50 text-zinc-800 dark:bg-zinc-900 dark:text-zinc-200 px-2">
<h1 class="text-3xl font-bold text-blue-800 dark:text-blue-200 text-center">Metadata extraction example</h1>
<p class="max-w-lg text-center">Select or drop a media file, and Mediakit will start extracting various metadata about that file.</p>
<p class="max-w-lg text-center">Select or drop a media file, and Mediabunny will start extracting various metadata about that file.</p>
<div class="flex gap-2 mt-4">
<button class="rounded-lg bg-zinc-200 dark:bg-zinc-750 hover:bg-zinc-300 dark:hover:bg-zinc-700 px-5 py-2">
@@ -31,8 +31,8 @@
<div id="metadata-container" class="text-sm"></div>
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediakit</p>
<img src="../../assets/mediabunny-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediabunny</p>
</div>
<a
@@ -1,4 +1,4 @@
import { Input, ALL_FORMATS, BlobSource } from 'mediakit';
import { Input, ALL_FORMATS, BlobSource } from 'mediabunny';
const selectMediaButton = document.querySelector('button') as HTMLButtonElement;
const fileNameElement = document.querySelector('#file-name') as HTMLParagraphElement;
+4 -4
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Procedural Generation example | Mediakit</title>
<title>Procedural Generation example | Mediabunny</title>
<script type="module" src="../base.ts"></script>
<script type="module" src="./procedural-generation.ts"></script>
<link rel="stylesheet" href="../base.css">
@@ -12,7 +12,7 @@
<body class="flex flex-col items-center py-10 bg-zinc-50 text-zinc-800 dark:bg-zinc-900 dark:text-zinc-200 px-2">
<h1 class="text-3xl font-bold text-teal-800 dark:text-teal-200 text-center">Procedural generation example</h1>
<p class="max-w-lg text-center">Using Mediakit, this page will procedurally generate a video of musical bouncing balls as fast as possible.</p>
<p class="max-w-lg text-center">Using Mediabunny, this page will procedurally generate a video of musical bouncing balls as fast as possible.</p>
<div class="flex flex-col gap-6 mt-8 w-full max-w-80">
<div class="flex flex-col gap-2">
@@ -45,8 +45,8 @@
<p class="text-xs font-medium mt-1" id="video-info" style="display: none;"></p>
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediakit</p>
<img src="../../assets/mediabunny-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediabunny</p>
</div>
<a
@@ -7,7 +7,7 @@ import {
QUALITY_HIGH,
getFirstEncodableAudioCodec,
getFirstEncodableVideoCodec,
} from 'mediakit';
} from 'mediabunny';
const durationSlider = document.querySelector('#duration-slider') as HTMLInputElement;
const durationValue = document.querySelector('#duration-value') as HTMLParagraphElement;
+4 -4
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Thumbnail generation example | Mediakit</title>
<title>Thumbnail generation example | Mediabunny</title>
<script type="module" src="./../base.ts"></script>
<script type="module" src="./thumbnail-generation.ts"></script>
<link rel="stylesheet" href="../base.css">
@@ -12,7 +12,7 @@
<body class="flex flex-col items-center py-10 bg-gray-50 text-gray-800 dark:bg-zinc-900 dark:text-zinc-200 px-2">
<h1 class="text-3xl font-bold text-emerald-800 dark:text-emerald-200 text-center">Thumbnail generation example</h1>
<p class="max-w-lg text-center">Select or drop a media file, and Mediakit will extract video thumbnails for it.</p>
<p class="max-w-lg text-center">Select or drop a media file, and Mediabunny will extract video thumbnails for it.</p>
<div class="flex gap-2 mt-4">
<button class="rounded-lg bg-gray-200 dark:bg-zinc-750 hover:bg-gray-300 dark:hover:bg-zinc-700 px-5 py-1">
@@ -31,8 +31,8 @@
<div id="thumbnail-container" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4"></div>
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediakit</p>
<img src="../../assets/mediabunny-logo.svg" class="size-6 dark:invert">
<p class="text-sm font-semibold">Mediabunny</p>
</div>
<a
@@ -1,4 +1,4 @@
import { Input, ALL_FORMATS, BlobSource, CanvasSink } from 'mediakit';
import { Input, ALL_FORMATS, BlobSource, CanvasSink } from 'mediabunny';
const selectMediaButton = document.querySelector('button') as HTMLButtonElement;
const fileNameElement = document.querySelector('#file-name') as HTMLParagraphElement;
+1 -1
View File
@@ -6,7 +6,7 @@
"composite": true,
"noEmit": false,
"paths": {
"mediakit": ["./dist/metamuxer.d.ts"],
"mediabunny": ["./dist/metamuxer.d.ts"],
},
},
"include": [
+1 -1
View File
@@ -20,7 +20,7 @@ const rollupInput = Object.fromEntries(
export default defineConfig({
resolve: {
alias: {
mediakit: path.resolve(__dirname, './dist/metamuxer.mjs'),
mediabunny: path.resolve(__dirname, './dist/metamuxer.mjs'),
},
},
plugins: [