UNPKG

mediabunny

Version:

Pure TypeScript media toolkit for reading, writing, and converting media files, directly in the browser.

639 lines 26.9 kB
/*! * 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