/*!
 * 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, VideoCodec } from './codec.js';
import { Quality } from './encode.js';
import { Input } from './input.js';
import { InputAudioTrack, InputTrack, InputVideoTrack } from './input-track.js';
import { MaybePromise, Rotation } from './misc.js';
import { Output, OutputTrackGroup } from './output.js';
import { AudioSample, CropRectangle, VideoSample, VideoSampleResource } from './sample.js';
import { MetadataTags } from './metadata.js';
/**
 * The options for media file conversion.
 * @group Conversion
 * @public
 */
export type ConversionOptions = {
    /** The input file. */
    input: Input;
    /** The output file. */
    output: Output;
    /**
     * Defines which input tracks are used for conversion. Defaults to `'all'` unless the input is an HLS input, in
     * which case it defaults to `'primary'`.
     *
     * - `'all'`: All input tracks are eligible for conversion.
     * - `'primary'`: Only the primary video and audio track from the input are eligible for conversion.
     */
    tracks?: 'all' | 'primary';
    /**
     * Video-specific options. When passing an object, the same options are applied to all video tracks. When passing a
     * function, it will be invoked for each video track and is expected to return or resolve to the options
     * for that specific track. The function is passed an instance of {@link InputVideoTrack} as well as a number `n`,
     * which is the 1-based index of the track in the list of all video tracks. Using `n` is deprecated, prefer the
     * identical `track.number` instead.
     *
     * When passing an array of a function that returns an array, one output track per array element will be created,
     * allowing for "fan-out". Useful for creating multiple variants from a single track, for example with different
     * resolutions.
     */
    video?: ConversionVideoOptions | ConversionVideoOptions[] | ((track: InputVideoTrack, n: number) => MaybePromise<ConversionVideoOptions | ConversionVideoOptions[] | undefined>);
    /**
     * Audio-specific options. When passing an object, the same options are applied to all audio tracks. When passing a
     * function, it will be invoked for each audio track and is expected to return or resolve to the options
     * for that specific track. The function is passed an instance of {@link InputAudioTrack} as well as a number `n`,
     * which is the 1-based index of the track in the list of all audio tracks. Using `n` is deprecated, prefer the
     * identical `track.number` instead.
     *
     * When passing an array of a function that returns an array, one output track per array element will be created,
     * allowing for "fan-out". Useful for creating multiple variants from a single track, for example with different
     * bitrates.
     */
    audio?: ConversionAudioOptions | ConversionAudioOptions[] | ((track: InputAudioTrack, n: number) => MaybePromise<ConversionAudioOptions | ConversionAudioOptions[] | undefined>);
    /** Options to trim the input file. */
    trim?: {
        /**
         * The time in the input file in seconds at which the output file should start. Must be less than `end`.
         * When omitted, defaults to the earliest start timestamp of the non-discarded tracks, or to 0, whichever
         * is higher.
         */
        start?: number;
        /**
         * The time in the input file in seconds at which the output file should end. Must be greater than `start`.
         * Defaults to the duration of the input when omitted.
         */
        end?: number;
    };
    /**
     * Options for controlling when media is copied directly without transcoding it. Set to `false` to always transcode.
     * Defaults to `{}`, which will copy media whenever possible and otherwise transcode it while retaining precise
     * timestamps.
     */
    copy?: ConversionCopyOptions | false;
    /**
     * An object or a callback that returns or resolves to an object containing the descriptive metadata tags that
     * should be written to the output file. If a function is passed, it will be passed the tags of the input file as
     * its first argument, allowing you to modify, augment or extend them.
     *
     * If no function is set, the input's metadata tags will be copied to the output.
     */
    tags?: MetadataTags | ((inputTags: MetadataTags) => MaybePromise<MetadataTags>);
    /**
     * Whether to show potential console warnings about discarded tracks after calling `Conversion.init()`, defaults to
     * `true`. Set this to `false` if you're properly handling the `discardedTracks` and `isValid` fields already and
     * want to keep the console output clean.
     */
    showWarnings?: boolean;
    /**
     * Whether this conversion is composable, defaults to `false`. A non-composable conversion takes full ownership of
     * the output: it requires a fresh output and controls its entire lifecycle, meaning it starts it, writes its
     * metadata tags, and finalizes it.
     *
     * A composable conversion only adds tracks to the output and drives their media data; starting and finalizing
     * the output is an outside responsibility. This is useful when only some output tracks should be driven by a
     * conversion, and other are to be driven manually. Additionally, it can be used to have multiple conversions target
     * the same output.
     */
    composable?: boolean;
};
/**
 * Video-specific options.
 * @group Conversion
 * @public
 */
