@gannochenko/staticstripes 0.0.22 → 0.0.24
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/Makefile +8 -0
- package/dist/app-builder.d.ts +18 -0
- package/dist/app-builder.d.ts.map +1 -0
- package/dist/app-builder.js +94 -0
- package/dist/app-builder.js.map +1 -0
- package/dist/cli/commands/filters.d.ts +3 -0
- package/dist/cli/commands/filters.d.ts.map +1 -0
- package/dist/cli/commands/filters.js +21 -0
- package/dist/cli/commands/filters.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +6 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.d.ts +5 -0
- package/dist/cli/instagram/instagram-upload-strategy.d.ts.map +1 -1
- package/dist/cli/instagram/instagram-upload-strategy.js +46 -3
- package/dist/cli/instagram/instagram-upload-strategy.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/ffmpeg.d.ts +32 -0
- package/dist/ffmpeg.d.ts.map +1 -1
- package/dist/ffmpeg.js +118 -0
- package/dist/ffmpeg.js.map +1 -1
- package/dist/html-project-parser.d.ts +36 -1
- package/dist/html-project-parser.d.ts.map +1 -1
- package/dist/html-project-parser.js +332 -15
- package/dist/html-project-parser.js.map +1 -1
- package/dist/project.d.ts +4 -1
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +50 -1
- package/dist/project.js.map +1 -1
- package/dist/sample-sequences.d.ts.map +1 -1
- package/dist/sample-sequences.js +293 -0
- package/dist/sample-sequences.js.map +1 -1
- package/dist/sequence.d.ts +4 -1
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +71 -21
- package/dist/sequence.js.map +1 -1
- package/dist/stream.d.ts +17 -0
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +28 -0
- package/dist/stream.js.map +1 -1
- package/dist/type.d.ts +29 -2
- package/dist/type.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/app-builder.ts +113 -0
- package/src/cli/commands/filters.ts +21 -0
- package/src/cli/commands/generate.ts +10 -1
- package/src/cli/instagram/instagram-upload-strategy.ts +61 -1
- package/src/cli.ts +2 -0
- package/src/ffmpeg.ts +161 -0
- package/src/html-project-parser.ts +410 -28
- package/src/project.ts +62 -0
- package/src/sample-sequences.ts +300 -0
- package/src/sequence.ts +78 -22
- package/src/stream.ts +50 -0
- package/src/type.ts +31 -2
package/src/sample-sequences.ts
CHANGED
|
@@ -36,8 +36,19 @@ export const getSampleSequences = (
|
|
|
36
36
|
objectFitContainAmbientBrightness: -0.1,
|
|
37
37
|
objectFitContainAmbientSaturation: 0.7,
|
|
38
38
|
objectFitContainPillarboxColor: '#000000',
|
|
39
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
40
|
+
objectFitKenBurnsZoom: 30,
|
|
41
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
42
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
43
|
+
objectFitKenBurnsFocalX: 50,
|
|
44
|
+
objectFitKenBurnsFocalY: 50,
|
|
45
|
+
objectFitKenBurnsPanStartX: 0,
|
|
46
|
+
objectFitKenBurnsPanStartY: 0,
|
|
47
|
+
objectFitKenBurnsPanEndX: 100,
|
|
48
|
+
objectFitKenBurnsPanEndY: 100,
|
|
39
49
|
chromakey: false,
|
|
40
50
|
chromakeyBlend: 0.1,
|
|
51
|
+
sound: 'on' as const,
|
|
41
52
|
chromakeySimilarity: 0.1,
|
|
42
53
|
chromakeyColor: '#000000',
|
|
43
54
|
},
|
|
@@ -59,8 +70,19 @@ export const getSampleSequences = (
|
|
|
59
70
|
objectFitContainAmbientBrightness: -0.1,
|
|
60
71
|
objectFitContainAmbientSaturation: 0.7,
|
|
61
72
|
objectFitContainPillarboxColor: '#000000',
|
|
73
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
74
|
+
objectFitKenBurnsZoom: 30,
|
|
75
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
76
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
77
|
+
objectFitKenBurnsFocalX: 50,
|
|
78
|
+
objectFitKenBurnsFocalY: 50,
|
|
79
|
+
objectFitKenBurnsPanStartX: 0,
|
|
80
|
+
objectFitKenBurnsPanStartY: 0,
|
|
81
|
+
objectFitKenBurnsPanEndX: 100,
|
|
82
|
+
objectFitKenBurnsPanEndY: 100,
|
|
62
83
|
chromakey: false,
|
|
63
84
|
chromakeyBlend: 0.1,
|
|
85
|
+
sound: 'on' as const,
|
|
64
86
|
chromakeySimilarity: 0.1,
|
|
65
87
|
chromakeyColor: '#000000',
|
|
66
88
|
},
|
|
@@ -82,10 +104,21 @@ export const getSampleSequences = (
|
|
|
82
104
|
objectFitContainAmbientBrightness: -0.1,
|
|
83
105
|
objectFitContainAmbientSaturation: 0.7,
|
|
84
106
|
objectFitContainPillarboxColor: '#000000',
|
|
107
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
108
|
+
objectFitKenBurnsZoom: 30,
|
|
109
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
110
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
111
|
+
objectFitKenBurnsFocalX: 50,
|
|
112
|
+
objectFitKenBurnsFocalY: 50,
|
|
113
|
+
objectFitKenBurnsPanStartX: 0,
|
|
114
|
+
objectFitKenBurnsPanStartY: 0,
|
|
115
|
+
objectFitKenBurnsPanEndX: 100,
|
|
116
|
+
objectFitKenBurnsPanEndY: 100,
|
|
85
117
|
chromakey: true,
|
|
86
118
|
chromakeyBlend: 0.1,
|
|
87
119
|
chromakeySimilarity: 0.1,
|
|
88
120
|
chromakeyColor: '#000000',
|
|
121
|
+
sound: 'on' as const,
|
|
89
122
|
},
|
|
90
123
|
{
|
|
91
124
|
id: 'f_04',
|
|
@@ -105,8 +138,19 @@ export const getSampleSequences = (
|
|
|
105
138
|
objectFitContainAmbientBrightness: -0.1,
|
|
106
139
|
objectFitContainAmbientSaturation: 0.7,
|
|
107
140
|
objectFitContainPillarboxColor: '#000000',
|
|
141
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
142
|
+
objectFitKenBurnsZoom: 30,
|
|
143
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
144
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
145
|
+
objectFitKenBurnsFocalX: 50,
|
|
146
|
+
objectFitKenBurnsFocalY: 50,
|
|
147
|
+
objectFitKenBurnsPanStartX: 0,
|
|
148
|
+
objectFitKenBurnsPanStartY: 0,
|
|
149
|
+
objectFitKenBurnsPanEndX: 100,
|
|
150
|
+
objectFitKenBurnsPanEndY: 100,
|
|
108
151
|
chromakey: false,
|
|
109
152
|
chromakeyBlend: 0.1,
|
|
153
|
+
sound: 'on' as const,
|
|
110
154
|
chromakeySimilarity: 0.1,
|
|
111
155
|
chromakeyColor: '#000000',
|
|
112
156
|
},
|
|
@@ -128,8 +172,19 @@ export const getSampleSequences = (
|
|
|
128
172
|
objectFitContainAmbientBrightness: -0.1,
|
|
129
173
|
objectFitContainAmbientSaturation: 0.7,
|
|
130
174
|
objectFitContainPillarboxColor: '#000000',
|
|
175
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
176
|
+
objectFitKenBurnsZoom: 30,
|
|
177
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
178
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
179
|
+
objectFitKenBurnsFocalX: 50,
|
|
180
|
+
objectFitKenBurnsFocalY: 50,
|
|
181
|
+
objectFitKenBurnsPanStartX: 0,
|
|
182
|
+
objectFitKenBurnsPanStartY: 0,
|
|
183
|
+
objectFitKenBurnsPanEndX: 100,
|
|
184
|
+
objectFitKenBurnsPanEndY: 100,
|
|
131
185
|
chromakey: false,
|
|
132
186
|
chromakeyBlend: 0.1,
|
|
187
|
+
sound: 'on' as const,
|
|
133
188
|
chromakeySimilarity: 0.1,
|
|
134
189
|
chromakeyColor: '#000000',
|
|
135
190
|
},
|
|
@@ -163,8 +218,19 @@ export const getSampleSequences = (
|
|
|
163
218
|
objectFitContainAmbientBrightness: -0.1,
|
|
164
219
|
objectFitContainAmbientSaturation: 0.7,
|
|
165
220
|
objectFitContainPillarboxColor: '#000000',
|
|
221
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
222
|
+
objectFitKenBurnsZoom: 30,
|
|
223
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
224
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
225
|
+
objectFitKenBurnsFocalX: 50,
|
|
226
|
+
objectFitKenBurnsFocalY: 50,
|
|
227
|
+
objectFitKenBurnsPanStartX: 0,
|
|
228
|
+
objectFitKenBurnsPanStartY: 0,
|
|
229
|
+
objectFitKenBurnsPanEndX: 100,
|
|
230
|
+
objectFitKenBurnsPanEndY: 100,
|
|
166
231
|
chromakey: false,
|
|
167
232
|
chromakeyBlend: 0.1,
|
|
233
|
+
sound: 'on' as const,
|
|
168
234
|
chromakeySimilarity: 0.1,
|
|
169
235
|
chromakeyColor: '#000000',
|
|
170
236
|
},
|
|
@@ -198,8 +264,19 @@ export const getSampleSequences = (
|
|
|
198
264
|
objectFitContainAmbientBrightness: -0.1,
|
|
199
265
|
objectFitContainAmbientSaturation: 0.7,
|
|
200
266
|
objectFitContainPillarboxColor: '#000000',
|
|
267
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
268
|
+
objectFitKenBurnsZoom: 30,
|
|
269
|
+
objectFitKenBurnsEffectDuration: 0,
|
|
270
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
271
|
+
objectFitKenBurnsFocalX: 50,
|
|
272
|
+
objectFitKenBurnsFocalY: 50,
|
|
273
|
+
objectFitKenBurnsPanStartX: 0,
|
|
274
|
+
objectFitKenBurnsPanStartY: 0,
|
|
275
|
+
objectFitKenBurnsPanEndX: 100,
|
|
276
|
+
objectFitKenBurnsPanEndY: 100,
|
|
201
277
|
chromakey: false,
|
|
202
278
|
chromakeyBlend: 0.1,
|
|
279
|
+
sound: 'on' as const,
|
|
203
280
|
chromakeySimilarity: 0.1,
|
|
204
281
|
chromakeyColor: '#000000',
|
|
205
282
|
},
|
|
@@ -211,6 +288,229 @@ export const getSampleSequences = (
|
|
|
211
288
|
);
|
|
212
289
|
seq3.build();
|
|
213
290
|
|
|
291
|
+
// Ken Burns effect test sequence - using intro_image for all effect types
|
|
292
|
+
const seq4 = new Sequence(
|
|
293
|
+
buf,
|
|
294
|
+
{
|
|
295
|
+
fragments: [
|
|
296
|
+
// zoom-in effect with custom focal point
|
|
297
|
+
{
|
|
298
|
+
id: 'kb_zoom_in',
|
|
299
|
+
enabled: true,
|
|
300
|
+
assetName: 'intro_image',
|
|
301
|
+
duration: 3000,
|
|
302
|
+
trimLeft: 0,
|
|
303
|
+
overlayLeft: 0,
|
|
304
|
+
overlayZIndex: 1,
|
|
305
|
+
transitionIn: '',
|
|
306
|
+
transitionInDuration: 0,
|
|
307
|
+
transitionOut: '',
|
|
308
|
+
transitionOutDuration: 0,
|
|
309
|
+
objectFit: 'ken-burns',
|
|
310
|
+
objectFitContain: 'ambient',
|
|
311
|
+
objectFitContainAmbientBlurStrength: 25,
|
|
312
|
+
objectFitContainAmbientBrightness: -0.1,
|
|
313
|
+
objectFitContainAmbientSaturation: 0.7,
|
|
314
|
+
objectFitContainPillarboxColor: '#000000',
|
|
315
|
+
objectFitKenBurns: 'zoom-in' as const,
|
|
316
|
+
objectFitKenBurnsZoom: 50,
|
|
317
|
+
objectFitKenBurnsEffectDuration: 1000,
|
|
318
|
+
objectFitKenBurnsEasing: 'ease-in-out' as const,
|
|
319
|
+
objectFitKenBurnsFocalX: 30,
|
|
320
|
+
objectFitKenBurnsFocalY: 40,
|
|
321
|
+
objectFitKenBurnsPanStartX: 0,
|
|
322
|
+
objectFitKenBurnsPanStartY: 0,
|
|
323
|
+
objectFitKenBurnsPanEndX: 100,
|
|
324
|
+
objectFitKenBurnsPanEndY: 100,
|
|
325
|
+
chromakey: false,
|
|
326
|
+
chromakeyBlend: 0.1,
|
|
327
|
+
sound: 'on' as const,
|
|
328
|
+
chromakeySimilarity: 0.1,
|
|
329
|
+
chromakeyColor: '#000000',
|
|
330
|
+
},
|
|
331
|
+
// zoom-out effect with center focal point
|
|
332
|
+
{
|
|
333
|
+
id: 'kb_zoom_out',
|
|
334
|
+
enabled: true,
|
|
335
|
+
assetName: 'intro_image',
|
|
336
|
+
duration: 3000,
|
|
337
|
+
trimLeft: 0,
|
|
338
|
+
overlayLeft: 0,
|
|
339
|
+
overlayZIndex: 1,
|
|
340
|
+
transitionIn: '',
|
|
341
|
+
transitionInDuration: 0,
|
|
342
|
+
transitionOut: '',
|
|
343
|
+
transitionOutDuration: 0,
|
|
344
|
+
objectFit: 'ken-burns',
|
|
345
|
+
objectFitContain: 'ambient',
|
|
346
|
+
objectFitContainAmbientBlurStrength: 25,
|
|
347
|
+
objectFitContainAmbientBrightness: -0.1,
|
|
348
|
+
objectFitContainAmbientSaturation: 0.7,
|
|
349
|
+
objectFitContainPillarboxColor: '#000000',
|
|
350
|
+
objectFitKenBurns: 'zoom-out' as const,
|
|
351
|
+
objectFitKenBurnsZoom: 40,
|
|
352
|
+
objectFitKenBurnsEffectDuration: 2000,
|
|
353
|
+
objectFitKenBurnsEasing: 'ease-in' as const,
|
|
354
|
+
objectFitKenBurnsFocalX: 50,
|
|
355
|
+
objectFitKenBurnsFocalY: 50,
|
|
356
|
+
objectFitKenBurnsPanStartX: 0,
|
|
357
|
+
objectFitKenBurnsPanStartY: 0,
|
|
358
|
+
objectFitKenBurnsPanEndX: 100,
|
|
359
|
+
objectFitKenBurnsPanEndY: 100,
|
|
360
|
+
chromakey: false,
|
|
361
|
+
chromakeyBlend: 0.1,
|
|
362
|
+
sound: 'on' as const,
|
|
363
|
+
chromakeySimilarity: 0.1,
|
|
364
|
+
chromakeyColor: '#000000',
|
|
365
|
+
},
|
|
366
|
+
// pan-left effect
|
|
367
|
+
{
|
|
368
|
+
id: 'kb_pan_left',
|
|
369
|
+
enabled: true,
|
|
370
|
+
assetName: 'intro_image',
|
|
371
|
+
duration: 3000,
|
|
372
|
+
trimLeft: 0,
|
|
373
|
+
overlayLeft: 0,
|
|
374
|
+
overlayZIndex: 1,
|
|
375
|
+
transitionIn: '',
|
|
376
|
+
transitionInDuration: 0,
|
|
377
|
+
transitionOut: '',
|
|
378
|
+
transitionOutDuration: 0,
|
|
379
|
+
objectFit: 'ken-burns',
|
|
380
|
+
objectFitContain: 'ambient',
|
|
381
|
+
objectFitContainAmbientBlurStrength: 25,
|
|
382
|
+
objectFitContainAmbientBrightness: -0.1,
|
|
383
|
+
objectFitContainAmbientSaturation: 0.7,
|
|
384
|
+
objectFitContainPillarboxColor: '#000000',
|
|
385
|
+
objectFitKenBurns: 'pan-left' as const,
|
|
386
|
+
objectFitKenBurnsZoom: 30,
|
|
387
|
+
objectFitKenBurnsEffectDuration: 1500,
|
|
388
|
+
objectFitKenBurnsEasing: 'linear' as const,
|
|
389
|
+
objectFitKenBurnsFocalX: 50,
|
|
390
|
+
objectFitKenBurnsFocalY: 50,
|
|
391
|
+
objectFitKenBurnsPanStartX: 0,
|
|
392
|
+
objectFitKenBurnsPanStartY: 0,
|
|
393
|
+
objectFitKenBurnsPanEndX: 100,
|
|
394
|
+
objectFitKenBurnsPanEndY: 100,
|
|
395
|
+
chromakey: false,
|
|
396
|
+
chromakeyBlend: 0.1,
|
|
397
|
+
sound: 'on' as const,
|
|
398
|
+
chromakeySimilarity: 0.1,
|
|
399
|
+
chromakeyColor: '#000000',
|
|
400
|
+
},
|
|
401
|
+
// pan-right effect
|
|
402
|
+
{
|
|
403
|
+
id: 'kb_pan_right',
|
|
404
|
+
enabled: true,
|
|
405
|
+
assetName: 'intro_image',
|
|
406
|
+
duration: 3000,
|
|
407
|
+
trimLeft: 0,
|
|
408
|
+
overlayLeft: 0,
|
|
409
|
+
overlayZIndex: 1,
|
|
410
|
+
transitionIn: '',
|
|
411
|
+
transitionInDuration: 0,
|
|
412
|
+
transitionOut: '',
|
|
413
|
+
transitionOutDuration: 0,
|
|
414
|
+
objectFit: 'ken-burns',
|
|
415
|
+
objectFitContain: 'ambient',
|
|
416
|
+
objectFitContainAmbientBlurStrength: 25,
|
|
417
|
+
objectFitContainAmbientBrightness: -0.1,
|
|
418
|
+
objectFitContainAmbientSaturation: 0.7,
|
|
419
|
+
objectFitContainPillarboxColor: '#000000',
|
|
420
|
+
objectFitKenBurns: 'pan-right' as const,
|
|
421
|
+
objectFitKenBurnsZoom: 50,
|
|
422
|
+
objectFitKenBurnsEffectDuration: 1500,
|
|
423
|
+
objectFitKenBurnsEasing: 'ease-out' as const,
|
|
424
|
+
objectFitKenBurnsFocalX: 50,
|
|
425
|
+
objectFitKenBurnsFocalY: 50,
|
|
426
|
+
objectFitKenBurnsPanStartX: 0,
|
|
427
|
+
objectFitKenBurnsPanStartY: 0,
|
|
428
|
+
objectFitKenBurnsPanEndX: 100,
|
|
429
|
+
objectFitKenBurnsPanEndY: 100,
|
|
430
|
+
chromakey: false,
|
|
431
|
+
chromakeyBlend: 0.1,
|
|
432
|
+
sound: 'on' as const,
|
|
433
|
+
chromakeySimilarity: 0.1,
|
|
434
|
+
chromakeyColor: '#000000',
|
|
435
|
+
},
|
|
436
|
+
// pan-top effect
|
|
437
|
+
{
|
|
438
|
+
id: 'kb_pan_top',
|
|
439
|
+
enabled: true,
|
|
440
|
+
assetName: 'intro_image',
|
|
441
|
+
duration: 3000,
|
|
442
|
+
trimLeft: 0,
|
|
443
|
+
overlayLeft: 0,
|
|
444
|
+
overlayZIndex: 1,
|
|
445
|
+
transitionIn: '',
|
|
446
|
+
transitionInDuration: 0,
|
|
447
|
+
transitionOut: '',
|
|
448
|
+
transitionOutDuration: 0,
|
|
449
|
+
objectFit: 'ken-burns',
|
|
450
|
+
objectFitContain: 'ambient',
|
|
451
|
+
objectFitContainAmbientBlurStrength: 25,
|
|
452
|
+
objectFitContainAmbientBrightness: -0.1,
|
|
453
|
+
objectFitContainAmbientSaturation: 0.7,
|
|
454
|
+
objectFitContainPillarboxColor: '#000000',
|
|
455
|
+
objectFitKenBurns: 'pan-top' as const,
|
|
456
|
+
objectFitKenBurnsZoom: 30,
|
|
457
|
+
objectFitKenBurnsEffectDuration: 1500,
|
|
458
|
+
objectFitKenBurnsEasing: 'ease-in' as const,
|
|
459
|
+
objectFitKenBurnsFocalX: 50,
|
|
460
|
+
objectFitKenBurnsFocalY: 50,
|
|
461
|
+
objectFitKenBurnsPanStartX: 0,
|
|
462
|
+
objectFitKenBurnsPanStartY: 0,
|
|
463
|
+
objectFitKenBurnsPanEndX: 100,
|
|
464
|
+
objectFitKenBurnsPanEndY: 100,
|
|
465
|
+
chromakey: false,
|
|
466
|
+
chromakeyBlend: 0.1,
|
|
467
|
+
sound: 'on' as const,
|
|
468
|
+
chromakeySimilarity: 0.1,
|
|
469
|
+
chromakeyColor: '#000000',
|
|
470
|
+
},
|
|
471
|
+
// pan-bottom effect
|
|
472
|
+
{
|
|
473
|
+
id: 'kb_pan_bottom',
|
|
474
|
+
enabled: true,
|
|
475
|
+
assetName: 'intro_image',
|
|
476
|
+
duration: 3000,
|
|
477
|
+
trimLeft: 0,
|
|
478
|
+
overlayLeft: 0,
|
|
479
|
+
overlayZIndex: 1,
|
|
480
|
+
transitionIn: '',
|
|
481
|
+
transitionInDuration: 0,
|
|
482
|
+
transitionOut: '',
|
|
483
|
+
transitionOutDuration: 0,
|
|
484
|
+
objectFit: 'ken-burns',
|
|
485
|
+
objectFitContain: 'ambient',
|
|
486
|
+
objectFitContainAmbientBlurStrength: 25,
|
|
487
|
+
objectFitContainAmbientBrightness: -0.1,
|
|
488
|
+
objectFitContainAmbientSaturation: 0.7,
|
|
489
|
+
objectFitContainPillarboxColor: '#000000',
|
|
490
|
+
objectFitKenBurns: 'pan-bottom' as const,
|
|
491
|
+
objectFitKenBurnsZoom: 40,
|
|
492
|
+
objectFitKenBurnsEffectDuration: 1500,
|
|
493
|
+
objectFitKenBurnsEasing: 'ease-in-out' as const,
|
|
494
|
+
objectFitKenBurnsFocalX: 50,
|
|
495
|
+
objectFitKenBurnsFocalY: 50,
|
|
496
|
+
objectFitKenBurnsPanStartX: 0,
|
|
497
|
+
objectFitKenBurnsPanStartY: 0,
|
|
498
|
+
objectFitKenBurnsPanEndX: 100,
|
|
499
|
+
objectFitKenBurnsPanEndY: 100,
|
|
500
|
+
chromakey: false,
|
|
501
|
+
chromakeyBlend: 0.1,
|
|
502
|
+
sound: 'on' as const,
|
|
503
|
+
chromakeySimilarity: 0.1,
|
|
504
|
+
chromakeyColor: '#000000',
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
},
|
|
508
|
+
output,
|
|
509
|
+
project.getAssetManager(),
|
|
510
|
+
expressionContext,
|
|
511
|
+
);
|
|
512
|
+
seq4.build();
|
|
513
|
+
|
|
214
514
|
seq1.overlayWith(seq2);
|
|
215
515
|
seq1.overlayWith(seq3);
|
|
216
516
|
|
package/src/sequence.ts
CHANGED
|
@@ -16,13 +16,14 @@ import {
|
|
|
16
16
|
Stream,
|
|
17
17
|
VisualFilter,
|
|
18
18
|
} from './stream';
|
|
19
|
-
import { Output, SequenceDefinition } from './type';
|
|
19
|
+
import { Output, SequenceDefinition, FragmentDebugInfo } from './type';
|
|
20
20
|
|
|
21
21
|
export class Sequence {
|
|
22
22
|
private time: number = 0; // time is absolute
|
|
23
23
|
|
|
24
24
|
private videoStream!: Stream;
|
|
25
25
|
private audioStream!: Stream;
|
|
26
|
+
private debugInfo: FragmentDebugInfo[] = []; // Collect debug info during build
|
|
26
27
|
|
|
27
28
|
constructor(
|
|
28
29
|
private buf: FilterBuffer,
|
|
@@ -44,6 +45,11 @@ export class Sequence {
|
|
|
44
45
|
this.expressionContext,
|
|
45
46
|
);
|
|
46
47
|
|
|
48
|
+
const calculatedDuration = calculateFinalValue(
|
|
49
|
+
fragment.duration,
|
|
50
|
+
this.expressionContext,
|
|
51
|
+
);
|
|
52
|
+
|
|
47
53
|
if (fragment.id === 'outro_message') {
|
|
48
54
|
debugger;
|
|
49
55
|
}
|
|
@@ -51,7 +57,7 @@ export class Sequence {
|
|
|
51
57
|
const timeContext: TimeData = {
|
|
52
58
|
start: 0,
|
|
53
59
|
end: 0,
|
|
54
|
-
duration:
|
|
60
|
+
duration: calculatedDuration,
|
|
55
61
|
};
|
|
56
62
|
|
|
57
63
|
const asset = this.assetManager.getAssetByName(fragment.assetName);
|
|
@@ -69,7 +75,7 @@ export class Sequence {
|
|
|
69
75
|
} else {
|
|
70
76
|
// Create blank transparent video stream for audio-only assets
|
|
71
77
|
currentVideoStream = makeBlankStream(
|
|
72
|
-
|
|
78
|
+
calculatedDuration,
|
|
73
79
|
this.output.resolution.width,
|
|
74
80
|
this.output.resolution.height,
|
|
75
81
|
this.output.fps,
|
|
@@ -78,40 +84,50 @@ export class Sequence {
|
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
// Create audio stream: use actual audio if available, otherwise create silent stream
|
|
87
|
+
// If fragment has -sound: off, always use silence
|
|
81
88
|
let currentAudioStream: Stream;
|
|
82
|
-
if (
|
|
89
|
+
if (fragment.sound === 'off') {
|
|
90
|
+
// Force silent audio when -sound: off
|
|
91
|
+
currentAudioStream = makeSilentStream(calculatedDuration, this.buf);
|
|
92
|
+
} else if (asset.hasAudio) {
|
|
83
93
|
currentAudioStream = makeStream(
|
|
84
94
|
this.assetManager.getAudioInputLabelByAssetName(fragment.assetName),
|
|
85
95
|
this.buf,
|
|
86
96
|
);
|
|
87
97
|
} else {
|
|
88
98
|
// Create silent audio stream matching the video duration
|
|
89
|
-
currentAudioStream = makeSilentStream(
|
|
99
|
+
currentAudioStream = makeSilentStream(calculatedDuration, this.buf);
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
// duration and clipping adjustment
|
|
93
|
-
if (fragment.trimLeft != 0 ||
|
|
103
|
+
if (fragment.trimLeft != 0 || calculatedDuration < asset.duration) {
|
|
94
104
|
// console.log('fragment.trimLeft=' + fragment.trimLeft);
|
|
95
|
-
// console.log('fragment.duration=' +
|
|
105
|
+
// console.log('fragment.duration=' + calculatedDuration);
|
|
96
106
|
// console.log('asset.duration=' + asset.duration);
|
|
97
107
|
|
|
98
108
|
// Only trim video if it came from an actual source
|
|
99
109
|
if (asset.hasVideo) {
|
|
100
110
|
currentVideoStream.trim(
|
|
101
111
|
fragment.trimLeft,
|
|
102
|
-
fragment.trimLeft +
|
|
112
|
+
fragment.trimLeft + calculatedDuration,
|
|
103
113
|
);
|
|
104
114
|
}
|
|
105
115
|
|
|
106
|
-
// Only trim audio if it came from an actual source
|
|
107
|
-
if (asset.hasAudio) {
|
|
116
|
+
// Only trim audio if it came from an actual source AND sound is not off
|
|
117
|
+
if (asset.hasAudio && fragment.sound !== 'off') {
|
|
108
118
|
currentAudioStream.trim(
|
|
109
119
|
fragment.trimLeft,
|
|
110
|
-
fragment.trimLeft +
|
|
120
|
+
fragment.trimLeft + calculatedDuration,
|
|
111
121
|
);
|
|
112
122
|
}
|
|
113
123
|
}
|
|
114
124
|
|
|
125
|
+
// Convert deprecated JPEG pixel format (yuvj420p) to standard yuv420p early
|
|
126
|
+
// This prevents swscaler warnings from appearing in all subsequent filters
|
|
127
|
+
if (asset.hasVideo && asset.type === 'image') {
|
|
128
|
+
currentVideoStream.convertPixelFormat('yuv420p');
|
|
129
|
+
}
|
|
130
|
+
|
|
115
131
|
// Apply visual filter early for static images (before padding/cloning)
|
|
116
132
|
// This is more efficient as ffmpeg processes the filter once, then clones the filtered frame
|
|
117
133
|
if (
|
|
@@ -124,12 +140,14 @@ export class Sequence {
|
|
|
124
140
|
|
|
125
141
|
if (
|
|
126
142
|
asset.duration === 0 &&
|
|
127
|
-
|
|
128
|
-
asset.type === 'image'
|
|
143
|
+
calculatedDuration > 0 &&
|
|
144
|
+
asset.type === 'image' &&
|
|
145
|
+
fragment.objectFit !== 'ken-burns'
|
|
129
146
|
) {
|
|
130
147
|
// special case for images - extend static image to desired duration
|
|
148
|
+
// Skip tpad for Ken Burns - zoompan will generate the frames
|
|
131
149
|
currentVideoStream.tPad({
|
|
132
|
-
start:
|
|
150
|
+
start: calculatedDuration,
|
|
133
151
|
startMode: 'clone',
|
|
134
152
|
});
|
|
135
153
|
}
|
|
@@ -140,7 +158,25 @@ export class Sequence {
|
|
|
140
158
|
currentVideoStream.fps(this.output.fps);
|
|
141
159
|
|
|
142
160
|
// fitting the video stream into the output frame
|
|
143
|
-
if (fragment.objectFit === '
|
|
161
|
+
if (fragment.objectFit === 'ken-burns') {
|
|
162
|
+
// Ken Burns effect (zoom/pan)
|
|
163
|
+
currentVideoStream.kenBurns({
|
|
164
|
+
effect: fragment.objectFitKenBurns,
|
|
165
|
+
zoom: fragment.objectFitKenBurnsZoom,
|
|
166
|
+
effectDuration: fragment.objectFitKenBurnsEffectDuration,
|
|
167
|
+
fragmentDuration: calculatedDuration,
|
|
168
|
+
easing: fragment.objectFitKenBurnsEasing,
|
|
169
|
+
width: this.output.resolution.width,
|
|
170
|
+
height: this.output.resolution.height,
|
|
171
|
+
fps: this.output.fps,
|
|
172
|
+
focalX: fragment.objectFitKenBurnsFocalX,
|
|
173
|
+
focalY: fragment.objectFitKenBurnsFocalY,
|
|
174
|
+
panStartX: fragment.objectFitKenBurnsPanStartX,
|
|
175
|
+
panStartY: fragment.objectFitKenBurnsPanStartY,
|
|
176
|
+
panEndX: fragment.objectFitKenBurnsPanEndX,
|
|
177
|
+
panEndY: fragment.objectFitKenBurnsPanEndY,
|
|
178
|
+
});
|
|
179
|
+
} else if (fragment.objectFit === 'cover') {
|
|
144
180
|
currentVideoStream.fitOutputCover(this.output.resolution);
|
|
145
181
|
} else {
|
|
146
182
|
const options: ObjectFitContainOptions = {};
|
|
@@ -202,7 +238,7 @@ export class Sequence {
|
|
|
202
238
|
fades: [
|
|
203
239
|
{
|
|
204
240
|
type: 'out',
|
|
205
|
-
startTime:
|
|
241
|
+
startTime: calculatedDuration - fragment.transitionOutDuration,
|
|
206
242
|
duration: fragment.transitionOutDuration,
|
|
207
243
|
},
|
|
208
244
|
],
|
|
@@ -211,7 +247,7 @@ export class Sequence {
|
|
|
211
247
|
fades: [
|
|
212
248
|
{
|
|
213
249
|
type: 'out',
|
|
214
|
-
startTime:
|
|
250
|
+
startTime: calculatedDuration - fragment.transitionOutDuration,
|
|
215
251
|
duration: fragment.transitionOutDuration,
|
|
216
252
|
},
|
|
217
253
|
],
|
|
@@ -239,7 +275,7 @@ export class Sequence {
|
|
|
239
275
|
|
|
240
276
|
// console.log('this.time=' + this.time);
|
|
241
277
|
// console.log('streamDuration=' + this.time);
|
|
242
|
-
// console.log('otherStreamDuration=' +
|
|
278
|
+
// console.log('otherStreamDuration=' + calculatedDuration);
|
|
243
279
|
// console.log('otherStreamOffsetLeft=' + otherStreamOffsetLeft);
|
|
244
280
|
|
|
245
281
|
// use overlay
|
|
@@ -247,14 +283,14 @@ export class Sequence {
|
|
|
247
283
|
flipLayers: fragment.overlayZIndex < 0,
|
|
248
284
|
offset: {
|
|
249
285
|
streamDuration: this.time,
|
|
250
|
-
otherStreamDuration:
|
|
286
|
+
otherStreamDuration: calculatedDuration,
|
|
251
287
|
otherStreamOffsetLeft: otherStreamOffsetLeft,
|
|
252
288
|
},
|
|
253
289
|
});
|
|
254
290
|
this.audioStream.overlayStream(currentAudioStream, {
|
|
255
291
|
offset: {
|
|
256
292
|
streamDuration: this.time,
|
|
257
|
-
otherStreamDuration:
|
|
293
|
+
otherStreamDuration: calculatedDuration,
|
|
258
294
|
otherStreamOffsetLeft: otherStreamOffsetLeft,
|
|
259
295
|
},
|
|
260
296
|
});
|
|
@@ -291,13 +327,25 @@ export class Sequence {
|
|
|
291
327
|
}
|
|
292
328
|
|
|
293
329
|
timeContext.start = this.time + calculatedOverlayLeft;
|
|
294
|
-
timeContext.end = this.time +
|
|
295
|
-
this.time +=
|
|
330
|
+
timeContext.end = this.time + calculatedDuration + calculatedOverlayLeft;
|
|
331
|
+
this.time += calculatedDuration + calculatedOverlayLeft;
|
|
296
332
|
|
|
297
333
|
this.expressionContext.fragments.set(fragment.id, {
|
|
298
334
|
time: timeContext,
|
|
299
335
|
});
|
|
300
336
|
|
|
337
|
+
// Collect debug info
|
|
338
|
+
this.debugInfo.push({
|
|
339
|
+
id: fragment.id,
|
|
340
|
+
assetName: fragment.assetName,
|
|
341
|
+
startTime: timeContext.start,
|
|
342
|
+
endTime: timeContext.end,
|
|
343
|
+
duration: calculatedDuration,
|
|
344
|
+
trimLeft: fragment.trimLeft,
|
|
345
|
+
overlayLeft: calculatedOverlayLeft,
|
|
346
|
+
enabled: fragment.enabled,
|
|
347
|
+
});
|
|
348
|
+
|
|
301
349
|
// console.log('new time=' + this.time);
|
|
302
350
|
|
|
303
351
|
firstOne = false;
|
|
@@ -327,4 +375,12 @@ export class Sequence {
|
|
|
327
375
|
public getAudioStream(): Stream {
|
|
328
376
|
return this.audioStream;
|
|
329
377
|
}
|
|
378
|
+
|
|
379
|
+
public getDebugInfo(): FragmentDebugInfo[] {
|
|
380
|
+
return this.debugInfo;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
public getTotalDuration(): number {
|
|
384
|
+
return this.time;
|
|
385
|
+
}
|
|
330
386
|
}
|
package/src/stream.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
Millisecond,
|
|
5
5
|
makeNull,
|
|
6
6
|
makeFps,
|
|
7
|
+
makeFormat,
|
|
7
8
|
makeTranspose,
|
|
8
9
|
makeTrim,
|
|
9
10
|
makeTPad,
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
makeOverlay,
|
|
18
19
|
makeEq,
|
|
19
20
|
makeChromakey,
|
|
21
|
+
makeKenBurns,
|
|
20
22
|
makeConcat,
|
|
21
23
|
makeFade,
|
|
22
24
|
makeAmix,
|
|
@@ -311,6 +313,45 @@ export class Stream {
|
|
|
311
313
|
return this;
|
|
312
314
|
}
|
|
313
315
|
|
|
316
|
+
public kenBurns(parameters: {
|
|
317
|
+
effect: 'zoom-in' | 'zoom-out' | 'pan-left' | 'pan-right' | 'pan-top' | 'pan-bottom';
|
|
318
|
+
zoom: number;
|
|
319
|
+
effectDuration: number;
|
|
320
|
+
fragmentDuration: number;
|
|
321
|
+
easing: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
|
322
|
+
width: number;
|
|
323
|
+
height: number;
|
|
324
|
+
fps: number;
|
|
325
|
+
focalX?: number;
|
|
326
|
+
focalY?: number;
|
|
327
|
+
panStartX?: number;
|
|
328
|
+
panStartY?: number;
|
|
329
|
+
panEndX?: number;
|
|
330
|
+
panEndY?: number;
|
|
331
|
+
}): Stream {
|
|
332
|
+
// Apply Ken Burns effect
|
|
333
|
+
const kenBurnsRes = makeKenBurns([this.looseEnd], {
|
|
334
|
+
effect: parameters.effect,
|
|
335
|
+
zoom: parameters.zoom,
|
|
336
|
+
effectDuration: parameters.effectDuration,
|
|
337
|
+
fragmentDuration: parameters.fragmentDuration,
|
|
338
|
+
easing: parameters.easing,
|
|
339
|
+
width: parameters.width,
|
|
340
|
+
height: parameters.height,
|
|
341
|
+
fps: parameters.fps,
|
|
342
|
+
focalX: parameters.focalX,
|
|
343
|
+
focalY: parameters.focalY,
|
|
344
|
+
panStartX: parameters.panStartX,
|
|
345
|
+
panStartY: parameters.panStartY,
|
|
346
|
+
panEndX: parameters.panEndX,
|
|
347
|
+
panEndY: parameters.panEndY,
|
|
348
|
+
});
|
|
349
|
+
this.looseEnd = kenBurnsRes.outputs[0];
|
|
350
|
+
this.buf.append(kenBurnsRes);
|
|
351
|
+
|
|
352
|
+
return this;
|
|
353
|
+
}
|
|
354
|
+
|
|
314
355
|
public fps(value: number): Stream {
|
|
315
356
|
const res = makeFps([this.looseEnd], value);
|
|
316
357
|
this.looseEnd = res.outputs[0];
|
|
@@ -320,6 +361,15 @@ export class Stream {
|
|
|
320
361
|
return this;
|
|
321
362
|
}
|
|
322
363
|
|
|
364
|
+
public convertPixelFormat(format: string): Stream {
|
|
365
|
+
const res = makeFormat([this.looseEnd], format);
|
|
366
|
+
this.looseEnd = res.outputs[0];
|
|
367
|
+
|
|
368
|
+
this.buf.append(res);
|
|
369
|
+
|
|
370
|
+
return this;
|
|
371
|
+
}
|
|
372
|
+
|
|
323
373
|
public blur(strength: number): Stream {
|
|
324
374
|
const res = makeGblur([this.looseEnd], {
|
|
325
375
|
sigma: strength,
|