@fly-cut/av-cliper
Version:
WebCodecs-based, combine video, audio, images, text, with animation support 基于 WebCodecs 合成 视频、音频、图片、文字,支持动画
903 lines (857 loc) • 26.7 kB
TypeScript
import { file } from 'opfs-tools';
import { Log } from '@fly-cut/internal-utils';
import { MP4Sample } from '@webav/mp4box.js';
declare type AnimateImgType = 'avif' | 'webp' | 'png' | 'gif';
/**
* 音频素材,为创建、编辑音视频功能提供音频数据
*
* @example
* new AudioClip((await fetch('<mp3 url>')).body, {
* loop: true,
* }),
*/
export declare class AudioClip implements IClip {
#private;
static ctx: AudioContext | null;
ready: IClip['ready'];
/**
* 音频元信息
*
* ⚠️ 注意,这里是转换后(标准化)的元信息,非原始音频元信息
*/
get meta(): {
sampleRate: 48000;
chanCount: number;
duration: number;
width: number;
height: number;
};
/**
* 获取音频素材完整的 PCM 数据
*/
getPCMData(): Float32Array[];
/**
*
* @param dataSource 音频文件流
* @param opts 音频配置,控制音量、是否循环
*/
constructor(dataSource: ReadableStream<Uint8Array> | Float32Array[], opts?: IAudioClipOpts);
setVolume(newVolume: number): void;
getVolume(): number;
/**
* 拦截 {@link AudioClip.tick} 方法返回的数据,用于对音频数据二次处理
* @param time 调用 tick 的时间
* @param tickRet tick 返回的数据
*
* @see [移除视频绿幕背景](https://webav-tech.github.io/WebAV/demo/3_2-chromakey-video)
*/
tickInterceptor: <T extends Awaited<ReturnType<AudioClip['tick']>>>(time: number, tickRet: T) => Promise<T>;
/**
* 返回上次与当前时刻差对应的音频 PCM 数据;
*
* 若差值超过 3s 或当前时间小于上次时间,则重置状态
* @example
* tick(0) // => []
* tick(1e6) // => [leftChanPCM(1s), rightChanPCM(1s)]
*
*/
tick(time: number): Promise<{
audio: Float32Array[];
state: 'success' | 'done';
}>;
/**
* 按指定时间切割,返回前后两个音频素材
* @param time 时间,单位微秒
*/
split(time: number): Promise<[this, this]>;
clone(): Promise<this>;
/**
* 销毁实例,释放资源
*/
destroy(): void;
}
/**
* Sprite 基类
*
* @see {@link OffscreenSprite}
* @see {@link VisibleSprite}
*/
declare abstract class BaseSprite {
#private;
/**
* 控制素材在视频中的空间属性(坐标、旋转、缩放)
*/
rect: Rect;
get time(): {
offset: number;
duration: number;
playbackRate: number;
};
set time(v: {
offset: number;
duration: number;
playbackRate?: number;
});
/**
* 监听属性变更事件
* @example
* sprite.on('propsChange', (changedProps) => {})
*/
on: <Type extends "propsChange">(type: Type, listener: {
propsChange: (value: Partial<{
rect: Partial<Rect>;
zIndex: number;
}>) => void;
}[Type]) => (() => void);
get zIndex(): number;
/**
* 控制素材间的层级关系,zIndex 值较小的素材会被遮挡
*/
set zIndex(v: number);
/**
* 不透明度
*/
opacity: number;
/**
* 水平或垂直方向翻转素材
*/
flip: 'horizontal' | 'vertical' | null;
/**
* @see {@link IClip.ready}
*/
ready: Promise<void>;
constructor();
protected _render(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, anchor: {
x: number;
y: number;
}): void;
/**
* 给素材添加动画,使用方法参考 css animation
*
* @example
* sprite.setAnimation(
* {
* '0%': { x: 0, y: 0 },
* '25%': { x: 1200, y: 680 },
* '50%': { x: 1200, y: 0 },
* '75%': { x: 0, y: 680 },
* '100%': { x: 0, y: 0 },
* },
* { duration: 4e6, iterCount: 1 },
* );
*
* @see [视频水印动画](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)
*/
setAnimation(keyFrame: TKeyFrameOpts, opts: IAnimationOpts): void;
/**
* 如果当前 sprite 已被设置动画,将 sprite 的动画属性设定到指定时间的状态
*/
animate(time: number): void;
/**
* 将当前 sprite 的属性赋值到目标
*
* 用于 clone,或 {@link VisibleSprite} 与 {@link OffscreenSprite} 实例间的类型转换
*/
copyStateTo<T extends BaseSprite>(target: T): void;
protected destroy(): void;
}
/**
* 视频合成器;能添加多个 {@link OffscreenSprite},根据它们位置、层级、时间偏移等信息,合成输出为视频文件
* @see [视频合成](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)
* @see [视频配音](https://webav-tech.github.io/WebAV/demo/2_2-video-add-audio)
* @example
* const spr1 = new OffscreenSprite(
* new MP4Clip((await fetch('<mp4 url>')).body),
* );
* const spr2 = new OffscreenSprite(
* new AudioClip((await fetch('<audio url>')).body),
* );
* const com = new Combinator({ width: 1280, height: 720, });
* await com.addSprite(spr1);
* await com.addSprite(spr2);
* com.output(); // => ReadableStream
*
*/
export declare class Combinator {
#private;
/**
* 检测当前环境的兼容性
* @param args.videoCodec 指定视频编码格式,默认 avc1.42E032
* @param args.width 指定视频宽度,默认 1920
* @param args.height 指定视频高度,默认 1080
* @param args.bitrate 指定视频比特率,默认 5e6
*/
static isSupported(args?: {
videoCodec?: string;
width?: number;
height?: number;
bitrate?: number;
}): Promise<boolean>;
on: <Type extends "OutputProgress" | "error">(type: Type, listener: {
OutputProgress: (progress: number) => void;
error: (err: Error) => void;
}[Type]) => (() => void);
/**
* 根据配置创建合成器实例
* @param opts ICombinatorOpts
*/
constructor(opts?: ICombinatorOpts);
/**
* 添加用于合成视频的 Sprite,视频时长默认取所有素材 duration 字段的最大值
* @param os Sprite
* @param opts.main 如果 main 为 true,视频时长为该素材的 duration 值
*/
addSprite(os: OffscreenSprite, opts?: {
main?: boolean;
}): Promise<void>;
/**
* 输出视频文件二进制流
*/
output(): ReadableStream<Uint8Array>;
/**
* 销毁实例,释放资源
*/
destroy(): void;
}
/**
* 绿幕抠图
* keyColor 需要扣除的背景色,若不传则取第一个像素点
* similarity 背景色相似度阈值,过小可能保留背景色,过大可能扣掉更多非背景像素点
* smoothness 平滑度;过小可能出现锯齿,过大导致整体变透明
* spill 饱和度;过小可能保留绿色混合,过大导致图片变灰度
* @param opts: {
* keyColor?: [r, g, b]
* similarity: number
* smoothness: number
* spill: number
* }
*/
export declare const createChromakey: (opts: Omit<IChromakeyOpts, "keyColor"> & {
keyColor?: [number, number, number];
}) => (imgSource: TImgSource) => Promise<ImageBitmap | VideoFrame>;
/**
* 嵌入式字幕,将字幕(目前仅支持 SRT 格式)嵌入视频画面中
*/
export declare class EmbedSubtitlesClip implements IClip {
#private;
ready: IClip['ready'];
get meta(): {
width: number;
height: number;
duration: number;
};
constructor(content: string | SubtitleStruct[], opts: IEmbedSubtitlesOpts);
/**
* 更新字幕样式
*/
setStyle(style: Partial<ITextStyle>): void;
/**
* @see {@link IClip.tick}
*/
tick(time: number): Promise<{
video?: VideoFrame;
audio?: Float32Array[];
state: 'success' | 'done';
}>;
/**
* @see {@link IClip.split}
*/
split(time: number): Promise<[this, this]>;
/**
* @see {@link IClip.clone}
*/
clone(): Promise<this>;
/**
* 通过时间戳,修改字幕内容
*/
updateSubtitle(subtitle: SubtitleStruct): void;
/**
* 删除指定的字幕并更新后续字幕的时间戳
*/
deleteSubtitle(subtitle: SubtitleStruct): SubtitleStruct[];
/**
* @see {@link IClip.destroy}
*/
destroy(): void;
}
declare type ExtMP4Sample = Omit<MP4Sample, 'data'> & {
is_idr: boolean;
deleted?: boolean;
data: null | Uint8Array;
};
/**
* 快速拼接多个mp4 文件流,要求所有 mp4 的属性一致,
* 属性包括(不限于):音视频编码格式、分辨率、采样率
*
* @param streams 一个包含 Uint8Array 的可读流数组。
* @returns 返回一个 Promise,该 Promise 在解析时返回一个包含合并后的 MP4 数据的可读流。
* @throws 如果无法从流生成文件,将抛出错误。
*
* @example
* const streams = [stream1, stream2, stream3];
* const resultStream = await fastConcatMP4(streams);
*/
export declare function fastConcatMP4(streams: ReadableStream<Uint8Array>[]): Promise<ReadableStream<Uint8Array>>;
/**
* 为 WebAV 生成的 fmp4 文件设置正确的时长值
*/
export declare function fixFMP4Duration(stream: ReadableStream<Uint8Array>): Promise<ReadableStream<Uint8Array>>;
declare interface IAnimationOpts {
duration: number;
delay?: number;
iterCount?: number;
}
declare interface IAudioClipOpts {
loop?: boolean;
volume?: number;
}
declare interface IChromakeyOpts {
keyColor: [number, number, number];
similarity: number;
smoothness: number;
spill: number;
}
/**
* 所有素材需要实现的接口
*
* 素材(Clip)是不同数据类型的抽象,给其他模块提供数据
*
* WebAV 内置了 {@link MP4Clip}, {@link AudioClip}, {@link ImgClip}, {@link MediaStreamClip} 等常用素材,用于给 {@link Combinator} {@link AVCanvas} 提供数据
*
* 你只需实现该接口即可自定义素材,拥有最大的灵活度来生成视频内容,比如动画、转场效果等
* @see [自定义素材](https://webav-tech.github.io/WebAV/demo/2_6-custom-clip)
*
*/
export declare interface IClip {
/**
* 从素材中提取指定时间数据
* @param time 时间,单位 微秒
*/
tick: (time: number) => Promise<{
video?: VideoFrame | ImageBitmap | null;
audio?: Float32Array[];
state: 'done' | 'success';
}>;
/**
* 当素材准备完成,ready 会切换到 resolved 状态
*/
readonly ready: Promise<IClipMeta>;
/**
* 数据元数据
*/
readonly meta: IClipMeta;
/**
* clone,返回一个新素材
*/
clone: () => Promise<this>;
/**
* 按指定时间切割,返回该时刻前后两个新素材,常用于剪辑场景按时间分割素材
*
* 该方法不会破坏原素材的数据
*
* @param time 时间,微秒
* @returns
*/
split?: (time: number) => Promise<[this, this]>;
/**
* 销毁实例,释放资源
*/
destroy: () => void;
}
declare interface IClipMeta {
width: number;
height: number;
duration: number;
}
export declare interface ICombinatorOpts {
width?: number;
height?: number;
bitrate?: number;
fps?: number;
bgColor?: string;
videoCodec?: string;
/**
* false 合成的视频文件中排除音轨
*/
audio?: false;
/**
* 向输出的视频中写入 meta tags 数据
*/
metaDataTags?: Record<string, string>;
/**
* 不安全,随时可能废弃
*/
__unsafe_hardwareAcceleration__?: HardwarePreference;
}
declare interface IEmbedSubtitlesOpts {
type?: 'srt';
width: number;
height: number;
style?: Partial<ITextStyle>;
}
/**
* 图像素材,支持动图
*
* 普通文字可通过 {@link renderTxt2ImgBitmap} 转换成图片素材
*
* @example
* new ImgClip((await fetch('<img url>')).body);
*
* @example
* new ImgClip(
* await renderTxt2ImgBitmap(
* '水印',
* `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`,
* )
* )
*
* @see [视频合成](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)
*/
export declare class ImgClip implements IClip {
#private;
ready: IClip['ready'];
/**
* ⚠️ 静态图片的 duration 为 Infinity
*
* 使用 Sprite 包装时需要将它的 duration 设置为有限数
*
*/
get meta(): {
duration: number;
width: number;
height: number;
};
/**
* 静态图片可使用流、ImageBitmap 初始化
*
* 动图需要使用 VideoFrame[] 或提供图片类型
*/
constructor(dataSource: ReadableStream | ImageBitmap | VideoFrame[] | {
type: `image/${AnimateImgType}`;
stream: ReadableStream;
});
tickInterceptor: <T extends Awaited<ReturnType<ImgClip['tick']>>>(time: number, tickRet: T) => Promise<T>;
tick(time: number): Promise<{
video: ImageBitmap | VideoFrame;
state: 'success';
}>;
split(time: number): Promise<[this, this]>;
clone(): Promise<this>;
destroy(): void;
}
declare interface IPoint {
x: number;
y: number;
}
declare interface IRectBaseProps {
x: number;
y: number;
w: number;
h: number;
angle: number;
}
declare interface ITextClipOpts {
type: 'text';
source: string;
x?: number;
y: number;
text: string;
style: ITextStyle;
}
declare interface ITextStyle {
fontSize: number;
fontFamily: string;
fontWeight: string;
fontColor: string;
fontStyle: 'italic' | 'underline' | 'bold' | string;
textAlign: 'left' | 'center' | 'right';
letterSpacing: number;
lineHeight: number;
stroke?: string;
strokeWidth?: number;
shadow?: boolean;
shadowColor?: string;
shadowBlur?: number;
shadowAngle?: number;
shadowDistance?: number;
padding: number | {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
wordWrapWidth?: number;
backgroundColor?: string;
breakWords?: boolean;
}
export { Log }
/**
* 包装实时音视频流,仅用于 [AVCanvas](../../av-canvas/classes/AVCanvas.html)
*
* ⚠️ 不可用于 {@link Combinator} ,因为后台合成视频的速度是快于物理时间的,实时流无法提供非实时的数据
*
* @example
* const spr = new VisibleSprite(
* new MediaStreamClip(
* await navigator.mediaDevices.getUserMedia({ video: true, audio: true, }),
* ),
* );
* await avCvs.addSprite(spr);
*/
export declare class MediaStreamClip implements IClip {
#private;
static ctx: AudioContext | null;
ready: IClip['ready'];
get meta(): {
duration: number;
width: number;
height: number;
};
/**
* 实时流的音轨
*/
readonly audioTrack: MediaStreamAudioTrack | null;
constructor(ms: MediaStream);
tick(): Promise<{
video: ImageBitmap | null;
audio: Float32Array[];
state: 'success';
}>;
split(): Promise<[this, this]>;
clone(): Promise<this>;
destroy(): void;
}
/**
* 视频配音;混合 MP4 与音频文件,仅重编码音频,视频轨道不变
* @param mp4Stream - MP4 流
* @param audio - 音频信息
* @param audio.stream - 音频数据流
* @param audio.volume - 音频音量
* @param audio.loop - 音频时长小于视频时,是否循环使用音频流
* @returns 输出混合后的音频流
*/
export declare function mixinMP4AndAudio(mp4Stream: ReadableStream<Uint8Array>, audio: {
stream: ReadableStream<Uint8Array>;
volume: number;
loop: boolean;
}): ReadableStream<Uint8Array>;
/**
* MP4 素材,解析 MP4 文件,使用 {@link MP4Clip.tick} 按需解码指定时间的图像帧
*
* 可用于实现视频抽帧、生成缩略图、视频编辑等功能
*
* @example
* new MP4Clip((await fetch('<mp4 url>')).body)
* new MP4Clip(mp4File.stream())
*
* @see {@link Combinator}
* @see [AVCanvas](../../av-canvas/classes/AVCanvas.html)
*
* @see [解码播放视频](https://webav-tech.github.io/WebAV/demo/1_1-decode-video)
*/
export declare class MP4Clip implements IClip {
#private;
ready: IClip['ready'];
get meta(): {
duration: number;
width: number;
height: number;
audioSampleRate: number;
audioChanCount: number;
};
/**
* 提供视频头(box: ftyp, moov)的二进制数据
* 使用任意 mp4 demxer 解析即可获得详细的视频信息
* 单元测试包含使用 mp4box.js 解析示例代码
*/
getFileHeaderBinData(): Promise<ArrayBuffer>;
constructor(source: OPFSToolFile | ReadableStream<Uint8Array> | MPClipCloneArgs, opts?: MP4ClipOpts);
/**
* 拦截 {@link MP4Clip.tick} 方法返回的数据,用于对图像、音频数据二次处理
* @param time 调用 tick 的时间
* @param tickRet tick 返回的数据
*
* @see [移除视频绿幕背景](https://webav-tech.github.io/WebAV/demo/3_2-chromakey-video)
*/
tickInterceptor: <T extends Awaited<ReturnType<MP4Clip['tick']>>>(time: number, tickRet: T) => Promise<T>;
/**
* 获取素材指定时刻的图像帧、音频数据
* @param time 微秒
*/
tick(time: number): Promise<{
video?: VideoFrame;
audio: Float32Array[];
state: 'success' | 'done';
}>;
/**
* 生成缩略图,默认每个关键帧生成一个 100px 宽度的缩略图。
*
* @param imgWidth 缩略图宽度,默认 100
* @param opts Partial<ThumbnailOpts>
* @returns Promise<Array<{ ts: number; img: Blob }>>
*/
thumbnails(imgWidth?: number, opts?: Partial<ThumbnailOpts>): Promise<Array<{
ts: number;
img: Blob;
}>>;
split(time: number): Promise<[this, this]>;
removeSegment(startTime: number, endTime: number): Promise<MP4Clip>;
setVolume(newVolume: number): void;
getVolume(): number;
clone(): Promise<this>;
/**
* 拆分 MP4Clip 为仅包含视频轨道和音频轨道的 MP4Clip
* @returns Mp4CLip[]
*/
splitTrack(): Promise<MP4Clip[]>;
destroy(): void;
}
declare interface MP4ClipOpts {
audio?: boolean | {
volume: number;
};
/**
* 不安全,随时可能废弃
*/
__unsafe_hardwareAcceleration__?: HardwarePreference;
}
declare interface MP4DecoderConf {
video: VideoDecoderConfig | null;
audio: AudioDecoderConfig | null;
}
declare function mp4FileToSamples(otFile: OPFSToolFile, opts?: MP4ClipOpts): Promise<{
videoSamples: ExtMP4Sample[];
audioSamples: ExtMP4Sample[];
decoderConf: MP4DecoderConf;
headerBoxPos: {
start: number;
size: number;
}[];
}>;
declare type MPClipCloneArgs = Awaited<ReturnType<typeof mp4FileToSamples>> & {
localFile: OPFSToolFile;
};
/**
* 包装 {@link IClip} 给素材扩展坐标、层级、透明度等信息,用于 {@link Combinator} 在后台合成视频
*
* 跟 {@link VisibleSprite} 非常相似,应用场景不同
*
* @example
* const spr = new OffscreenSprite(
* new MP4Clip((await fetch('<mp4 url>')).body),
* );
* spr.opacity = 0.5 // 半透明
* spr.rect.x = 100 // x 坐标偏移 100 像素
* spr.time.offset = 10e6 // 视频第 10s 开始绘制该视频素材
*
* @see [视频合成](https://webav-tech.github.io/WebAV/demo/2_1-concat-video)
*/
export declare class OffscreenSprite extends BaseSprite {
#private;
constructor(clip: IClip);
/**
* 绘制素材指定时刻的图像到 canvas 上下文,并返回对应的音频数据
* @param time 指定时刻,微秒
*/
offscreenRender(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, time: number): Promise<{
audio: Float32Array[];
done: boolean;
}>;
clone(): Promise<OffscreenSprite>;
destroy(): void;
}
declare type OPFSToolFile = ReturnType<typeof file>;
/**
* 用于记录素材在视频或画布中的空间属性:位置、大小、旋转
*
* 并提供控制点位置,支持用户在画布中缩放、旋转素材
*
* 一般由内部 WebAV SDK 内部创建维护
*
* @see {@link Combinator}, {@link OffscreenSprite}
* @see [AVCanvas](../../av-canvas/classes/AVCanvas.html), {@link VisibleSprite}
*
* @see [视频剪辑](https://webav-tech.github.io/WebAV/demo/6_4-video-editor)
*/
export declare class Rect implements IRectBaseProps {
#private;
/**
* 监听属性变更事件
* @example
* rect.on('propsChange', (changedProps) => {})
*/
on: <Type extends "propsChange">(type: Type, listener: {
propsChange: (props: Partial<IRectBaseProps>) => void;
}[Type]) => (() => void);
/**
* x 坐标
*/
get x(): number;
set x(v: number);
get y(): number;
/**
* y 坐标
*/
set y(v: number);
/**
* 宽
*/
get w(): number;
set w(v: number);
/**
* 高
*/
get h(): number;
set h(v: number);
/**
* 旋转角度
* @see [MDN Canvas rotate](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/rotate)
*/
get angle(): number;
set angle(v: number);
constructor(x?: number, y?: number, w?: number, h?: number, master?: Rect | null);
/**
* 根据坐标、宽高计算出来的矩形中心点
*/
get center(): IPoint;
/**
* 是否保持固定宽高比例,禁止变形缩放
*
* 值为 true 时,将缺少上下左右四个控制点
*/
fixedAspectRatio: boolean;
/**
* 是否固定中心点进行缩放
* 值为 true 时,固定中心点不变进行缩放
* 值为 false 时,固定对角点不变进行缩放
*/
fixedScaleCenter: boolean;
clone(): Rect;
/**
* 检测目标坐标是否命中当前实例
* @param tx 目标点 x 坐标
* @param ty 目标点 y 坐标
*/
checkHit(tx: number, ty: number): boolean;
}
/**
* 将文本渲染为 {@link ImageBitmap},用来创建 {@link ImgClip}
* @param txt - 要渲染的文本
* @param cssText - 应用于文本的 CSS 样式
*
* @example
* new ImgClip(
* await renderTxt2ImgBitmap(
* '水印',
* `font-size:40px; color: white; text-shadow: 2px 2px 6px red;`,
* )
* )
*/
export declare function renderTxt2ImgBitmap(txt: string, cssText: string): Promise<ImageBitmap>;
declare interface SubtitleStruct {
start: number;
end: number;
text: string;
}
declare type TAnimateProps = IRectBaseProps & {
opacity: number;
};
export declare class TextClip implements IClip {
#private;
ready: Promise<{
width: number;
height: number;
duration: number;
}>;
constructor(opts: ITextClipOpts);
get meta(): {
width: number;
height: number;
duration: number;
};
tick(time: number): Promise<{
video: VideoFrame;
state: "success";
}>;
clone(): Promise<this>;
/**
* 更新文本样式
* @param style 新的样式配置,将与现有样式合并
*/
setStyle(style: Partial<ITextStyle>): this;
/**
* 更新文本内容
* @param text 新的文本内容
*/
setText(text: string): this;
destroy(): void;
}
declare type ThumbnailOpts = {
start: number;
end: number;
step: number;
};
declare type TImgSource = HTMLVideoElement | HTMLCanvasElement | HTMLImageElement | ImageBitmap | OffscreenCanvas | VideoFrame;
declare type TKeyFrameOpts = Partial<Record<`${number}%` | 'from' | 'to', Partial<TAnimateProps>>>;
/**
* 包装 {@link IClip} 给素材扩展坐标、层级、透明度等信息,用于 {@link [AVCanvas](../../av-canvas/classes/AVCanvas.html)} 响应用户交互
*
* 跟 {@link OffscreenSprite} 非常相似,应用场景不同
*
* @example
* const spr = new VisibleSprite(
* new MP4Clip((await fetch('<mp4 url>')).body),
* );
* spr.opacity = 0.5 // 半透明
* spr.rect.x = 100 // x 坐标偏移 100 像素
* spr.time.offset = 10e6 // 视频第 10s 开始绘制素材
*
* @see [视频剪辑](https://webav-tech.github.io/WebAV/demo/6_4-video-editor)
*
*/
export declare class VisibleSprite extends BaseSprite {
#private;
getClip(): IClip;
/**
* 元素是否可见,用于不想删除,期望临时隐藏 Sprite 的场景
*/
visible: boolean;
/**
* 元素是否可选择
*/
selectable: boolean;
constructor(clip: IClip);
/**
* 提前准备指定 time 的帧
*/
preFrame(time: number): void;
resetLastTime(): void;
/**
* 设置裁剪为固定宽高比,或设置为空使用原始比例
* @param width 宽度比例,传入 null 或 undefined 使用原始比例
* @param height 高度比例,传入 null 或 undefined 使用原始比例
*/
setAspectRatio(width: number | null, height: number | null): void;
getAspectRatio(): {
width: number;
height: number;
} | null;
/**
* 绘制素材指定时刻的图像到 canvas 上下文,并返回对应的音频数据
* @param time 指定时刻,微秒
*/
render(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, time: number, anchor: {
x: number;
y: number;
}): {
audio: Float32Array[];
};
copyStateTo<T extends BaseSprite>(target: T): void;
destroy(): void;
}
export { }
declare global {
interface ReadableStream<R = any> {
_ctrl: ReadableStreamController<R>;
}
}