export type ConversionVideoOptions = {
    /** If `true`, all video tracks will be discarded and will not be present in the output. */
    discard?: boolean;
    /**
     * The desired width of the output video in pixels, defaulting to the video's natural display width. If height
     * is not set, it will be deduced automatically based on aspect ratio.
     */
    width?: number;
    /**
     * The desired height of the output video in pixels, defaulting to the video's natural display height. If width
     * is not set, it will be deduced automatically based on aspect ratio.
     */
    height?: number;
    /**
     * The fitting algorithm in case both width and height are set, or if the input video changes its size over time.
     *
     * - `'fill'` will stretch the image to fill the entire box, potentially altering aspect ratio.
     * - `'contain'` will contain the entire image within the box while preserving aspect ratio. This may lead to
     * letterboxing.
     * - `'cover'` will scale the image until the entire box is filled, while preserving aspect ratio.
     */
    fit?: 'fill' | 'contain' | 'cover';
    /**
     * The angle in degrees to rotate the input video by, clockwise. Rotation is applied before flipping, cropping and
     * resizing. This rotation is _in addition to_ the natural rotation of the input video as specified in input file's
     * metadata.
     */
    rotate?: Rotation;
    /**
     * Whether to flip the input video horizontally (about the vertical axis). The flip is applied after rotation but
     * before cropping and resizing. This flip is _in addition to_ the natural flip of the input video as specified in
     * the input file's metadata.
     */
    flip?: boolean;
    /**
     * Defaults to `true`. When enabled, Mediabunny will use the rotation and flip metadata in the output file to
     * perform video rotation and flipping whenever possible. Set this field to `false` if you want to ensure the output
     * file does not make use of such metadata and that any rotation and flip is baked into the video frames directly.
     */
    allowTransformationMetadata?: boolean;
    /**
     * Defaults to `true`. When enabled, Mediabunny will use the rotation metadata in the output file to perform video
     * rotation whenever possible.
     * @deprecated Use {@link ConversionVideoOptions.allowTransformationMetadata} instead.
     */
    allowRotationMetadata?: boolean;
    /**
     * Specifies the rectangular region of the input video to crop to. The crop region will automatically be clamped to
     * the dimensions of the input video track. Cropping is performed after rotation and flip but before resizing.
     */
    crop?: CropRectangle;
    /**
     * The desired frame rate of the output video, in hertz. If not specified, the original input frame rate will
     * be used (which may be variable).
     */
    frameRate?: number;
    /** The desired output video codec. */
    codec?: VideoCodec;
    /** The desired quality of the output video. */
    quality?: Quality;
    /**
     * The desired bitrate of the output video.
     * @deprecated Use `quality` instead.
     */
    bitrate?: number | Quality;
    /**
     * Whether to discard or keep the transparency information of the input video. The default is `'discard'`. Note that
     * for `'keep'` to produce a transparent video, you must use an output config that supports it, such as WebM with
     * VP9.
     */
    alpha?: 'discard' | 'keep';
    /**
     * The interval, in seconds, of how often frames are encoded as a key frame. The default is 5 seconds. Frequent key
     * frames improve seeking behavior but increase file size. When using multiple video tracks, you should give them
     * all the same key frame interval.
     *
     * Setting this fields forces a transcode.
     */
    keyFrameInterval?: number;
    /**
     * A hint that configures the hardware acceleration method used when transcoding. This is best left on
     * `'no-preference'`, the default.
     */
    hardwareAcceleration?: 'no-preference' | 'prefer-hardware' | 'prefer-software';
    /** When `true`, video will always be re-encoded instead of directly copying over the encoded packets. */
    forceTranscode?: boolean;
    /**
     * Allows for custom user-defined processing of video frames, e.g. for applying overlays, color transformations, or
     * timestamp modifications. Will be called for each input video sample after transformations and frame rate
     * corrections.
     *
     * Must return a {@link VideoSample}, a {@link VideoSampleResource} or a `CanvasImageSource`, an array of them, or
     * `null` for dropping the frame. When non-timestamped data is returned, the timestamp and duration from the source
     * sample will be used. Rotation and flip metadata of the returned sample will be ignored.
     *
     * This function can also be used to manually resize frames. When doing so, you should signal the post-process
     * dimensions using the `processedWidth` and `processedHeight` fields, which enables the encoder to better know what
     * to expect. If these fields aren't set, Mediabunny will assume you won't perform any resizing.
     */
    process?: (sample: VideoSample) => MaybePromise<CanvasImageSource | VideoSample | VideoSampleResource | (CanvasImageSource | VideoSample | VideoSampleResource)[] | null>;
    /**
     * An optional hint specifying the width of video samples returned by the `process` function, for better
     * encoder configuration.
     */
    processedWidth?: number;
    /**
     * An optional hint specifying the height of video samples returned by the `process` function, for better
     * encoder configuration.
     */
    processedHeight?: number;
    /**
     * Defines the group(s) the output track is a part of. For more, see {@link BaseTrackMetadata.group}.
     *
     * If left blank, tracks will internally be assigned to groups such that the output track pairability graph exactly
     * matches the input track pairability graph.
     */
    group?: OutputTrackGroup | OutputTrackGroup[];
};
/**
 * Audio-specific options.
 * @group Conversion
 * @public
 */
