mediabunny
Version:
Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.
639 lines • 26.9 kB
TypeScript
/*!
* Copyright (c) 2026-present, Vanilagy and contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { AudioCodec, MediaCodec, SubtitleCodec, VideoCodec } from './codec.js';
import { MediaSource } from './media-source.js';
import { OutputTrack, TrackType } from './output.js';
import { MaybePromise, FilePath } from './misc.js';
import { Target } from './target.js';
/**
* Specifies an inclusive range of integers.
* @group Miscellaneous
* @public
*/
export type InclusiveIntegerRange = {
/** The integer cannot be less than this. */
min: number;
/** The integer cannot be greater than this. */
max: number;
};
/**
* Specifies the number of tracks (for each track type and in total) that an output format supports.
* @group Output formats
* @public
*/
export type TrackCountLimits = {
[K in TrackType]: InclusiveIntegerRange;
} & {
/** Specifies the overall allowed range of track counts for the output format. */
total: InclusiveIntegerRange;
};
/**
* Base class representing an output media file format.
* @group Output formats
* @public
*/
export declare abstract class OutputFormat {
/** The file extension used by this output format, beginning with a dot. */
abstract get fileExtension(): string;
/** The base MIME type of the output format. */
abstract get mimeType(): string;
/** Returns a list of media codecs that this output format can contain. */
abstract getSupportedCodecs(): MediaCodec[];
/** Returns the number of tracks that this output format supports. */
abstract getSupportedTrackCounts(): TrackCountLimits;
/** Whether this output format supports video rotation metadata. */
abstract get supportsVideoRotationMetadata(): boolean;
/**
* Whether this output format's tracks store timestamped media data. When `true`, the timestamps of added packets
* will be respected, allowing things like gaps in media data or non-zero start times. When `false`, the format's
* media data implicitly starts at zero and follows an implicit sequential timing from there, using the intrinsic
* durations of the media data.
*/
abstract get supportsTimestampedMediaData(): boolean;
/** Returns a list of video codecs that this output format can contain. */
getSupportedVideoCodecs(): VideoCodec[];
/** Returns a list of audio codecs that this output format can contain. */
getSupportedAudioCodecs(): AudioCodec[];
/** Returns a list of subtitle codecs that this output format can contain. */
getSupportedSubtitleCodecs(): SubtitleCodec[];
}
/**
* ISOBMFF-specific output options.
* @group Output formats
* @public
*/
export type IsobmffOutputFormatOptions = {
/**
* Controls the placement of metadata in the file. Placing metadata at the start of the file is known as "Fast
* Start", which results in better playback at the cost of more required processing or memory.
*
* Use `false` to disable Fast Start, placing the metadata at the end of the file. Fastest and uses the least
* memory.
*
* Use `'in-memory'` to produce a file with Fast Start by keeping all media chunks in memory until the file is
* finalized. This produces a high-quality and compact output at the cost of a more expensive finalization step and
* higher memory requirements. Data will be written monotonically (in order) when this option is set.
*
* Use `'reserve'` to reserve space at the start of the file into which the metadata will be written later. This
* produces a file with Fast Start but requires knowledge about the expected length of the file beforehand. When
* using this option, you must set the {@link BaseTrackMetadata.maximumPacketCount} field in the track metadata
* for all tracks.
*
* Use `'fragmented'` to place metadata at the start of the file by creating a fragmented file (fMP4). In a
* fragmented file, chunks of media and their metadata are written to the file in "fragments", eliminating the need
* to put all metadata in one place. Fragmented files are useful for streaming contexts, as each fragment can be
* played individually without requiring knowledge of the other fragments. Furthermore, they remain lightweight to
* create even for very large files, as they don't require all media to be kept in memory. However, fragmented files
* are not as widely and wholly supported as regular MP4/MOV files. Data will be written monotonically (in order)
* when this option is set.
*
* When this field is not defined, either `false` or `'in-memory'` will be used, automatically determined based on
* the type of output target used.
*/
fastStart?: false | 'in-memory' | 'reserve' | 'fragmented';
/**
* When using `fastStart: 'fragmented'`, this field controls the minimum duration of each fragment, in seconds.
* New fragments will only be created when the current fragment is longer than this value. Defaults to 1 second.
*/
minimumFragmentDuration?: number;
/**
* The metadata format to use for writing metadata tags.
*
* - `'auto'` (default): Behaves like `'mdir'` for MP4 and like `'udta'` for QuickTime, matching FFmpeg's default
* behavior.
* - `'mdir'`: Write tags into `moov/udta/meta` using the 'mdir' handler format.
* - `'mdta'`: Write tags into `moov/udta/meta` using the 'mdta' handler format, equivalent to FFmpeg's
* `use_metadata_tags` flag. This allows for custom keys of arbitrary length.
* - `'udta'`: Write tags directly into `moov/udta`.
*/
metadataFormat?: 'auto' | 'mdir' | 'mdta' | 'udta';
/**
* Will be called once the ftyp (File Type) box of the output file has been written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onFtyp?: (data: Uint8Array, position: number) => unknown;
/**
* Will be called once the moov (Movie) box of the output file has been written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onMoov?: (data: Uint8Array, position: number) => unknown;
/**
* Will be called for each finalized mdat (Media Data) box of the output file. Usage of this callback is not
* recommended when not using `fastStart: 'fragmented'`, as there will be one monolithic mdat box which might
* require large amounts of memory.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onMdat?: (data: Uint8Array, position: number) => unknown;
/**
* Will be called for each finalized moof (Movie Fragment) box of the output file.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
* @param timestamp - The start timestamp of the fragment in seconds.
*/
onMoof?: (data: Uint8Array, position: number, timestamp: number) => unknown;
};
/**
* Format representing files compatible with the ISO base media file format (ISOBMFF), like MP4 or MOV files.
* @group Output formats
* @public
*/
export declare abstract class IsobmffOutputFormat extends OutputFormat {
/** Internal constructor. */
constructor(options?: IsobmffOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* MPEG-4 Part 14 (MP4) file format. Supports most codecs.
* @group Output formats
* @public
*/
export declare class Mp4OutputFormat extends IsobmffOutputFormat {
/** Creates a new {@link Mp4OutputFormat} configured with the specified `options`. */
constructor(options?: IsobmffOutputFormatOptions);
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
}
/**
* CMAF-specific output options.
* @group Output formats
* @public
*/
export type CmafOutputFormatOptions = Omit<IsobmffOutputFormatOptions, 'fastStart'> & {
/**
* Controls the minimum duration of each fragment, in seconds. New fragments will only be created when the current
* fragment is longer than this value. Defaults to `Infinity`, meaning the file will contain only one fragment.
*/
minimumFragmentDuration?: number;
};
/**
* Creates a single Common Media Application Format (CMAF) segment. An init segment will be written to the
* {@link Target} specified in {@link OutputOptions.initTarget}. Supports most codecs.
* @group Output formats
* @public
*/
export declare class CmafOutputFormat extends IsobmffOutputFormat {
/** Creates a new {@link CmafOutputFormat} configured with the specified `options`. */
constructor(options?: CmafOutputFormatOptions);
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
}
/**
* QuickTime File Format (QTFF), often called MOV. Supports all video and audio codecs, but not subtitle codecs.
* @group Output formats
* @public
*/
export declare class MovOutputFormat extends IsobmffOutputFormat {
/** Creates a new {@link MovOutputFormat} configured with the specified `options`. */
constructor(options?: IsobmffOutputFormatOptions);
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
}
/**
* Matroska-specific output options.
* @group Output formats
* @public
*/
export type MkvOutputFormatOptions = {
/**
* Configures the output to only append new data at the end, useful for live-streaming the file as it's being
* created. When enabled, some features such as storing duration and seeking will be disabled or impacted, so don't
* use this option when you want to write out a clean file for later use.
*/
appendOnly?: boolean;
/**
* This field controls the minimum duration of each Matroska cluster, in seconds. New clusters will only be created
* when the current cluster is longer than this value. Defaults to 1 second.
*/
minimumClusterDuration?: number;
/**
* Will be called once the EBML header of the output file has been written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onEbmlHeader?: (data: Uint8Array, position: number) => void;
/**
* Will be called once the header part of the Matroska Segment element has been written. The header data includes
* the Segment element and everything inside it, up to (but excluding) the first Matroska Cluster.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onSegmentHeader?: (data: Uint8Array, position: number) => unknown;
/**
* Will be called for each finalized Matroska Cluster of the output file.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
* @param timestamp - The start timestamp of the cluster in seconds.
*/
onCluster?: (data: Uint8Array, position: number, timestamp: number) => unknown;
};
/**
* Matroska file format.
*
* Supports writing transparent video. For a video track to be marked as transparent, the first packet added must
* contain alpha side data.
*
* @group Output formats
* @public
*/
export declare class MkvOutputFormat extends OutputFormat {
/** Creates a new {@link MkvOutputFormat} configured with the specified `options`. */
constructor(options?: MkvOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* WebM-specific output options.
* @group Output formats
* @public
*/
export type WebMOutputFormatOptions = MkvOutputFormatOptions;
/**
* WebM file format, based on Matroska.
*
* Supports writing transparent video. For a video track to be marked as transparent, the first packet added must
* contain alpha side data.
*
* @group Output formats
* @public
*/
export declare class WebMOutputFormat extends MkvOutputFormat {
/** Creates a new {@link WebMOutputFormat} configured with the specified `options`. */
constructor(options?: MkvOutputFormatOptions);
getSupportedCodecs(): MediaCodec[];
get fileExtension(): string;
get mimeType(): string;
}
/**
* MP3-specific output options.
* @group Output formats
* @public
*/
export type Mp3OutputFormatOptions = {
/**
* Controls whether the Xing header, which contains additional metadata as well as an index, is written to the start
* of the MP3 file. When disabled, the writing process becomes append-only. Defaults to `true`.
*/
xingHeader?: boolean;
/**
* Will be called once the Xing metadata frame is finalized.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onXingFrame?: (data: Uint8Array, position: number) => unknown;
};
/**
* MP3 file format.
* @group Output formats
* @public
*/
export declare class Mp3OutputFormat extends OutputFormat {
/** Creates a new {@link Mp3OutputFormat} configured with the specified `options`. */
constructor(options?: Mp3OutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* WAVE-specific output options.
* @group Output formats
* @public
*/
export type WavOutputFormatOptions = {
/**
* When enabled, an RF64 file will be written, allowing for file sizes to exceed 4 GiB, which is otherwise not
* possible for regular WAVE files.
*/
large?: boolean;
/**
* The metadata format to use for writing metadata tags.
*
* - `'info'` (default): Writes metadata into a RIFF INFO LIST chunk, the default way to contain metadata tags
* within WAVE. Only allows for a limited subset of tags to be written.
* - `'id3'`: Writes metadata into an ID3 chunk. Non-default, but used by many taggers in practice. Allows for a
* much larger and richer set of tags to be written.
*/
metadataFormat?: 'info' | 'id3';
/**
* Will be called once the file header is written. The header consists of the RIFF header, the format chunk,
* metadata chunks, and the start of the data chunk (with a placeholder size of 0).
*/
onHeader?: (data: Uint8Array, position: number) => unknown;
};
/**
* WAVE file format, based on RIFF.
* @group Output formats
* @public
*/
export declare class WavOutputFormat extends OutputFormat {
/** Creates a new {@link WavOutputFormat} configured with the specified `options`. */
constructor(options?: WavOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* Ogg-specific output options.
* @group Output formats
* @public
*/
export type OggOutputFormatOptions = {
/**
* The maximum duration of each Ogg page, in seconds. This is useful for streaming contexts where more frequent page
* output is desired. By default, pages are only flushed when they exceed a certain size.
*/
maximumPageDuration?: number;
/**
* Will be called for each Ogg page that is written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
* @param source - The {@link MediaSource} backing the page's logical bitstream (track).
*/
onPage?: (data: Uint8Array, position: number, source: MediaSource) => unknown;
};
/**
* Ogg file format.
* @group Output formats
* @public
*/
export declare class OggOutputFormat extends OutputFormat {
/** Creates a new {@link OggOutputFormat} configured with the specified `options`. */
constructor(options?: OggOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* ADTS-specific output options.
* @group Output formats
* @public
*/
export type AdtsOutputFormatOptions = {
/**
* Will be called for each ADTS frame that is written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onFrame?: (data: Uint8Array, position: number) => unknown;
};
/**
* ADTS file format.
* @group Output formats
* @public
*/
export declare class AdtsOutputFormat extends OutputFormat {
/** Creates a new {@link AdtsOutputFormat} configured with the specified `options`. */
constructor(options?: AdtsOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* FLAC-specific output options.
* @group Output formats
* @public
*/
export type FlacOutputFormatOptions = {
/**
* Configures the output to only append new data at the end, useful for live-streaming the file as it's being
* created. When enabled, the STREAMINFO block will not be finalized with accurate min/max block sizes, frame sizes,
* or total sample count, so don't use this option when you want to write out a clean file for later use.
*/
appendOnly?: boolean;
/**
* Will be called for each FLAC frame that is written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onFrame?: (data: Uint8Array, position: number) => unknown;
};
/**
* FLAC file format.
* @group Output formats
* @public
*/
export declare class FlacOutputFormat extends OutputFormat {
/** Creates a new {@link FlacOutputFormat} configured with the specified `options`. */
constructor(options?: FlacOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* MPEG-TS-specific output options.
* @group Output formats
* @public
*/
export type MpegTsOutputFormatOptions = {
/**
* Will be called for each 188-byte Transport Stream packet that is written.
*
* @param data - The raw bytes.
* @param position - The byte offset of the data in the file.
*/
onPacket?: (data: Uint8Array, position: number) => unknown;
};
/**
* MPEG Transport Stream file format.
* @group Output formats
* @public
*/
export declare class MpegTsOutputFormat extends OutputFormat {
/** Creates a new {@link MpegTsOutputFormat} configured with the specified `options`. */
constructor(options?: MpegTsOutputFormatOptions);
getSupportedTrackCounts(): TrackCountLimits;
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
/**
* Info about an HLS media playlist.
* @group Output formats
* @public
*/
export type HlsOutputPlaylistInfo = {
/** The 1-based index of the media playlist in the master playlist. */
n: number;
/** The output tracks contained in this playlist. */
tracks: OutputTrack[];
/** The format of the media segments in this playlist. */
segmentFormat: OutputFormat;
};
/**
* Info about an HLS media segment.
* @group Output formats
* @public
*/
export type HlsOutputSegmentInfo = {
/** The 1-based index of the segment in the containing media playlist. */
n: number;
/** If the segment is a single file, meaning it is a single segment file that covers the entire playlist. */
isSingleFile: boolean;
/** The format of the media segment. */
format: OutputFormat;
/** The media playlist to which this segment belongs. */
playlist: HlsOutputPlaylistInfo;
};
/**
* HLS-specific output options.
* @group Output formats
* @public
*/
export type HlsOutputFormatOptions = {
/**
* Specifies the file format of each media segment. Not all formats are supported by all players; prefer sticking
* to the most commonly used ones: {@link MpegTsOutputFormat}, {@link CmafOutputFormat}, {@link AdtsOutputFormat},
* and {@link Mp3OutputFormat}.
*
* When an array of formats is specified, for each playlist, the first format that can contain all of the playlist's
* tracks is chosen. This allows you to, for example, package audio into .aac files and video into .ts files.
*/
segmentFormat: OutputFormat | OutputFormat[];
/**
* Specifies the target (max) duration in seconds for each media segment, defaulting to 2 seconds.
*
* Mediabunny will try not to emit media segments longer than the target duration, but it is forced to if key frames
* are provided with a longer period than the target duration. Therefore, make sure to encode a key frame at least
* every `targetDuration` seconds to guarantee segment length, controllable via
* {@link VideoEncodingConfig.keyFrameInterval}.
*/
targetDuration?: number;
/**
* Whether to bundle all media segments for a playlist into a single file. Individual segments are then extracted
* via range requests.
*/
singleFilePerPlaylist?: boolean;
/**
* If `true`, the muxer will be in "live mode", continuously emitting updated playlists as new segments are created.
* The master playlist will be emitted as soon as all playlists have been emitted at least once, and will continue
* to be emitted each time a segment is finalized to further refine the accuracy of the `BANDWIDTH` attribute.
*
* When `false` (the default), all playlists will only be emitted once, upon output finalization.
*/
live?: boolean;
/**
* When in live mode, this controls the maximum number of segments contained in each playlist. Defaults to
* `Infinity`, meaning playlists continually grow in size.
*/
maxLiveSegmentCount?: number;
/**
* Returns the file path for a given media playlist. If the returned path is relative, it is relative to the root
* path.
*
* Defaults to `'playlist-{n}.m3u8'`, where `n` is the 1-based index of the media playlist in the master playlist.
*/
getPlaylistPath?: (info: HlsOutputPlaylistInfo) => MaybePromise<FilePath>;
/**
* Returns the file path for a given media segment. If the returned path is relative, it is relative to the path
* of the containing playlist.
*
* Defaults to `'segment-{n}-{k}{ext}'`, where `n` is the 1-based index of the containing media playlist in the
* master playlist, `k` is the 1-based index of the segment in its playlist, and `ext` is the file extension of the
* segment format (including the leading dot).
*
* If {@link HlsOutputFormatOptions.singleFilePerPlaylist} is true, it defaults to `'segments-{n}{ext}'` instead.
*/
getSegmentPath?: (info: HlsOutputSegmentInfo) => MaybePromise<FilePath>;
/**
* Returns the file path for a given media init segment. If the returned path is relative, it is relative to the
* path of the containing playlist.
*
* Only necessary for segment formats that require an init file, such as {@link CmafOutputFormat}.
*
* Defaults to `'init-{n}{ext}'`, where `n` is the 1-based index of the containing media playlist in the master
* playlist and `ext` is the file extension of the segment format (including the leading dot).
*/
getInitPath?: (info: HlsOutputPlaylistInfo) => MaybePromise<FilePath>;
/** Called whenever the master playlist is written. */
onMaster?: (content: string) => unknown;
/** Called whenever a media playlist is written. */
onPlaylist?: (content: string, info: HlsOutputPlaylistInfo) => unknown;
/**
* Called whenever a media segment has been fully written. In single-file mode, this function will only be called
* once when the playlist is finalized.
*/
onSegment?: (target: Target, info: HlsOutputSegmentInfo) => unknown;
/**
* Called when a media playlist is initialized, before any segments have been written. In single-file mode, this
* function is never called.
*/
onInit?: (target: Target, info: HlsOutputPlaylistInfo) => unknown;
/**
* Called when a media segment is removed from the start of a media playlist due to
* {@link HlsOutputFormatOptions.maxLiveSegmentCount}. Will not be called when
* {@link HlsOutputFormatOptions.singleFilePerPlaylist} is `true`.
*/
onSegmentPopped?: (path: string, info: HlsOutputSegmentInfo) => unknown;
};
/**
* HTTP Live Streaming (HLS) output format. HLS media is represented by a set of .m3u8 playlist files and media segment
* files, meaning this format writes out multiple files, requiring the use of a _pathed Output_
* ({@link OutputOptions.target} must be a {@link PathedTarget}).
*
* This output format creates the following files:
* - A master playlist .m3u8 file, containing the list of available playlists. A master playlist is always emitted,
* written to the root path.
* - One .m3u8 file for each playlist, each containing a list of media segments.
* - Many media segments, containing the actual media data.
*
* To emit media playlists that use the `#EXT-X-PROGRAM-DATE-TIME` tag to map segment timestamps to real-world time,
* set {@link BaseTrackMetadata.isRelativeToUnixEpoch} to `true` for all tracks.
*
* @group Output formats
* @public
*/
export declare class HlsOutputFormat extends OutputFormat {
/** Creates a new {@link HlsOutputFormat} configured with the specified `options`. */
constructor(options: HlsOutputFormatOptions);
get fileExtension(): string;
get mimeType(): string;
getSupportedCodecs(): MediaCodec[];
getSupportedTrackCounts(): TrackCountLimits;
get supportsVideoRotationMetadata(): boolean;
get supportsTimestampedMediaData(): boolean;
}
//# sourceMappingURL=output-format.d.ts.map