@agrhub/engine-pixi 0.0.0-stage → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +47 -0
- package/NOTICE.md +20 -0
- package/README.md +6 -2
- package/dist/animation/block-reveal-animation.d.ts +33 -0
- package/dist/animation/easings.d.ts +4 -0
- package/dist/animation/gsap-animation.d.ts +32 -0
- package/dist/animation/index.d.ts +9 -0
- package/dist/animation/keyframe-animation.d.ts +11 -0
- package/dist/animation/mask-animation.d.ts +170 -0
- package/dist/animation/pixi-animation-utils.d.ts +10 -0
- package/dist/animation/registry.d.ts +11 -0
- package/dist/animation/types.d.ts +211 -0
- package/dist/animation/wipe-animation.d.ts +53 -0
- package/dist/clips/audio-clip.d.ts +122 -0
- package/dist/clips/backdrop-clip.d.ts +56 -0
- package/dist/clips/base-clip.d.ts +150 -0
- package/dist/clips/base-text-clip.d.ts +228 -0
- package/dist/clips/caption-clip.d.ts +129 -0
- package/dist/clips/clip-registry.d.ts +56 -0
- package/dist/clips/effect-clip.d.ts +37 -0
- package/dist/clips/iclip.d.ts +235 -0
- package/dist/clips/image-clip.d.ts +116 -0
- package/dist/clips/index.d.ts +20 -0
- package/dist/clips/placeholder-clip.d.ts +22 -0
- package/dist/clips/shape-clip.d.ts +59 -0
- package/dist/clips/text-clip.d.ts +148 -0
- package/dist/clips/transition-clip.d.ts +45 -0
- package/dist/clips/video-clip.d.ts +216 -0
- package/dist/compositor/audio-mixer.d.ts +8 -0
- package/dist/compositor/av-encoder.d.ts +17 -0
- package/dist/compositor/clip-style-renderer.d.ts +23 -0
- package/dist/compositor/compositor-renderer.d.ts +29 -0
- package/dist/compositor/effect-manager.d.ts +30 -0
- package/dist/compositor/scheduler.d.ts +8 -0
- package/dist/compositor/transition-manager.d.ts +45 -0
- package/dist/compositor.d.ts +157 -0
- package/dist/effect/constant/index.d.ts +566 -0
- package/dist/effect/effect.d.ts +9 -0
- package/dist/effect/glsl/custom-glsl.d.ts +1043 -0
- package/dist/effect/glsl/gl-effect.d.ts +38 -0
- package/dist/effect/interface/index.d.ts +25 -0
- package/dist/effect/types.d.ts +26 -0
- package/dist/effect/vertex.d.ts +1 -0
- package/dist/event-emitter.d.ts +55 -0
- package/dist/filters/outline-filter.d.ts +28 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.es.js +16144 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.cjs +3335 -0
- package/dist/index.umd.cjs.map +1 -0
- package/dist/json-serialization.d.ts +312 -0
- package/dist/mp4-utils/index.d.ts +31 -0
- package/dist/mp4-utils/mp4box-utils.d.ts +44 -0
- package/dist/mp4-utils/sample-transform.d.ts +26 -0
- package/dist/sprite/base-sprite.d.ts +273 -0
- package/dist/sprite/pixi-sprite-renderer.d.ts +69 -0
- package/dist/standalone/index.es.js +94191 -0
- package/dist/standalone/index.es.js.map +1 -0
- package/dist/studio/history-manager.d.ts +46 -0
- package/dist/studio/resource-manager.d.ts +53 -0
- package/dist/studio/selection-manager.d.ts +66 -0
- package/dist/studio/timeline-model.d.ts +117 -0
- package/dist/studio/transport.d.ts +44 -0
- package/dist/studio-bridge.d.ts +50 -0
- package/dist/studio.d.ts +529 -0
- package/dist/transformer/handle.d.ts +17 -0
- package/dist/transformer/snapping.d.ts +45 -0
- package/dist/transformer/transformer.d.ts +38 -0
- package/dist/transformer/wireframe.d.ts +5 -0
- package/dist/transition/fragment.d.ts +1 -0
- package/dist/transition/glsl/custom-glsl.d.ts +231 -0
- package/dist/transition/glsl/gl-transition.d.ts +42 -0
- package/dist/transition/transition.d.ts +6 -0
- package/dist/transition/types.d.ts +31 -0
- package/dist/transition/uniforms.d.ts +35 -0
- package/dist/transition/vertex.d.ts +1 -0
- package/dist/utils/asset-manager.d.ts +15 -0
- package/dist/utils/audio-codec-detector.d.ts +39 -0
- package/dist/utils/audio.d.ts +81 -0
- package/dist/utils/chromakey.d.ts +24 -0
- package/dist/utils/color-adjustment.d.ts +53 -0
- package/dist/utils/color.d.ts +17 -0
- package/dist/utils/common.d.ts +7 -0
- package/dist/utils/dom.d.ts +48 -0
- package/dist/utils/effect.d.ts +1 -0
- package/dist/utils/fonts.d.ts +21 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/log.d.ts +27 -0
- package/dist/utils/media-cache.d.ts +45 -0
- package/dist/utils/stream-utils.d.ts +4 -0
- package/dist/utils/video.d.ts +16 -0
- package/dist/utils/worker-timer.d.ts +1 -0
- package/package.json +63 -3
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BaseClip } from './base-clip';
|
|
2
|
+
import { IClip } from './iclip';
|
|
3
|
+
import { TransitionKey } from '../transition/glsl/gl-transition';
|
|
4
|
+
export declare class Transition extends BaseClip {
|
|
5
|
+
readonly type = "Transition";
|
|
6
|
+
ready: IClip["ready"];
|
|
7
|
+
private _meta;
|
|
8
|
+
get meta(): {
|
|
9
|
+
duration: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Unique identifier for this clip instance
|
|
15
|
+
*/
|
|
16
|
+
id: string;
|
|
17
|
+
/**
|
|
18
|
+
* The transition key
|
|
19
|
+
*/
|
|
20
|
+
transitionKey: TransitionKey;
|
|
21
|
+
/**
|
|
22
|
+
* ID of the clip from which the transition starts
|
|
23
|
+
*/
|
|
24
|
+
fromClipId: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* ID of the clip to which the transition ends
|
|
27
|
+
*/
|
|
28
|
+
toClipId: string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Custom shader parameter values (uniform name -> value)
|
|
31
|
+
*/
|
|
32
|
+
values: Record<string, any>;
|
|
33
|
+
constructor(transitionKey: TransitionKey);
|
|
34
|
+
clone(): Promise<this>;
|
|
35
|
+
tick(_time: number): Promise<{
|
|
36
|
+
video: ImageBitmap | undefined;
|
|
37
|
+
state: "success";
|
|
38
|
+
}>;
|
|
39
|
+
split(_time: number): Promise<[this, this]>;
|
|
40
|
+
toJSON(_main?: boolean): any;
|
|
41
|
+
/**
|
|
42
|
+
* Create a Transition instance from a JSON object
|
|
43
|
+
*/
|
|
44
|
+
static fromObject(json: any): Promise<Transition>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { MP4Sample } from 'wrapbox';
|
|
2
|
+
import { file } from 'opfs-tools';
|
|
3
|
+
import { BaseClip } from './base-clip';
|
|
4
|
+
import { IClip, IPlaybackCapable } from './iclip';
|
|
5
|
+
import { VideoJSON } from '../json-serialization';
|
|
6
|
+
type OPFSToolFile = ReturnType<typeof file>;
|
|
7
|
+
type MPClipCloneArgs = Awaited<ReturnType<typeof mp4FileToSamples>> & {
|
|
8
|
+
localFile: OPFSToolFile;
|
|
9
|
+
};
|
|
10
|
+
interface MP4DecoderConf {
|
|
11
|
+
video: VideoDecoderConfig | null;
|
|
12
|
+
audio: AudioDecoderConfig | null;
|
|
13
|
+
}
|
|
14
|
+
export interface IMP4ClipOpts {
|
|
15
|
+
audio?: boolean | {
|
|
16
|
+
volume: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Unsafe, may be deprecated at any time
|
|
20
|
+
*/
|
|
21
|
+
__unsafe_hardwareAcceleration__?: HardwarePreference;
|
|
22
|
+
}
|
|
23
|
+
type ExtMP4Sample = Omit<MP4Sample, "data"> & {
|
|
24
|
+
is_idr: boolean;
|
|
25
|
+
deleted?: boolean;
|
|
26
|
+
data: null | Uint8Array;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Video clip, parses MP4 files, uses {@link Video.tick} to decode image frames at specified time on demand
|
|
30
|
+
*
|
|
31
|
+
* Can be used to implement video frame extraction, thumbnail generation, video editing and other functions
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Load video clip asynchronously
|
|
35
|
+
* const videoClip = await Video.fromUrl('clip.mp4', {
|
|
36
|
+
* x: 0,
|
|
37
|
+
* y: 0,
|
|
38
|
+
* width: 1920,
|
|
39
|
+
* height: 1080,
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Set timeline position
|
|
43
|
+
* videoClip.set({
|
|
44
|
+
* display: {
|
|
45
|
+
* from: 150, // frames
|
|
46
|
+
* to: 450, // frames (10 seconds at 30fps)
|
|
47
|
+
* },
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
*/
|
|
51
|
+
export declare class Video extends BaseClip implements IPlaybackCapable {
|
|
52
|
+
readonly type = "Video";
|
|
53
|
+
private insId;
|
|
54
|
+
private logger;
|
|
55
|
+
ready: IClip["ready"];
|
|
56
|
+
private _meta;
|
|
57
|
+
get meta(): {
|
|
58
|
+
duration: number;
|
|
59
|
+
width: number;
|
|
60
|
+
height: number;
|
|
61
|
+
audioSampleRate: number;
|
|
62
|
+
audioChanCount: number;
|
|
63
|
+
};
|
|
64
|
+
private localFile;
|
|
65
|
+
/** Store binary data of video header (box: ftyp, moov) */
|
|
66
|
+
private headerBoxPos;
|
|
67
|
+
/**
|
|
68
|
+
* Provide binary data of video header (box: ftyp, moov)
|
|
69
|
+
* Use any mp4 demuxer to parse and get detailed video information
|
|
70
|
+
* Unit tests include sample code using mp4box.js
|
|
71
|
+
*/
|
|
72
|
+
getFileHeaderBinData(): Promise<ArrayBuffer>;
|
|
73
|
+
/** Store video transform and rotation info, currently only restores rotation */
|
|
74
|
+
private parsedMatrix;
|
|
75
|
+
private vfRotater;
|
|
76
|
+
private videoSamples;
|
|
77
|
+
private audioSamples;
|
|
78
|
+
private videoFrameFinder;
|
|
79
|
+
private audioFrameFinder;
|
|
80
|
+
protected onEffectiveVolumeChange(): void;
|
|
81
|
+
private decoderConf;
|
|
82
|
+
private opts;
|
|
83
|
+
/**
|
|
84
|
+
* Whether to include audio track (hybrid JSON structure)
|
|
85
|
+
*/
|
|
86
|
+
audio: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Unique identifier for this clip instance
|
|
89
|
+
*/
|
|
90
|
+
id: string;
|
|
91
|
+
/**
|
|
92
|
+
* Array of effects to be applied to this clip
|
|
93
|
+
* Each effect specifies key, startTime, duration, and optional targets
|
|
94
|
+
*/
|
|
95
|
+
effects: Array<{
|
|
96
|
+
id: string;
|
|
97
|
+
key: string;
|
|
98
|
+
startTime: number;
|
|
99
|
+
duration: number;
|
|
100
|
+
}>;
|
|
101
|
+
getVisibleHandles(): Array<"tl" | "tr" | "bl" | "br" | "ml" | "mr" | "mt" | "mb" | "rot">;
|
|
102
|
+
/**
|
|
103
|
+
* Load a video clip from a URL
|
|
104
|
+
* @param url Video URL
|
|
105
|
+
* @param opts Position and size options
|
|
106
|
+
* @returns Promise that resolves to a video clip
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* const videoClip = await Video.fromUrl('clip.mp4', {
|
|
110
|
+
* x: 0,
|
|
111
|
+
* y: 0,
|
|
112
|
+
* width: 1920,
|
|
113
|
+
* height: 1080,
|
|
114
|
+
* });
|
|
115
|
+
*/
|
|
116
|
+
static fromUrl(url: string, opts?: {
|
|
117
|
+
x?: number;
|
|
118
|
+
y?: number;
|
|
119
|
+
width?: number;
|
|
120
|
+
height?: number;
|
|
121
|
+
}): Promise<Video>;
|
|
122
|
+
constructor(source: OPFSToolFile | ReadableStream<Uint8Array> | MPClipCloneArgs, opts?: IMP4ClipOpts, src?: string);
|
|
123
|
+
/**
|
|
124
|
+
* Intercept data returned by {@link Video.tick} method for secondary processing of image and audio data
|
|
125
|
+
* @param time Time when tick was called
|
|
126
|
+
* @param tickRet Data returned by tick
|
|
127
|
+
*
|
|
128
|
+
* */
|
|
129
|
+
tickInterceptor: <T extends Awaited<ReturnType<Video["tick"]>>>(time: number, tickRet: T) => Promise<T>;
|
|
130
|
+
/**
|
|
131
|
+
* Get image frame and audio data at specified time
|
|
132
|
+
* @param time Time in microseconds
|
|
133
|
+
*/
|
|
134
|
+
tick(time: number): Promise<{
|
|
135
|
+
video?: VideoFrame;
|
|
136
|
+
audio: Float32Array[];
|
|
137
|
+
state: "success" | "done";
|
|
138
|
+
}>;
|
|
139
|
+
addEffect(effect: {
|
|
140
|
+
id: string;
|
|
141
|
+
key: string;
|
|
142
|
+
startTime: number;
|
|
143
|
+
duration: number;
|
|
144
|
+
}): void;
|
|
145
|
+
editEffect(effectId: string, newEffectData: Partial<{
|
|
146
|
+
key: string;
|
|
147
|
+
startTime: number;
|
|
148
|
+
duration: number;
|
|
149
|
+
}>): void;
|
|
150
|
+
removeEffect(effectId: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Split is handled by core state, not implemented here
|
|
153
|
+
*/
|
|
154
|
+
split(_time: number): Promise<[this, this]>;
|
|
155
|
+
clone(): Promise<this>;
|
|
156
|
+
destroy(): void;
|
|
157
|
+
toJSON(main?: boolean): VideoJSON;
|
|
158
|
+
/**
|
|
159
|
+
* Create a Video instance from a JSON object (fabric.js pattern)
|
|
160
|
+
* @param json The JSON object representing the clip
|
|
161
|
+
* @returns Promise that resolves to a Video instance
|
|
162
|
+
*/
|
|
163
|
+
static fromObject(json: VideoJSON): Promise<Video>;
|
|
164
|
+
/**
|
|
165
|
+
* Create HTMLVideoElement for playback
|
|
166
|
+
*/
|
|
167
|
+
createPlaybackElement(): Promise<{
|
|
168
|
+
element: HTMLVideoElement;
|
|
169
|
+
objectUrl?: string;
|
|
170
|
+
}>;
|
|
171
|
+
play(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void>;
|
|
172
|
+
pause(element: HTMLVideoElement | HTMLAudioElement): void;
|
|
173
|
+
seek(element: HTMLVideoElement | HTMLAudioElement, timeSeconds: number): Promise<void>;
|
|
174
|
+
syncPlayback(element: HTMLVideoElement | HTMLAudioElement, isPlaying: boolean, timeSeconds: number): void;
|
|
175
|
+
cleanupPlayback(element: HTMLVideoElement | HTMLAudioElement, objectUrl?: string): void;
|
|
176
|
+
/**
|
|
177
|
+
* Scale clip to fit within the scene dimensions while maintaining aspect ratio
|
|
178
|
+
* Similar to fabric.js scaleToFit
|
|
179
|
+
* @param sceneWidth Scene width
|
|
180
|
+
* @param sceneHeight Scene height
|
|
181
|
+
*/
|
|
182
|
+
scaleToFit(sceneWidth: number, sceneHeight: number): Promise<void>;
|
|
183
|
+
/**
|
|
184
|
+
* Scale clip to fill the scene dimensions while maintaining aspect ratio
|
|
185
|
+
* May crop parts of the clip. Similar to fabric.js scaleToFill
|
|
186
|
+
* @param sceneWidth Scene width
|
|
187
|
+
* @param sceneHeight Scene height
|
|
188
|
+
*/
|
|
189
|
+
scaleToFill(sceneWidth: number, sceneHeight: number): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Center the clip within the scene dimensions
|
|
192
|
+
* Similar to fabric.js center
|
|
193
|
+
* @param sceneWidth Scene width
|
|
194
|
+
* @param sceneHeight Scene height
|
|
195
|
+
*/
|
|
196
|
+
centerInScene(sceneWidth: number, sceneHeight: number): void;
|
|
197
|
+
}
|
|
198
|
+
declare function mp4FileToSamples(otFile: OPFSToolFile, opts?: IMP4ClipOpts): Promise<{
|
|
199
|
+
videoSamples: ExtMP4Sample[];
|
|
200
|
+
audioSamples: ExtMP4Sample[];
|
|
201
|
+
decoderConf: MP4DecoderConf;
|
|
202
|
+
headerBoxPos: {
|
|
203
|
+
start: number;
|
|
204
|
+
size: number;
|
|
205
|
+
}[];
|
|
206
|
+
parsedMatrix: {
|
|
207
|
+
perspective: number;
|
|
208
|
+
rotationRad: number;
|
|
209
|
+
rotationDeg: number;
|
|
210
|
+
scaleX: number;
|
|
211
|
+
scaleY: number;
|
|
212
|
+
translateX: number;
|
|
213
|
+
translateY: number;
|
|
214
|
+
};
|
|
215
|
+
}>;
|
|
216
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buffer input data and convert to AudioData with fixed frame count.
|
|
3
|
+
* Matches the WebCodecs audio configuration.
|
|
4
|
+
*
|
|
5
|
+
* @param framesPerChunk Number of audio frames per AudioData instance
|
|
6
|
+
* @param fps The video fps (used for calculating buffer limits)
|
|
7
|
+
*/
|
|
8
|
+
export declare function createAudioTrackBuf(framesPerChunk: number, fps?: number): (timestamp: number, trackAudios: Float32Array[][]) => AudioData[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { recodemux } from 'wrapbox';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the WebGL/WebGL2 context already held by an OffscreenCanvas.
|
|
4
|
+
* Returns null if no WebGL context is attached (e.g. canvas not yet used).
|
|
5
|
+
*/
|
|
6
|
+
export declare function getCanvasGl(canvas: OffscreenCanvas): WebGLRenderingContext | WebGL2RenderingContext | null;
|
|
7
|
+
/**
|
|
8
|
+
* Creates an AV encoder function that queues and encodes both mixed AudioData and VideoFrames.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createAVEncoder(opts: {
|
|
11
|
+
muxer: ReturnType<typeof recodemux>;
|
|
12
|
+
canvas: OffscreenCanvas;
|
|
13
|
+
outputAudio?: boolean;
|
|
14
|
+
hasVideoTrack: boolean;
|
|
15
|
+
timeSlice: number;
|
|
16
|
+
fps: number;
|
|
17
|
+
}): (timestamp: number, audios: Float32Array[][], hasVideo: boolean) => Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Container, Sprite, Texture, Graphics } from 'pixi.js';
|
|
2
|
+
import { IClip } from '../clips';
|
|
3
|
+
export interface IPooledClipObjects {
|
|
4
|
+
root: Container;
|
|
5
|
+
mainSprite: Sprite;
|
|
6
|
+
mirrors: Sprite[];
|
|
7
|
+
maskGfx: Graphics | null;
|
|
8
|
+
strokeGfx: Graphics | null;
|
|
9
|
+
shadowGfx: Graphics | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Applies layout transforms, mirrors, filters (blur, adjustments, chroma, hsl), and decoration styles
|
|
13
|
+
* (border radius, strokes, drop shadows) to a set of PixiJS containers and sprites representing a clip.
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyClipStylesAndFilters(opts: {
|
|
16
|
+
clip: IClip;
|
|
17
|
+
tex: Texture;
|
|
18
|
+
rootContainer: Container;
|
|
19
|
+
tempSprite: Sprite;
|
|
20
|
+
pooled: IPooledClipObjects;
|
|
21
|
+
scaleX: number;
|
|
22
|
+
scaleY: number;
|
|
23
|
+
}): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Application } from 'pixi.js';
|
|
2
|
+
import { IClip } from '../clips';
|
|
3
|
+
export interface ISpritesRenderOpts {
|
|
4
|
+
pixiApp: Application | null;
|
|
5
|
+
backgroundColor: string;
|
|
6
|
+
sprites: Array<IClip & {
|
|
7
|
+
main: boolean;
|
|
8
|
+
expired: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
aborter: {
|
|
11
|
+
aborted: boolean;
|
|
12
|
+
};
|
|
13
|
+
scaleX: number;
|
|
14
|
+
scaleY: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ISpritesRenderResult {
|
|
17
|
+
render: (timestamp: number) => Promise<{
|
|
18
|
+
audios: Float32Array[][];
|
|
19
|
+
mainSprDone: boolean;
|
|
20
|
+
hasVideo: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
cleanup: () => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates the renderer pipeline for compositor frames.
|
|
26
|
+
* Delegates actual transition handling, asset transformations, styles/filters,
|
|
27
|
+
* and global effects pipeline execution to separate managers.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createSpritesRender(opts: ISpritesRenderOpts): ISpritesRenderResult;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Application, Container, Sprite } from 'pixi.js';
|
|
2
|
+
import { IClip } from '../clips';
|
|
3
|
+
import { PixiSpriteRenderer } from '../sprite/pixi-sprite-renderer';
|
|
4
|
+
export declare class EffectManager {
|
|
5
|
+
private pixiApp;
|
|
6
|
+
private effectCache;
|
|
7
|
+
private effectInputTexture;
|
|
8
|
+
private scaleX;
|
|
9
|
+
private scaleY;
|
|
10
|
+
constructor(pixiApp: Application, hasVideoTrack: boolean, scaleX?: number, scaleY?: number);
|
|
11
|
+
/**
|
|
12
|
+
* Processes all active global and adjustment layer effects at the given timestamp.
|
|
13
|
+
*/
|
|
14
|
+
processEffects(opts: {
|
|
15
|
+
timestamp: number;
|
|
16
|
+
sprites: Array<IClip & {
|
|
17
|
+
expired?: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
spriteById: Map<string, IClip>;
|
|
20
|
+
spriteIndexById: Map<string, number>;
|
|
21
|
+
spriteRenderers: Map<IClip & {
|
|
22
|
+
expired?: boolean;
|
|
23
|
+
}, PixiSpriteRenderer>;
|
|
24
|
+
transitionSprites: Map<string, Sprite>;
|
|
25
|
+
clipsEffectContainer: Container;
|
|
26
|
+
clipsNormalContainer: Container;
|
|
27
|
+
postProcessContainer: Container;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
cleanup(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function yieldToScheduler(): Promise<void>;
|
|
2
|
+
/** Max frames allowed in the VideoEncoder queue before back-pressure kicks in. */
|
|
3
|
+
export declare const ENCODER_QUEUE_LIMIT = 20;
|
|
4
|
+
/**
|
|
5
|
+
* Wait until the encoder queue drains below the limit.
|
|
6
|
+
* Prevents OOM from too many queued VideoFrames.
|
|
7
|
+
*/
|
|
8
|
+
export declare function waitEncoderQueue(getQueueSize: () => number): Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Application, Container, Sprite } from 'pixi.js';
|
|
2
|
+
import { IClip, Transition } from '../clips';
|
|
3
|
+
export declare class TransitionManager {
|
|
4
|
+
private pixiApp;
|
|
5
|
+
private scaleX;
|
|
6
|
+
private scaleY;
|
|
7
|
+
private transitionRenderers;
|
|
8
|
+
private transitionSprites;
|
|
9
|
+
private transFromTexture;
|
|
10
|
+
private transToTexture;
|
|
11
|
+
private transBgGraphics;
|
|
12
|
+
private transClipPool;
|
|
13
|
+
constructor(pixiApp: Application, scaleX: number, scaleY: number);
|
|
14
|
+
/**
|
|
15
|
+
* Reset the visibility of all transition sprites at the start of a frame.
|
|
16
|
+
*/
|
|
17
|
+
resetFrame(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Checks if a transition sprite has been created for a given ID.
|
|
20
|
+
*/
|
|
21
|
+
getTransitionSprite(id: string): Sprite | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Retrieve pool container/sprite elements for a given clip to avoid allocations.
|
|
24
|
+
*/
|
|
25
|
+
private getTransClipObjects;
|
|
26
|
+
private getClipFrameAtTimestamp;
|
|
27
|
+
private renderClipToTransitionTexture;
|
|
28
|
+
/**
|
|
29
|
+
* Render transition between two clips at a given timeline timestamp.
|
|
30
|
+
* Modifies target claimed set and updates internal transition sprite.
|
|
31
|
+
*/
|
|
32
|
+
renderTransition(opts: {
|
|
33
|
+
sprite: Transition & {
|
|
34
|
+
expired?: boolean;
|
|
35
|
+
};
|
|
36
|
+
timestamp: number;
|
|
37
|
+
fromClip: IClip;
|
|
38
|
+
toClip: IClip;
|
|
39
|
+
getFrameCached: (clip: IClip, timestamp: number) => Promise<any>;
|
|
40
|
+
clipsNormalContainer: Container;
|
|
41
|
+
clipsClaimedByTransition: Set<string>;
|
|
42
|
+
onVideoState: () => void;
|
|
43
|
+
}): Promise<boolean>;
|
|
44
|
+
cleanup(): void;
|
|
45
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { IClip } from './clips';
|
|
2
|
+
import { default as EventEmitter } from './event-emitter';
|
|
3
|
+
import { ProjectJSON } from './json-serialization';
|
|
4
|
+
export interface ICompositorOpts {
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
bitrate?: number;
|
|
8
|
+
fps?: number;
|
|
9
|
+
backgroundColor?: string;
|
|
10
|
+
format?: string;
|
|
11
|
+
videoCodec?: string;
|
|
12
|
+
/**
|
|
13
|
+
* If false, exclude audio track from the output video
|
|
14
|
+
*/
|
|
15
|
+
audio?: false;
|
|
16
|
+
audioCodec?: string;
|
|
17
|
+
audioSampleRate?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Write metadata tags to the output video
|
|
20
|
+
*/
|
|
21
|
+
metaDataTags?: Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Unsafe, may be deprecated at any time
|
|
24
|
+
*/
|
|
25
|
+
__unsafe_hardwareAcceleration__?: HardwarePreference;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Video compositor that can add multiple {@link OffscreenSprite} instances,
|
|
29
|
+
* @example
|
|
30
|
+
* const spr1 = new OffscreenSprite(
|
|
31
|
+
* new Video((await fetch('<mp4 url>')).body),
|
|
32
|
+
* );
|
|
33
|
+
* const spr2 = new OffscreenSprite(
|
|
34
|
+
* await Audio.fromUrl('<audio url>'),
|
|
35
|
+
* );
|
|
36
|
+
* const com = new Compositor({ width: 1280, height: 720, });
|
|
37
|
+
|
|
38
|
+
* await com.addSprite(spr1);
|
|
39
|
+
* await com.addSprite(spr2);
|
|
40
|
+
|
|
41
|
+
* com.output(); // => ReadableStream
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
export declare class Compositor extends EventEmitter<{
|
|
45
|
+
"export:progress": number;
|
|
46
|
+
error: Error;
|
|
47
|
+
}> {
|
|
48
|
+
/**
|
|
49
|
+
* Check compatibility with the current environment
|
|
50
|
+
* @param args.videoCodec Specify video codec, default avc1.42E032
|
|
51
|
+
* @param args.width Specify video width, default 1920
|
|
52
|
+
* @param args.height Specify video height, default 1080
|
|
53
|
+
* @param args.bitrate Specify video bitrate, default 5e6
|
|
54
|
+
*/
|
|
55
|
+
static isSupported(args?: {
|
|
56
|
+
videoCodec?: string;
|
|
57
|
+
width?: number;
|
|
58
|
+
height?: number;
|
|
59
|
+
bitrate?: number;
|
|
60
|
+
}): Promise<boolean>;
|
|
61
|
+
private logger;
|
|
62
|
+
private destroyed;
|
|
63
|
+
private sprites;
|
|
64
|
+
private canvas;
|
|
65
|
+
private pixiApp;
|
|
66
|
+
private stopOutput;
|
|
67
|
+
private opts;
|
|
68
|
+
/** Encodable audio chosen for output (undefined = not resolved yet, null = audio must be skipped) */
|
|
69
|
+
private resolvedAudio;
|
|
70
|
+
private explicitOpts;
|
|
71
|
+
private hasVideoTrack;
|
|
72
|
+
private jsonDimensions;
|
|
73
|
+
/**
|
|
74
|
+
* Create a compositor instance based on configuration
|
|
75
|
+
* @param opts ICompositorOpts
|
|
76
|
+
*/
|
|
77
|
+
constructor(opts?: ICompositorOpts);
|
|
78
|
+
initPixiApp(): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Settles which audio codec/sample rate output() will use, falling back when the requested one
|
|
81
|
+
* isn't encodable here (e.g. no AAC encoder in headless Chromium). Called by initPixiApp and
|
|
82
|
+
* loadFromJSON, which callers await before output().
|
|
83
|
+
*/
|
|
84
|
+
private resolveAudioEncoding;
|
|
85
|
+
/**
|
|
86
|
+
* Add a clip for video composition. Video duration defaults to the maximum duration value from all clips
|
|
87
|
+
* @param clip Clip (extends BaseSprite)
|
|
88
|
+
* @param opts.main If main is true, the video duration uses this clip's duration value
|
|
89
|
+
*/
|
|
90
|
+
addSprite(clip: IClip, opts?: {
|
|
91
|
+
main?: boolean;
|
|
92
|
+
}): Promise<void>;
|
|
93
|
+
private initMuxer;
|
|
94
|
+
/**
|
|
95
|
+
* Output video file binary stream
|
|
96
|
+
* @param opts.maxTime Maximum duration allowed for output video, content exceeding this will be ignored
|
|
97
|
+
*/
|
|
98
|
+
output(opts?: {
|
|
99
|
+
maxTime?: number;
|
|
100
|
+
}): ReadableStream<Uint8Array>;
|
|
101
|
+
/**
|
|
102
|
+
* Destroy instance and release resources
|
|
103
|
+
*/
|
|
104
|
+
destroy(): void;
|
|
105
|
+
private runEncoding;
|
|
106
|
+
/**
|
|
107
|
+
* Export current compositor state to JSON
|
|
108
|
+
*/
|
|
109
|
+
exportToJSON(): ProjectJSON;
|
|
110
|
+
/**
|
|
111
|
+
* Load clips from JSON
|
|
112
|
+
* @param json The JSON project data
|
|
113
|
+
*/
|
|
114
|
+
loadFromJSON(json: ProjectJSON): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Renders the frame at the given time and returns it as a base64-encoded PNG.
|
|
117
|
+
*
|
|
118
|
+
* Initialises the internal Pixi application on demand (if not already
|
|
119
|
+
* initialised), performs a single-frame render using the same sprite
|
|
120
|
+
* pipeline as {@link output}, and returns the result without modifying
|
|
121
|
+
* the compositor's encoding state.
|
|
122
|
+
*
|
|
123
|
+
* @param timeMs Time in milliseconds
|
|
124
|
+
* @param options.transparent If true, the renderer background is made
|
|
125
|
+
* transparent so the resulting PNG has a transparent background.
|
|
126
|
+
* @returns Base64 data-URL string (e.g. "data:image/png;base64,...")
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* const compositor = new Compositor({ width: 1280, height: 720 });
|
|
130
|
+
* await compositor.addSprite(videoClip);
|
|
131
|
+
* const frame = await compositor.renderFrame(2000); // frame at 2 s
|
|
132
|
+
* const transparent = await compositor.renderFrame(2000, { transparent: true });
|
|
133
|
+
*/
|
|
134
|
+
renderFrame(timeMs: number, options?: {
|
|
135
|
+
transparent?: boolean;
|
|
136
|
+
}): Promise<string>;
|
|
137
|
+
/**
|
|
138
|
+
* Alias for {@link renderFrame} with an optional timestamp.
|
|
139
|
+
* Captures a single frame as a base64-encoded PNG.
|
|
140
|
+
*
|
|
141
|
+
* @param timeMs Optional time in milliseconds, or an options object. If
|
|
142
|
+
* omitted, the first frame at time 0 is captured.
|
|
143
|
+
* @param options.transparent If true, the renderer background is made
|
|
144
|
+
* transparent so the resulting PNG has a transparent background.
|
|
145
|
+
* @returns Base64 data-URL string (e.g. "data:image/png;base64,...")
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* const compositor = new Compositor({ width: 1280, height: 720 });
|
|
149
|
+
* await compositor.addSprite(videoClip);
|
|
150
|
+
* const firstFrame = await compositor.snapshot(); // time 0
|
|
151
|
+
* const frameAt2s = await compositor.snapshot(2000); // explicit timestamp
|
|
152
|
+
* const transparent = await compositor.snapshot({ transparent: true }); // time 0, transparent
|
|
153
|
+
*/
|
|
154
|
+
snapshot(timeMs?: number | {
|
|
155
|
+
transparent?: boolean;
|
|
156
|
+
}): Promise<string>;
|
|
157
|
+
}
|