export type ConversionAudioOptions = {
    /** If `true`, all audio tracks will be discarded and will not be present in the output. */
    discard?: boolean;
    /** The desired channel count of the output audio. */
    numberOfChannels?: number;
    /** The desired sample rate of the output audio, in hertz. */
    sampleRate?: number;
    /**
     * The desired sample format (and therefore bit depth) of the audio samples before they are passed to the encoder.
     * Can be used to control bit depth with certain output codecs such as FLAC.
     *
     * Setting this field forces audio transcoding.
     */
    sampleFormat?: 'u8' | 's16' | 's32' | 'f32';
    /** The desired output audio codec. */
    codec?: AudioCodec;
    /** The desired quality of the output audio. */
    quality?: Quality;
    /**
     * The desired bitrate of the output audio.
     * @deprecated Use `quality` instead.
     */
    bitrate?: number | Quality;
    /** When `true`, audio will always be re-encoded instead of directly copying over the encoded packets. */
    forceTranscode?: boolean;
    /**
     * Allows for custom user-defined processing of audio samples, e.g. for applying audio effects, transformations, or
     * timestamp modifications. Will be called for each input audio sample after remixing and resampling.
     *
     * Must return an {@link AudioSample}, an array of them, or `null` for dropping the sample.
     *
     * This function can also be used to manually perform remixing or resampling. When doing so, you should signal the
     * post-process parameters using the `processedNumberOfChannels` and `processedSampleRate` fields, which enables the
     * encoder to better know what to expect. If these fields aren't set, Mediabunny will assume you won't perform
     * remixing or resampling.
     */
    process?: (sample: AudioSample) => MaybePromise<AudioSample | AudioSample[] | null>;
    /**
     * An optional hint specifying the channel count of audio samples returned by the `process` function, for better
     * encoder configuration.
     */
    processedNumberOfChannels?: number;
    /**
     * An optional hint specifying the sample rate of audio samples returned by the `process` function, for better
     * encoder configuration.
     */
    processedSampleRate?: number;
    /**
     * Defines the group(s) the output track is a part of. For more, see {@link BaseTrackMetadata.group}.
     *
     * If left blank, tracks will internally be assigned to groups such that the output track pairability graph exactly
     * matches the input track pairability graph.
     */
    group?: OutputTrackGroup | OutputTrackGroup[];
};
/**
 * Options for copying encoded media during conversion.
 * @group Conversion
 * @public
 */
