import * as stream from 'stream';
import { ChildProcessWithoutNullStreams } from 'node:child_process';
import { DuplexOptions, Duplex } from 'node:stream';

type FFmpegLib = 'ffmpeg' | './ffmpeg' | 'avconv' | './avconv' | 'ffmpeg-static' | '@ffmpeg-installer/ffmpeg' | '@node-ffmpeg/node-ffmpeg-installer' | 'ffmpeg-binaries';
type FFmpegCallback<Args extends Array<unknown>> = (...args: Args) => unknown;
/**
 * FFmpeg source configuration
 */
interface FFmpegSource {
    /** Name or path of the FFmpeg executable */
    name: FFmpegLib;
    /** Whether this source is a Node.js module */
    module: boolean;
}
interface ResolvedFFmpegSource extends FFmpegSource {
    path: string;
    version: string;
    command: string;
    result: string;
}
/**
 * Compares and updates FFmpeg flags as needed
 * @param oldFlags The old flags
 * @param newFlags The new flags
 * @returns The updated flags
 */
declare function changeFFmpegFlags(oldFlags: string[], newFlags: string[]): string[];

interface FFmpegOptions extends DuplexOptions {
    args?: string[];
    shell?: boolean;
}
declare class FFmpeg extends Duplex {
    /**
     * Cached FFmpeg source.
     */
    private static cached;
    /**
     * Supported FFmpeg sources.
     */
    static sources: FFmpegSource[];
    /**
     * Checks if FFmpeg is loaded.
     */
    static isLoaded(): boolean;
    /**
     * Adds a new FFmpeg source.
     * @param source FFmpeg source
     */
    static addSource(source: FFmpegSource): boolean;
    /**
     * Removes a FFmpeg source.
     * @param source FFmpeg source
     */
    static removeSource(source: FFmpegSource): boolean;
    /**
     * Resolves FFmpeg path. Throws an error if it fails to resolve.
     * @param force if it should relocate the command
     */
    static resolve(force?: boolean): ResolvedFFmpegSource;
    /**
     * Resolves FFmpeg path safely. Returns null if it fails to resolve.
     * @param force if it should relocate the command
     */
    static resolveSafe(force?: boolean): ResolvedFFmpegSource | null;
    /**
     * Spawns ffmpeg process
     * @param options Spawn options
     */
    static spawn({ args, shell }?: {
        args?: string[] | undefined;
        shell?: boolean | undefined;
    }): ChildProcessWithoutNullStreams;
    /**
     * Current FFmpeg process
     */
    process: ChildProcessWithoutNullStreams;
    /**
     * Create FFmpeg duplex stream
     * @param options Options to initialize ffmpeg
     * @example ```typescript
     * const ffmpeg = new FFmpeg({
     *   args: [
     *     '-analyzeduration', '0',
     *     '-loglevel', '0',
     *     '-f', 's16le',
     *     '-ar', '48000',
     *     '-ac', '2',
     *     '-af', 'bass=g=10,acompressor'
     *   ]
     * });
     *
     * const pcm = input.pipe(ffmpeg);
     *
     * pcm.pipe(fs.createWriteStream('./audio.pcm'));
     * ```
     */
    constructor(options?: FFmpegOptions);
    get _reader(): stream.Readable;
    get _writer(): stream.Writable;
    private _copy;
    _destroy(err: Error | null, cb: FFmpegCallback<[Error | null]>): unknown;
    _final(cb: FFmpegCallback<[]>): void;
    private _cleanup;
}

declare const version: string;

type ArgPrimitive = string | number | null;
/**
 * Create FFmpeg arguments from an object.
 * @param input The input object.
 * @param post Additional arguments to append.
 * @returns The FFmpeg arguments.
 * @example createFFmpegArgs({ i: 'input.mp3', af: ['bass=g=10','acompressor'] }, './out.mp3');
 * // => ['-i', 'input.mp3', '-af', 'bass=g=10,acompressor', './out.mp3']
 */
declare const createFFmpegArgs: (input: Record<string, ArgPrimitive | ArgPrimitive[]>, post?: string | string[]) => string[];

export { type ArgPrimitive, FFmpeg, type FFmpegCallback, type FFmpegLib, type FFmpegOptions, type FFmpegSource, type ResolvedFFmpegSource, changeFFmpegFlags, createFFmpegArgs, version };
