@efxlab/motion-canvas-ffmpeg 4.0.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.
@@ -0,0 +1,44 @@
1
+ import type { Exporter, MetaField, Project, RendererResult, RendererSettings, Sound } from '@efxlab/motion-canvas-core';
2
+ /**
3
+ * FFmpeg video exporter.
4
+ *
5
+ * @remarks
6
+ * Most of the export logic is handled on the server. This class communicates
7
+ * with the FFmpegBridge through a WebSocket connection which lets it invoke
8
+ * methods on the FFmpegExporterServer class.
9
+ *
10
+ * For example, calling the following method:
11
+ * ```ts
12
+ * async this.invoke('process', 7);
13
+ * ```
14
+ * Will invoke the `process` method on the FFmpegExporterServer class with `7`
15
+ * as the argument. The result of the method will be returned as a Promise.
16
+ *
17
+ * Before any methods can be invoked, the FFmpegExporterServer class must be
18
+ * initialized by invoking `start`.
19
+ */
20
+ export declare class FFmpegExporterClient implements Exporter {
21
+ private readonly project;
22
+ private readonly settings;
23
+ static readonly id = "@efxlab/motion-canvas-ffmpeg";
24
+ static readonly displayName = "Video (FFmpeg)";
25
+ static meta(project: Project): MetaField<any>;
26
+ static create(project: Project, settings: RendererSettings): Promise<FFmpegExporterClient>;
27
+ private static readonly response;
28
+ private concurrentFrames;
29
+ private error;
30
+ constructor(project: Project, settings: RendererSettings);
31
+ start(sounds: Sound[], duration: number): Promise<void>;
32
+ handleFrame(canvas: HTMLCanvasElement, _frame: number, _sceneFrame: number, _sceneName: string, _signal: AbortSignal, context: CanvasRenderingContext2D): Promise<void>;
33
+ stop(result: RendererResult): Promise<void>;
34
+ /**
35
+ * Remotely invoke a method on the server and wait for a response.
36
+ *
37
+ * @param method - The method name to execute on the server.
38
+ * @param data - The data that will be passed as an argument to the method.
39
+ * Should be serializable.
40
+ * @param strategy - How the data should be sent to the server.
41
+ */
42
+ private invoke;
43
+ }
44
+ //# sourceMappingURL=FFmpegExporterClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FFmpegExporterClient.d.ts","sourceRoot":"","sources":["../../client/FFmpegExporterClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,SAAS,EACT,OAAO,EACP,cAAc,EACd,gBAAgB,EAChB,KAAK,EACN,MAAM,4BAA4B,CAAC;AA8BpC;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAqB,YAAW,QAAQ;IAiCjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjC3B,gBAAuB,EAAE,kCAAkC;IAC3D,gBAAuB,WAAW,oBAAoB;WAExC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC;WAUhC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB;IAIvE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAWzE,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,KAAK,CAAkB;gBAGZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,gBAAgB;IAGhC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAavD,WAAW,CACtB,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC;IAqBH,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYxD;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM;CA0Cf"}
@@ -0,0 +1,135 @@
1
+ var _a;
2
+ import { BoolMetaField, EventDispatcher, NumberMetaField, ObjectMetaField, } from '@efxlab/motion-canvas-core';
3
+ const EXPORT_FRAME_LIMIT = 256;
4
+ const EXPORT_RETRY_DELAY = 1000;
5
+ /**
6
+ * FFmpeg video exporter.
7
+ *
8
+ * @remarks
9
+ * Most of the export logic is handled on the server. This class communicates
10
+ * with the FFmpegBridge through a WebSocket connection which lets it invoke
11
+ * methods on the FFmpegExporterServer class.
12
+ *
13
+ * For example, calling the following method:
14
+ * ```ts
15
+ * async this.invoke('process', 7);
16
+ * ```
17
+ * Will invoke the `process` method on the FFmpegExporterServer class with `7`
18
+ * as the argument. The result of the method will be returned as a Promise.
19
+ *
20
+ * Before any methods can be invoked, the FFmpegExporterServer class must be
21
+ * initialized by invoking `start`.
22
+ */
23
+ export class FFmpegExporterClient {
24
+ static meta(project) {
25
+ return new ObjectMetaField(this.displayName, {
26
+ fastStart: new BoolMetaField('fast start', true),
27
+ includeAudio: new BoolMetaField('include audio', true).disable(!project.audio),
28
+ audioSampleRate: new NumberMetaField('audio sample rate', 48000),
29
+ });
30
+ }
31
+ static async create(project, settings) {
32
+ return new _a(project, settings);
33
+ }
34
+ constructor(project, settings) {
35
+ this.project = project;
36
+ this.settings = settings;
37
+ this.concurrentFrames = 0;
38
+ this.error = false;
39
+ }
40
+ async start(sounds, duration) {
41
+ const options = this.settings.exporter.options;
42
+ await this.invoke('start', {
43
+ ...this.settings,
44
+ ...options,
45
+ audio: this.project.audio,
46
+ audioOffset: this.project.meta.shared.audioOffset.get() - this.settings.range[0],
47
+ sounds,
48
+ duration,
49
+ });
50
+ }
51
+ async handleFrame(canvas, _frame, _sceneFrame, _sceneName, _signal, context) {
52
+ while (this.concurrentFrames >= EXPORT_FRAME_LIMIT) {
53
+ await new Promise(resolve => setTimeout(resolve, EXPORT_RETRY_DELAY));
54
+ }
55
+ if (this.error) {
56
+ throw this.error;
57
+ }
58
+ const data = context.getImageData(0, 0, canvas.width, canvas.height).data;
59
+ this.concurrentFrames++;
60
+ this.invoke('handleFrame', data, 'octet-stream')
61
+ .then(() => {
62
+ this.concurrentFrames--;
63
+ })
64
+ .catch(error => {
65
+ this.error = error;
66
+ this.concurrentFrames--;
67
+ });
68
+ }
69
+ async stop(result) {
70
+ while (this.concurrentFrames >= EXPORT_FRAME_LIMIT) {
71
+ await new Promise(resolve => setTimeout(resolve, EXPORT_RETRY_DELAY));
72
+ }
73
+ if (this.error) {
74
+ throw this.error;
75
+ }
76
+ await this.invoke('end', result);
77
+ }
78
+ /**
79
+ * Remotely invoke a method on the server and wait for a response.
80
+ *
81
+ * @param method - The method name to execute on the server.
82
+ * @param data - The data that will be passed as an argument to the method.
83
+ * Should be serializable.
84
+ * @param strategy - How the data should be sent to the server.
85
+ */
86
+ invoke(method, data, strategy = 'ws') {
87
+ if (import.meta.hot) {
88
+ return new Promise((resolve, reject) => {
89
+ const handle = (response) => {
90
+ if (response.method !== method) {
91
+ return;
92
+ }
93
+ _a.response.unsubscribe(handle);
94
+ if (response.status === 'success') {
95
+ resolve(response.data);
96
+ }
97
+ else {
98
+ reject({
99
+ message: 'An error occurred while exporting the video.',
100
+ remarks: `Method: ${method}<br>Server error: ${response.message}`,
101
+ object: data,
102
+ });
103
+ }
104
+ };
105
+ _a.response.subscribe(handle);
106
+ switch (strategy) {
107
+ case 'ws':
108
+ import.meta.hot.send('motion-canvas/ffmpeg', { method, data });
109
+ break;
110
+ case 'octet-stream':
111
+ fetch(`/ffmpeg/${method}`, {
112
+ method: 'POST',
113
+ body: data,
114
+ // eslint-disable-next-line @typescript-eslint/naming-convention
115
+ headers: { 'Content-Type': 'application/octet-stream' },
116
+ }).catch(reject);
117
+ break;
118
+ }
119
+ });
120
+ }
121
+ else {
122
+ throw new Error('FFmpegExporter can only be used locally.');
123
+ }
124
+ }
125
+ }
126
+ _a = FFmpegExporterClient;
127
+ FFmpegExporterClient.id = '@efxlab/motion-canvas-ffmpeg';
128
+ FFmpegExporterClient.displayName = 'Video (FFmpeg)';
129
+ FFmpegExporterClient.response = new EventDispatcher();
130
+ (() => {
131
+ if (import.meta.hot) {
132
+ import.meta.hot.on(`motion-canvas/ffmpeg-ack`, (response) => _a.response.dispatch(response));
133
+ }
134
+ })();
135
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRkZtcGVnRXhwb3J0ZXJDbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9jbGllbnQvRkZtcGVnRXhwb3J0ZXJDbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQVFBLE9BQU8sRUFDTCxhQUFhLEVBQ2IsZUFBZSxFQUNmLGVBQWUsRUFDZixlQUFlLEdBRWhCLE1BQU0sNEJBQTRCLENBQUM7QUFvQnBDLE1BQU0sa0JBQWtCLEdBQUcsR0FBRyxDQUFDO0FBQy9CLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDO0FBRWhDOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUNILE1BQU0sT0FBTyxvQkFBb0I7SUFJeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFnQjtRQUNqQyxPQUFPLElBQUksZUFBZSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDM0MsU0FBUyxFQUFFLElBQUksYUFBYSxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUM7WUFDaEQsWUFBWSxFQUFFLElBQUksYUFBYSxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQzVELENBQUMsT0FBTyxDQUFDLEtBQUssQ0FDZjtZQUNELGVBQWUsRUFBRSxJQUFJLGVBQWUsQ0FBQyxtQkFBbUIsRUFBRSxLQUFLLENBQUM7U0FDakUsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQWdCLEVBQUUsUUFBMEI7UUFDckUsT0FBTyxJQUFJLEVBQW9CLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFnQkQsWUFDbUIsT0FBZ0IsRUFDaEIsUUFBMEI7UUFEMUIsWUFBTyxHQUFQLE9BQU8sQ0FBUztRQUNoQixhQUFRLEdBQVIsUUFBUSxDQUFrQjtRQUxyQyxxQkFBZ0IsR0FBRyxDQUFDLENBQUM7UUFDckIsVUFBSyxHQUFZLEtBQUssQ0FBQztJQUs1QixDQUFDO0lBRUcsS0FBSyxD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
@@ -0,0 +1,3 @@
1
+ declare const _default: () => import("@efxlab/motion-canvas-core").Plugin;
2
+ export default _default;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../client/index.ts"],"names":[],"mappings":";AAIA,wBAKG"}
@@ -0,0 +1,9 @@
1
+ import { makePlugin } from '@efxlab/motion-canvas-core';
2
+ import { FFmpegExporterClient } from './FFmpegExporterClient';
3
+ export default makePlugin({
4
+ name: 'ffmpeg-plugin',
5
+ exporters() {
6
+ return [FFmpegExporterClient];
7
+ },
8
+ });
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9jbGllbnQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLDRCQUE0QixDQUFDO0FBQ3RELE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBRTVELGVBQWUsVUFBVSxDQUFDO0lBQ3hCLElBQUksRUFBRSxlQUFlO0lBQ3JCLFNBQVM7UUFDUCxPQUFPLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUNoQyxDQUFDO0NBQ0YsQ0FBQyxDQUFDIn0=
@@ -0,0 +1,20 @@
1
+ import { PluginConfig } from '@efxlab/motion-canvas-vite-plugin';
2
+ import { ViteDevServer } from 'vite';
3
+ /**
4
+ * A simple bridge between the FFmpegExporterServer and FFmpegExporterClient.
5
+ *
6
+ * @remarks
7
+ * This class lets the client exporter invoke methods on the server and receive
8
+ * responses using a simple Promise-based API.
9
+ */
10
+ export declare class FFmpegBridge {
11
+ private readonly server;
12
+ private readonly config;
13
+ private process;
14
+ constructor(server: ViteDevServer, config: PluginConfig);
15
+ private handleRequest;
16
+ private handleMessage;
17
+ private respondSuccess;
18
+ private respondError;
19
+ }
20
+ //# sourceMappingURL=FFmpegBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FFmpegBridge.d.ts","sourceRoot":"","sources":["../../server/FFmpegBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAE/D,OAAO,EAAU,aAAa,EAAC,MAAM,MAAM,CAAC;AAW5C;;;;;;GAMG;AACH,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,OAAO,CAAqC;gBAGjC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,YAAY;IAMvC,OAAO,CAAC,aAAa,CASnB;IAEF,OAAO,CAAC,aAAa,CAiCnB;IAEF,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,YAAY;CAOrB"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FFmpegBridge = void 0;
4
+ const FFmpegExporterServer_1 = require("./FFmpegExporterServer");
5
+ /**
6
+ * A simple bridge between the FFmpegExporterServer and FFmpegExporterClient.
7
+ *
8
+ * @remarks
9
+ * This class lets the client exporter invoke methods on the server and receive
10
+ * responses using a simple Promise-based API.
11
+ */
12
+ class FFmpegBridge {
13
+ constructor(server, config) {
14
+ this.server = server;
15
+ this.config = config;
16
+ this.process = null;
17
+ this.handleRequest = async (req, res) => {
18
+ res.end();
19
+ await this.handleMessage({
20
+ method: req.url.slice(1),
21
+ data: req,
22
+ });
23
+ };
24
+ this.handleMessage = async ({ method, data }) => {
25
+ if (method === 'start') {
26
+ try {
27
+ this.process = new FFmpegExporterServer_1.FFmpegExporterServer(data, this.config);
28
+ this.respondSuccess(method, await this.process.start());
29
+ }
30
+ catch (e) {
31
+ this.respondError(method, e?.message);
32
+ }
33
+ return;
34
+ }
35
+ if (!this.process) {
36
+ this.respondError(method, 'The exporting process has not been started.');
37
+ return;
38
+ }
39
+ if (!(method in this.process)) {
40
+ this.respondError(method, `Unknown method: "${method}".`);
41
+ return;
42
+ }
43
+ try {
44
+ this.respondSuccess(method, await this.process[method](data));
45
+ }
46
+ catch (e) {
47
+ this.respondError(method, e?.message);
48
+ }
49
+ if (method === 'end') {
50
+ this.process = null;
51
+ }
52
+ };
53
+ server.ws.on('motion-canvas/ffmpeg', this.handleMessage);
54
+ server.middlewares.use('/ffmpeg', this.handleRequest);
55
+ }
56
+ respondSuccess(method, data = {}) {
57
+ this.server.ws.send('motion-canvas/ffmpeg-ack', {
58
+ status: 'success',
59
+ method,
60
+ data,
61
+ });
62
+ }
63
+ respondError(method, message = 'Unknown error.') {
64
+ this.server.ws.send('motion-canvas/ffmpeg-ack', {
65
+ status: 'error',
66
+ method,
67
+ message,
68
+ });
69
+ }
70
+ }
71
+ exports.FFmpegBridge = FFmpegBridge;
72
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRkZtcGVnQnJpZGdlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc2VydmVyL0ZGbXBlZ0JyaWRnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxpRUFHZ0M7QUFPaEM7Ozs7OztHQU1HO0FBQ0gsTUFBYSxZQUFZO0lBR3ZCLFlBQ21CLE1BQXFCLEVBQ3JCLE1BQW9CO1FBRHBCLFdBQU0sR0FBTixNQUFNLENBQWU7UUFDckIsV0FBTSxHQUFOLE1BQU0sQ0FBYztRQUovQixZQUFPLEdBQWdDLElBQUksQ0FBQztRQVU1QyxrQkFBYSxHQUFHLEtBQUssRUFDM0IsR0FBNEIsRUFDNUIsR0FBbUIsRUFDbkIsRUFBRTtZQUNGLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNWLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQztnQkFDdkIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxHQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztnQkFDekIsSUFBSSxFQUFFLEdBQUc7YUFDVixDQUFDLENBQUM7UUFDTCxDQUFDLENBQUM7UUFFTSxrQkFBYSxHQUFHLEtBQUssRUFBRSxFQUFDLE1BQU0sRUFBRSxJQUFJLEVBQWlCLEVBQUUsRUFBRTtZQUMvRCxJQUFJLE1BQU0sS0FBSyxPQUFPLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDO29CQUNILElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSwyQ0FBb0IsQ0FDckMsSUFBOEIsRUFDOUIsSUFBSSxDQUFDLE1BQU0sQ0FDWixDQUFDO29CQUNGLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO2dCQUMxRCxDQUFDO2dCQUFDLE9BQU8sQ0FBTSxFQUFFLENBQUM7b0JBQ2hCLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDeEMsQ0FBQztnQkFDRCxPQUFPO1lBQ1QsQ0FBQztZQUVELElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2xCLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLDZDQUE2QyxDQUFDLENBQUM7Z0JBQ3pFLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxDQUFDLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUM5QixJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxvQkFBb0IsTUFBTSxJQUFJLENBQUMsQ0FBQztnQkFDMUQsT0FBTztZQUNULENBQUM7WUFFRCxJQUFJLENBQUM7Z0JBQ0gsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsTUFBTyxJQUFJLENBQUMsT0FBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDekUsQ0FBQztZQUFDLE9BQU8sQ0FBTSxFQUFFLENBQUM7Z0JBQ2hCLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUN4QyxDQUFDO1lBRUQsSUFBSSxNQUFNLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQ3JCLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1lBQ3RCLENBQUM7UUFDSCxDQUFDLENBQUM7UUFoREEsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsc0JBQXNCLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQWdETyxjQUFjLENBQUMsTUFBYyxFQUFFLE9BQVksRUFBRTtRQUNuRCxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsMEJBQTBCLEVBQUU7WUFDOUMsTUFBTSxFQUFFLFNBQVM7WUFDakIsTUFBTTtZQUNOLElBQUk7U0FDTCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sWUFBWSxDQUFDLE1BQWMsRUFBRSxPQUFPLEdBQUcsZ0JBQWdCO1FBQzdELElBQUksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQywwQkFBMEIsRUFBRTtZQUM5QyxNQUFNLEVBQUUsT0FBTztZQUNmLE1BQU07WUFDTixPQUFPO1NBQ1IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBeEVELG9DQXdFQyJ9
@@ -0,0 +1,26 @@
1
+ import type { RendererResult, RendererSettings, Sound } from '@efxlab/motion-canvas-core';
2
+ import type { PluginConfig } from '@efxlab/motion-canvas-vite-plugin';
3
+ import { Readable } from 'stream';
4
+ export interface FFmpegExporterSettings extends RendererSettings {
5
+ audio?: string;
6
+ audioOffset?: number;
7
+ sounds: Sound[];
8
+ duration: number;
9
+ fastStart: boolean;
10
+ includeAudio: boolean;
11
+ audioSampleRate: number;
12
+ }
13
+ /**
14
+ * The server-side implementation of the FFmpeg video exporter.
15
+ */
16
+ export declare class FFmpegExporterServer {
17
+ private readonly config;
18
+ private readonly stream;
19
+ private readonly command;
20
+ private readonly promise;
21
+ constructor(settings: FFmpegExporterSettings, config: PluginConfig);
22
+ start(): Promise<void>;
23
+ handleFrame(req: Readable): Promise<void>;
24
+ end(result: RendererResult): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=FFmpegExporterServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FFmpegExporterServer.d.ts","sourceRoot":"","sources":["../../server/FFmpegExporterServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,KAAK,EACN,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAMpE,OAAO,EAAC,QAAQ,EAAC,MAAM,QAAQ,CAAC;AAMhC,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IAEjB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAoBD;;GAEG;AACH,qBAAa,oBAAoB;IAO7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAGtC,QAAQ,EAAE,sBAAsB,EACf,MAAM,EAAE,YAAY;IAgI1B,KAAK;IAQL,WAAW,CAAC,GAAG,EAAE,QAAQ;IAIzB,GAAG,CAAC,MAAM,EAAE,cAAc;CAaxC"}
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.FFmpegExporterServer = void 0;
40
+ const ffmpeg_ffprobe_static_1 = require("ffmpeg-ffprobe-static");
41
+ const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg"));
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ const ImageStream_1 = require("./ImageStream");
45
+ fluent_ffmpeg_1.default.setFfmpegPath(ffmpeg_ffprobe_static_1.ffmpegPath);
46
+ fluent_ffmpeg_1.default.setFfprobePath(ffmpeg_ffprobe_static_1.ffprobePath);
47
+ function formatFilters(filters) {
48
+ return filters
49
+ .map(f => {
50
+ let options = [];
51
+ if (typeof f.options === 'string') {
52
+ options = [f.options];
53
+ }
54
+ else if (f.options.constructor === Array) {
55
+ options = f.options;
56
+ }
57
+ else {
58
+ options = Object.entries(f.options)
59
+ .filter(([, v]) => v !== undefined)
60
+ .map(([k, v]) => `${k}=${v}`);
61
+ }
62
+ return `${f.filter}=${options.join(':')}`;
63
+ })
64
+ .join(',');
65
+ }
66
+ /**
67
+ * The server-side implementation of the FFmpeg video exporter.
68
+ */
69
+ class FFmpegExporterServer {
70
+ constructor(settings, config) {
71
+ this.config = config;
72
+ const size = {
73
+ x: Math.round(settings.size.x * settings.resolutionScale),
74
+ y: Math.round(settings.size.y * settings.resolutionScale),
75
+ };
76
+ this.stream = new ImageStream_1.ImageStream(size);
77
+ this.command = (0, fluent_ffmpeg_1.default)();
78
+ // Input image sequence
79
+ this.command
80
+ .input(this.stream)
81
+ .inputFormat('rawvideo')
82
+ .inputOptions(['-pix_fmt rgba', '-s:v', `${size.x}x${size.y}`])
83
+ .inputFps(settings.fps);
84
+ // Input audio
85
+ const sounds = [...settings.sounds];
86
+ if (settings.audio && settings.includeAudio) {
87
+ sounds.push({
88
+ audio: settings.audio,
89
+ realPlaybackRate: 1,
90
+ offset: settings.audioOffset ?? 0,
91
+ });
92
+ }
93
+ const filterSpec = [];
94
+ const streams = [];
95
+ for (let i = 0; i < sounds.length; i++) {
96
+ const sound = sounds[i];
97
+ this.command.input(sound.audio.slice(1));
98
+ let trimmed = sound.start ?? 0;
99
+ if (sound.offset < 0) {
100
+ trimmed -= sound.offset * sound.realPlaybackRate;
101
+ }
102
+ if (trimmed !== 0) {
103
+ this.command.inputOptions(`-ss ${trimmed}`);
104
+ }
105
+ const filters = [];
106
+ if (sound.end !== undefined) {
107
+ filters.push({
108
+ filter: 'atrim',
109
+ options: { end: sound.end - trimmed },
110
+ });
111
+ }
112
+ filters.push({
113
+ filter: 'aresample',
114
+ options: settings.audioSampleRate.toString(),
115
+ });
116
+ if (sound.gain) {
117
+ filters.push({
118
+ filter: 'volume',
119
+ options: { volume: `${sound.gain}dB` },
120
+ });
121
+ }
122
+ if (sound.realPlaybackRate !== 1) {
123
+ const rate = Math.round(settings.audioSampleRate * sound.realPlaybackRate);
124
+ filters.push({
125
+ filter: 'asetrate',
126
+ options: { r: rate },
127
+ });
128
+ filters.push({
129
+ filter: 'aresample',
130
+ options: settings.audioSampleRate.toString(),
131
+ });
132
+ }
133
+ if (sound.offset > 0) {
134
+ const delay = Math.round(sound.offset * 1000);
135
+ filters.push({
136
+ filter: 'adelay',
137
+ options: { delays: delay, all: 1 },
138
+ });
139
+ }
140
+ if (filters.length > 0) {
141
+ filterSpec.push({
142
+ inputs: `${i + 1}:a`,
143
+ filter: formatFilters(filters),
144
+ outputs: `a${i + 1}`,
145
+ });
146
+ streams.push(`a${i + 1}`);
147
+ }
148
+ else {
149
+ streams.push(`${i + 1}:a`);
150
+ }
151
+ }
152
+ if (sounds.length > 0) {
153
+ this.command.complexFilter([
154
+ ...filterSpec,
155
+ {
156
+ filter: 'amix',
157
+ // eslint-disable-next-line @typescript-eslint/naming-convention
158
+ options: { inputs: sounds.length, dropout_transition: 0, normalize: 0 },
159
+ inputs: streams,
160
+ outputs: 'a',
161
+ },
162
+ ]);
163
+ this.command.outputOptions(['-map 0:v', '-map [a]']);
164
+ }
165
+ // Output settings
166
+ this.command
167
+ .output(path.join(this.config.output, `${settings.name}.mp4`))
168
+ .outputOptions([
169
+ '-pix_fmt yuv420p',
170
+ `-t ${settings.duration / settings.fps}`,
171
+ ])
172
+ .outputFps(settings.fps)
173
+ .size(`${size.x}x${size.y}`);
174
+ if (settings.fastStart) {
175
+ this.command.outputOptions(['-movflags +faststart']);
176
+ }
177
+ this.promise = new Promise((resolve, reject) => {
178
+ this.command.on('end', () => resolve()).on('error', reject);
179
+ });
180
+ }
181
+ async start() {
182
+ if (!fs.existsSync(this.config.output)) {
183
+ await fs.promises.mkdir(this.config.output, { recursive: true });
184
+ }
185
+ this.command.on('stderr', console.error);
186
+ this.command.run();
187
+ }
188
+ async handleFrame(req) {
189
+ await this.stream.pushImage(req);
190
+ }
191
+ async end(result) {
192
+ this.stream.pushImage(null);
193
+ if (result === 1) {
194
+ try {
195
+ this.command.kill('SIGKILL');
196
+ await this.promise;
197
+ }
198
+ catch (_) {
199
+ // do nothing
200
+ }
201
+ }
202
+ else {
203
+ await this.promise;
204
+ }
205
+ }
206
+ }
207
+ exports.FFmpegExporterServer = FFmpegExporterServer;
208
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRkZtcGVnRXhwb3J0ZXJTZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zZXJ2ZXIvRkZtcGVnRXhwb3J0ZXJTZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBTUEsaUVBQThEO0FBRTlELGtFQUFtQztBQUNuQyx1Q0FBeUI7QUFDekIsMkNBQTZCO0FBRTdCLCtDQUEwQztBQUUxQyx1QkFBTSxDQUFDLGFBQWEsQ0FBQyxrQ0FBVyxDQUFDLENBQUM7QUFDbEMsdUJBQU0sQ0FBQyxjQUFjLENBQUMsbUNBQVksQ0FBQyxDQUFDO0FBY3BDLFNBQVMsYUFBYSxDQUFDLE9BQTJCO0lBQ2hELE9BQU8sT0FBTztTQUNYLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRTtRQUNQLElBQUksT0FBTyxHQUFhLEVBQUUsQ0FBQztRQUMzQixJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNsQyxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEIsQ0FBQzthQUFNLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDM0MsT0FBTyxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUM7UUFDdEIsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO2lCQUNoQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxTQUFTLENBQUM7aUJBQ2xDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2xDLENBQUM7UUFDRCxPQUFPLEdB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
@@ -0,0 +1,12 @@
1
+ import { Readable } from 'stream';
2
+ export declare class ImageStream extends Readable {
3
+ private size;
4
+ private queue;
5
+ constructor(size: {
6
+ x: number;
7
+ y: number;
8
+ });
9
+ pushImage(readable: Readable | null): Promise<void>;
10
+ _read(): void;
11
+ }
12
+ //# sourceMappingURL=ImageStream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageStream.d.ts","sourceRoot":"","sources":["../../server/ImageStream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,QAAQ,CAAC;AAYhC,qBAAa,WAAY,SAAQ,QAAQ;IAGpB,OAAO,CAAC,IAAI;IAF/B,OAAO,CAAC,KAAK,CAAmB;gBAEL,IAAI,EAAE;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAC;IAI1C,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA6BhC,KAAK;CAiBtB"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ImageStream = void 0;
4
+ const stream_1 = require("stream");
5
+ class ImageStream extends stream_1.Readable {
6
+ constructor(size) {
7
+ super();
8
+ this.size = size;
9
+ this.queue = [];
10
+ }
11
+ async pushImage(readable) {
12
+ if (readable) {
13
+ const length = this.size.x * this.size.y * 4;
14
+ const item = {
15
+ type: 'frame',
16
+ array: new Uint8Array(length),
17
+ finished: false,
18
+ };
19
+ this.queue.push(item);
20
+ let pointer = 0;
21
+ readable.on('data', (chunk) => {
22
+ item.array.set(chunk, pointer);
23
+ pointer += chunk.length;
24
+ });
25
+ await new Promise((resolve, reject) => {
26
+ readable.on('end', resolve).on('error', reject);
27
+ });
28
+ item.finished = true;
29
+ }
30
+ else {
31
+ this.queue.push({ type: 'end' });
32
+ }
33
+ this._read();
34
+ }
35
+ // eslint-disable-next-line @typescript-eslint/naming-convention
36
+ _read() {
37
+ while (this.queue.length > 0) {
38
+ const item = this.queue[0];
39
+ if (item.type === 'end') {
40
+ this.queue = [];
41
+ this.push(null);
42
+ return;
43
+ }
44
+ if (!item.finished) {
45
+ return;
46
+ }
47
+ this.queue.shift();
48
+ this.push(item.array);
49
+ }
50
+ }
51
+ }
52
+ exports.ImageStream = ImageStream;
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW1hZ2VTdHJlYW0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zZXJ2ZXIvSW1hZ2VTdHJlYW0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQWdDO0FBWWhDLE1BQWEsV0FBWSxTQUFRLGlCQUFRO0lBR3ZDLFlBQTJCLElBQTRCO1FBQ3JELEtBQUssRUFBRSxDQUFDO1FBRGlCLFNBQUksR0FBSixJQUFJLENBQXdCO1FBRi9DLFVBQUssR0FBZ0IsRUFBRSxDQUFDO0lBSWhDLENBQUM7SUFFTSxLQUFLLENBQUMsU0FBUyxDQUFDLFFBQXlCO1FBQzlDLElBQUksUUFBUSxFQUFFLENBQUM7WUFDYixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDN0MsTUFBTSxJQUFJLEdBQWM7Z0JBQ3RCLElBQUksRUFBRSxPQUFPO2dCQUNiLEtBQUssRUFBRSxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUM7Z0JBQzdCLFFBQVEsRUFBRSxLQUFLO2FBQ2hCLENBQUM7WUFDRixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUV0QixJQUFJLE9BQU8sR0FBRyxDQUFDLENBQUM7WUFDaEIsUUFBUSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFpQixFQUFFLEVBQUU7Z0JBQ3hDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDL0IsT0FBTyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUM7WUFDMUIsQ0FBQyxDQUFDLENBQUM7WUFFSCxNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUNwQyxRQUFRLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ2xELENBQUMsQ0FBQyxDQUFDO1lBRUgsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7UUFDdkIsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLElBQUksRUFBRSxLQUFLLEVBQUMsQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFFRCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDZixDQUFDO0lBRUQsZ0VBQWdFO0lBQ2hELEtBQUs7UUFDbkIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzNCLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDeEIsSUFBSSxDQUFDLEtBQUssR0FBRyxFQUFFLENBQUM7Z0JBQ2hCLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2hCLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDbkIsT0FBTztZQUNULENBQUM7WUFFRCxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ25CLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hCLENBQUM7SUFDSCxDQUFDO0NBQ0Y7QUFyREQsa0NBcURDIn0=
@@ -0,0 +1,4 @@
1
+ import { Plugin } from '@efxlab/motion-canvas-vite-plugin';
2
+ declare const _default: () => Plugin;
3
+ export default _default;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EAGP,MAAM,mCAAmC,CAAC;8BAGxB,MAAM;AAAzB,wBAcE"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const motion_canvas_vite_plugin_1 = require("@efxlab/motion-canvas-vite-plugin");
4
+ const FFmpegBridge_1 = require("./FFmpegBridge");
5
+ exports.default = () => {
6
+ let config;
7
+ return {
8
+ name: 'motion-canvas/ffmpeg',
9
+ [motion_canvas_vite_plugin_1.PLUGIN_OPTIONS]: {
10
+ entryPoint: '@efxlab/motion-canvas-ffmpeg/lib/client',
11
+ async config(value) {
12
+ config = value;
13
+ },
14
+ },
15
+ configureServer(server) {
16
+ new FFmpegBridge_1.FFmpegBridge(server, config);
17
+ },
18
+ };
19
+ };
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zZXJ2ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxpRkFJMkM7QUFDM0MsaURBQTRDO0FBRTVDLGtCQUFlLEdBQVcsRUFBRTtJQUMxQixJQUFJLE1BQW9CLENBQUM7SUFDekIsT0FBTztRQUNMLElBQUksRUFBRSxzQkFBc0I7UUFDNUIsQ0FBQywwQ0FBYyxDQUFDLEVBQUU7WUFDaEIsVUFBVSxFQUFFLHlDQUF5QztZQUNyRCxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUs7Z0JBQ2hCLE1BQU0sR0FBRyxLQUFLLENBQUM7WUFDakIsQ0FBQztTQUNGO1FBQ0QsZUFBZSxDQUFDLE1BQVc7WUFDekIsSUFBSSwyQkFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNuQyxDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUMsQ0FBQyJ9
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@efxlab/motion-canvas-ffmpeg",
3
+ "version": "4.0.0",
4
+ "description": "An FFmpeg video exporter for Motion Canvas",
5
+ "main": "lib/server/index.js",
6
+ "author": "motion-canvas",
7
+ "homepage": "https://motioncanvas.io/",
8
+ "bugs": "https://github.com/motion-canvas/motion-canvas/issues",
9
+ "license": "GPLv3",
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "scripts": {
14
+ "build": "npm run client:build && npm run server:build",
15
+ "client:build": "tsc --project client/tsconfig.json",
16
+ "client:dev": "tsc -w --project client/tsconfig.json",
17
+ "server:build": "tsc --project server/tsconfig.json",
18
+ "server:dev": "tsc -w --project server/tsconfig.json"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/electroheadfx/efx-motion-canvas.git"
23
+ },
24
+ "files": [
25
+ "lib"
26
+ ],
27
+ "devDependencies": {
28
+ "@types/fluent-ffmpeg": "^2.1.21"
29
+ },
30
+ "dependencies": {
31
+ "@efxlab/motion-canvas-core": "workspace:*",
32
+ "@efxlab/motion-canvas-vite-plugin": "workspace:*",
33
+ "ffmpeg-ffprobe-static": "^6.1.1-rc.5",
34
+ "fluent-ffmpeg": "^2.1.3"
35
+ }
36
+ }