export type ConversionCopyOptions = {
    /**
     * Controls whether media copying is preferred or required. Defaults to `'preferred'`.
     *
     * - `'forced'`: Copy encoded media where possible and discard tracks that cannot possibly be copied.
     * - `'preferred'`: Copy encoded media when possible, and transcode tracks that cannot be copied.
     */
    mode?: 'forced' | 'preferred';
    /**
     * The maximum absolute shift, in seconds, that may be applied to the media to be able to copy it into the output
     * format. Defaults to `0`, which permits no additional shift. Set to `Infinity` to permit any shift.
     *
     * A shift of `0` gives you perfect _timeline sync_: output timestamps will match input timestamps exactly (only
     * offset by the trim region). Any non-zero shift will break this property but will still, under all circumstances,
     * maintain perfect cross-track and audio-video sync.
     */
    shiftTolerance?: number;
    /**
     * Controls which media region will be copied to satisfy the requested trim range. Defaults to `'expand'`.
     *
     * - `'expand'`: Include at least all media in the requested range. This may require expanding the media region due
     * to key frames and packet boundaries, and thus may include media outside of your trim range. The region is always
     * minimally expanded to satisfy the copy criteria.
     * - `'shrink'`: Only include media that lies entirely within the requested trim range. This may require shrinking
     * the media region due to key frames and packet boundaries, and thus may exclude media inside of your trim range.
     * The region is always minimally shrunk to satisfy the copy criteria.
     *
     * Use `expand` if you don't want to lose any media; use `shrink` to never expose any media outside of the
     * trim region.
     */
    boundaryPolicy?: 'expand' | 'shrink';
    /**
     * The maximum amount, in seconds, by which the copied media region may deviate from the requested trim range at
     * its start, as caused by {@link ConversionCopyOptions.boundaryPolicy}. Defaults to `Infinity`, which permits any
     * deviation.
     *
     * In other words, this field sets how many seconds of media the conversion is allowed to add/remove to make a copy
     * path possible.
     */
    boundaryTolerance?: number;
};
/**
 * An input track that was discarded (excluded) from a {@link Conversion} alongside the discard reason.
 * @group Conversion
 * @public
 */
export type DiscardedTrack = {
    /** The track that was discarded. */
    track: InputTrack;
    /**
     * The reason for discarding the track.
     *
     * - `'discarded_by_user'`: You discarded this track by setting `discard: true`.
     * - `'max_track_count_reached'`: The output had no more room for another track.
     * - `'max_track_count_of_type_reached'`: The output had no more room for another track of this type, or the output
     * doesn't support this track type at all.
     * - `'unknown_source_codec'`: We don't know the codec of the input track and therefore don't know what to do
     * with it.
     * - `'undecodable_source_codec'`: The input track's codec is known, but we are unable to decode it.
     * - `'no_encodable_target_codec'`: We can't find a codec that we are able to encode and that can be contained
     * within the output format. This reason can be hit if the environment doesn't support the necessary encoders, or if
     * you requested a codec that cannot be contained within the output format.
     * - `'cannot_copy'`: {@link ConversionCopyOptions.mode} was set to `'forced'` but the track could not be copied
     * with the given copy configuration because it would require a transcode instead.
     */
    reason: 'discarded_by_user' | 'max_track_count_reached' | 'max_track_count_of_type_reached' | 'unknown_source_codec' | 'undecodable_source_codec' | 'no_encodable_target_codec' | 'cannot_copy';
    /** The options that were provided for this track, or `{}` if none were provided. */
    trackOptions: ConversionVideoOptions | ConversionAudioOptions;
};
/**
 * Options for controlling a single call to {@link Conversion.execute}.
 * @group Conversion
 * @public
 */
export type ConversionExecuteOptions = {
    /**
     * The timestamp in seconds, in the output's timescale, until which the conversion should advance. Defaults to
     * `Infinity`, meaning the conversion runs until the end.
     *
     * This field is especially useful for composable conversions, as it allows you to advance the conversion in
     * lockstep with other media data sources.
     */
    until?: number;
    /**
     * A signal that, when triggered, pauses the conversion as soon as possible.
     */
    pauseSignal?: AbortSignal;
};
/**
 * Represents a media file conversion process, used to convert one media file into another. In addition to conversion,
 * this class can be used to resize and rotate video, resample audio, drop tracks, or trim to a specific time range.
 * @group Conversion
 * @public
 */
export declare class Conversion {
    /** The input file. */
    readonly input: Input;
    /** The output file. */
    readonly output: Output;
    /**
     * A callback that is fired whenever the conversion progresses. Gets passed as first argument a number between
     * 0 and 1, indicating the completion of the conversion. Note that a progress of 1 doesn't necessarily mean the
     * conversion is complete; the conversion is complete once `execute()` resolves.
     *
     * As second argument, this callback receives the input time in seconds that has been processed.
     *
     * In order for progress to be computed, this property must be set before `execute` is called.
     */
    onProgress?: (progress: number, processedTime: number) => unknown;
    /**
     * Whether this conversion, as it has been configured, is valid and can be executed. If this field is `false`, check
     * the `discardedTracks` field for reasons. Composable conversions are always valid, even if they utilize
     * zero tracks.
     *
     * Note: a conversion having discarded tracks does not automatically mean it is invalid; if the remaining, utilized
     * tracks make for a valid output file, the conversion is still allowed.
     */
    isValid: boolean;
    /**
     * The list of tracks that are included in the output file. When fan-out is used, the same track appears in this
     * array multiple times.
     */
    readonly utilizedTracks: InputTrack[];
    /** The list of tracks from the input file that have been discarded, alongside the discard reason. */
    readonly discardedTracks: DiscardedTrack[];
    /**
     * The current state of the conversion.
     *
     * - `'idle'`: The conversion is not currently executing and isn't done; `execute` can be called.
     * - `'executing'`: A call to `execute` is currently running.
     * - `'canceled'`: The conversion has been canceled and can no longer be executed.
     * - `'done'`: The conversion has run to completion. Subsequent calls to `execute` do nothing.
     */
    get state(): "done" | "canceled" | "idle" | "executing";
    /** Initializes a new conversion process without starting the conversion. */
    static init(options: ConversionOptions): Promise<Conversion>;
    /** Creates a new Conversion instance (duh). */
    private constructor();
    /**
     * Executes the conversion process and resolves when the conversion is complete. When
     * {@link ConversionExecuteOptions.until} is provided, the conversion will be suspended once that output timestamp
     * is reached and can be resumed with another call to `execute`. An ongoing execution may also be suspended via
     * {@link ConversionExecuteOptions.pauseSignal}.
     *
     * Execution will throw if `isValid` is `false`.
     */
    execute(options?: ConversionExecuteOptions): Promise<void>;
    /**
     * Cancels the conversion process, causing any ongoing `execute` call to throw a `ConversionCanceledError`.
     * Does nothing if the conversion is already complete.
     */
    cancel(): Promise<void>;
}
/**
 * Thrown when a conversion couldn't complete due to being canceled.
 * @group Conversion
 * @public
 */
export declare class ConversionCanceledError extends Error {
    /** Creates a new {@link ConversionCanceledError}. */
    constructor(message?: string);
}
//# sourceMappingURL=conversion.d.ts.map