@omelhorsite/video-sdk 0.2.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/README.md +103 -0
- package/dist/index.js +1197 -0
- package/dist/types/captions.d.ts +79 -0
- package/dist/types/cloud/cloud.d.ts +257 -0
- package/dist/types/cloud/index.d.ts +4 -0
- package/dist/types/cloud/srt.d.ts +29 -0
- package/dist/types/cloud/store.d.ts +41 -0
- package/dist/types/compile.d.ts +63 -0
- package/dist/types/fx.d.ts +124 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/packfile.d.ts +44 -0
- package/dist/types/placement.d.ts +30 -0
- package/dist/types/slice.d.ts +20 -0
- package/dist/types/types.d.ts +200 -0
- package/package.json +46 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Matematica partilhada entre o preview (canvas) e o compilador (ffmpeg).
|
|
3
|
+
* A paridade preview/export nasce aqui: os dois lados chamam ESTAS funcoes,
|
|
4
|
+
* por isso nao ha duas interpretacoes da mesma timeline.
|
|
5
|
+
*/
|
|
6
|
+
import type { ClipTransform, Project } from "./types";
|
|
7
|
+
export interface Placement {
|
|
8
|
+
/** Canto superior esquerdo e dimensoes, em pixels do projecto. */
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* "Fit" base: o asset ajustado por inteiro dentro da tela (contain), depois
|
|
16
|
+
* multiplicado pela escala do clip e centrado em (x, y).
|
|
17
|
+
*/
|
|
18
|
+
export declare const computePlacement: (assetWidth: number, assetHeight: number, project: Pick<Project, "width" | "height">, transform: ClipTransform) => Placement;
|
|
19
|
+
/**
|
|
20
|
+
* Factor de fade (0..1) num instante da timeline. Fades lineares, medidos a
|
|
21
|
+
* partir das pontas do clip. PRODUTO dos dois envelopes (nao minimo): e assim
|
|
22
|
+
* que o ffmpeg compoe `fade in` + `fade out` encadeados, e o preview tem de
|
|
23
|
+
* bater com o export quando os fades se sobrepoem (docs/PLAYBACK.md 3.2).
|
|
24
|
+
*/
|
|
25
|
+
export declare const fadeFactor: (t: number, clip: {
|
|
26
|
+
start: number;
|
|
27
|
+
duration: number;
|
|
28
|
+
fadeIn: number;
|
|
29
|
+
fadeOut: number;
|
|
30
|
+
}) => number;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recorta um Project a uma janela de tempo.
|
|
3
|
+
*
|
|
4
|
+
* Serve para iterar: mudou-se um corte aos 30s, quer-se ver os 30s aos 40s, e
|
|
5
|
+
* nao ha razao nenhuma para recodificar os outros 75 segundos. Como isto e' uma
|
|
6
|
+
* transformacao pura sobre o Project, tudo o resto - o compilador, as legendas,
|
|
7
|
+
* os efeitos - continua a funcionar sem saber que esta a ver so' um pedaco.
|
|
8
|
+
*
|
|
9
|
+
* O que sai e' um projecto normal, a comecar em zero. As legendas nao precisam
|
|
10
|
+
* de ser tocadas: vivem em tempo do SOURCE e quem as le deriva-as dos clips,
|
|
11
|
+
* que aqui ja vao aparados.
|
|
12
|
+
*/
|
|
13
|
+
import type { Clip, Project } from "./types";
|
|
14
|
+
/** Apara um clip a` janela; `undefined` se ficar todo de fora. */
|
|
15
|
+
export declare const sliceClip: (clip: Clip, from: number, to: number) => Clip | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Projecto equivalente a` janela `[from, to]`, com tudo deslocado para comecar
|
|
18
|
+
* em zero.
|
|
19
|
+
*/
|
|
20
|
+
export declare const sliceProject: (project: Project, from: number, to: number) => Project;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modelo da timeline do OMS Video. Este JSON e o contrato entre TODAS as
|
|
3
|
+
* pontas: o preview (canvas), o export local (ffmpeg) e o render no
|
|
4
|
+
* servidor. Qualquer efeito novo so entra quando existir nas tres.
|
|
5
|
+
*/
|
|
6
|
+
import type { CaptionSource, CaptionStyle } from "./captions";
|
|
7
|
+
export type AssetKind = "video" | "image" | "audio";
|
|
8
|
+
export interface Asset {
|
|
9
|
+
id: string;
|
|
10
|
+
kind: AssetKind;
|
|
11
|
+
name: string;
|
|
12
|
+
/** Caminho absoluto no disco do host. */
|
|
13
|
+
path: string;
|
|
14
|
+
/** Segundos; obrigatorio para video/audio. */
|
|
15
|
+
duration?: number;
|
|
16
|
+
width?: number;
|
|
17
|
+
height?: number;
|
|
18
|
+
/** Se o ficheiro tem stream de audio (probe); orienta o link video+audio. */
|
|
19
|
+
hasAudio?: boolean;
|
|
20
|
+
/** So apresentacao (UI): thumbnail (dataURL/URL); ignorado pelo compilador. */
|
|
21
|
+
thumb?: string;
|
|
22
|
+
/** So apresentacao (UI): imagem da waveform; ignorado pelo compilador. */
|
|
23
|
+
wave?: string;
|
|
24
|
+
/**
|
|
25
|
+
* SO PREVIEW (docs/PLAYBACK.md 3.4). O compilador de export usa SEMPRE
|
|
26
|
+
* `path` e as `width`/`height` do ORIGINAL pos-rotacao - nunca as do proxy.
|
|
27
|
+
*/
|
|
28
|
+
proxyPath?: string;
|
|
29
|
+
/** So preview: PCM s16le intercalado, fonte do motor de audio. */
|
|
30
|
+
pcmPath?: string;
|
|
31
|
+
pcmFrames?: number;
|
|
32
|
+
pcmChannels?: number;
|
|
33
|
+
pcmSampleRate?: number;
|
|
34
|
+
/** So preview: filmstrip (tile horizontal) para os clips da timeline. */
|
|
35
|
+
stripPath?: string;
|
|
36
|
+
/** Versao do probe que preencheu width/height (rotacao aplicada a partir da 2). */
|
|
37
|
+
probeVersion?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ClipTransform {
|
|
40
|
+
/** Centro do clip em fraccoes da tela (0..1); 0.5/0.5 = centrado. */
|
|
41
|
+
x: number;
|
|
42
|
+
y: number;
|
|
43
|
+
/** Multiplicador sobre o "fit" base (1 = ajustado dentro da tela). */
|
|
44
|
+
scale: number;
|
|
45
|
+
/** 0..1 */
|
|
46
|
+
opacity: number;
|
|
47
|
+
}
|
|
48
|
+
interface BaseClip {
|
|
49
|
+
id: string;
|
|
50
|
+
/** Posicao na timeline, em segundos. */
|
|
51
|
+
start: number;
|
|
52
|
+
/** Duracao na timeline, em segundos. */
|
|
53
|
+
duration: number;
|
|
54
|
+
/** Segundos de fade a entrada/saida (0 = sem fade). */
|
|
55
|
+
fadeIn: number;
|
|
56
|
+
fadeOut: number;
|
|
57
|
+
/**
|
|
58
|
+
* Clips com o mesmo linkId estao associados (ex.: video + o seu audio
|
|
59
|
+
* separado): mover/aparar/dividir/apagar seguem juntos no editor ate se
|
|
60
|
+
* desassociar. Ignorado pelo compilador.
|
|
61
|
+
*/
|
|
62
|
+
linkId?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface VisualClip extends BaseClip {
|
|
65
|
+
kind: "video" | "image";
|
|
66
|
+
assetId: string;
|
|
67
|
+
/** Offset dentro do ficheiro de origem (so video). */
|
|
68
|
+
in: number;
|
|
69
|
+
transform: ClipTransform;
|
|
70
|
+
/** So video: descarta o audio proprio do clip. */
|
|
71
|
+
muted: boolean;
|
|
72
|
+
/** So video: ganho do audio proprio (0..2). */
|
|
73
|
+
volume: number;
|
|
74
|
+
/**
|
|
75
|
+
* Desfoca TUDO o que ja esta composto por baixo enquanto este clip esta no
|
|
76
|
+
* ar - o truque de "fundo desfocado, primeiro plano em grande". Sigma em
|
|
77
|
+
* fraccao da LARGURA do projecto (0.02 = 2%), para escalar sozinho quando o
|
|
78
|
+
* preview corre em baixa resolucao. 0/ausente = desligado.
|
|
79
|
+
*/
|
|
80
|
+
blurBehind?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Sombra por baixo do clip, para o descolar do fundo quando ele esta em
|
|
83
|
+
* primeiro plano. Raio em fraccao da LARGURA do projecto (0.015 = 1.5%),
|
|
84
|
+
* pela mesma razao que o `blurBehind`. 0/ausente = desligado.
|
|
85
|
+
*/
|
|
86
|
+
shadow?: number;
|
|
87
|
+
}
|
|
88
|
+
export interface AudioClip extends BaseClip {
|
|
89
|
+
kind: "audio";
|
|
90
|
+
assetId: string;
|
|
91
|
+
in: number;
|
|
92
|
+
/** 0..2 */
|
|
93
|
+
volume: number;
|
|
94
|
+
}
|
|
95
|
+
export interface TextClip extends BaseClip {
|
|
96
|
+
kind: "text";
|
|
97
|
+
text: string;
|
|
98
|
+
/** Tamanho da fonte como fraccao da ALTURA do projecto. */
|
|
99
|
+
size: number;
|
|
100
|
+
/** #rrggbb */
|
|
101
|
+
color: string;
|
|
102
|
+
/** Centro, em fraccoes da tela. */
|
|
103
|
+
x: number;
|
|
104
|
+
y: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Efeito de ecra inteiro colocado na timeline. Vive numa track de video (para
|
|
108
|
+
* a UI o poder mostrar e arrastar) mas e SEMPRE composto no fim, por cima de
|
|
109
|
+
* tudo - video, imagens e texto - porque uma transicao apanha o frame todo.
|
|
110
|
+
* Matematica e valores por omissao em fx.ts.
|
|
111
|
+
*/
|
|
112
|
+
export interface FxClip extends BaseClip {
|
|
113
|
+
kind: "fx";
|
|
114
|
+
fx: "flash";
|
|
115
|
+
/** Opacidade maxima do veu de cor, 0..1. */
|
|
116
|
+
intensity: number;
|
|
117
|
+
/** Zoom extra no pico (0.07 = +7%). */
|
|
118
|
+
punch: number;
|
|
119
|
+
/** Amplitude da ondulacao, em fraccao da largura (0.022 = 2.2%). */
|
|
120
|
+
wave: number;
|
|
121
|
+
/** Ciclos da ondulacao de cima a baixo do ecra. */
|
|
122
|
+
freq: number;
|
|
123
|
+
/** Cor do nucleo do brilho, #rrggbb (branco no flash classico). */
|
|
124
|
+
color: string;
|
|
125
|
+
/** Cor da orla do brilho, #rrggbb (o ambar que da o ar de luz quente). */
|
|
126
|
+
warm: string;
|
|
127
|
+
/** Onde nasce o brilho, em fraccoes do ecra. */
|
|
128
|
+
focusX: number;
|
|
129
|
+
focusY: number;
|
|
130
|
+
/**
|
|
131
|
+
* Asset de audio disparado no CORTE (o "clique" do obturador). Toca sempre
|
|
132
|
+
* a velocidade natural: esticar a transicao NAO estica o som.
|
|
133
|
+
*/
|
|
134
|
+
soundAssetId?: string;
|
|
135
|
+
/** Ganho desse som, 0..2. */
|
|
136
|
+
soundVolume?: number;
|
|
137
|
+
}
|
|
138
|
+
export type Clip = VisualClip | AudioClip | TextClip | FxClip;
|
|
139
|
+
export type TrackKind = "video" | "audio" | "text";
|
|
140
|
+
export interface Track {
|
|
141
|
+
id: string;
|
|
142
|
+
kind: TrackKind;
|
|
143
|
+
name: string;
|
|
144
|
+
clips: Clip[];
|
|
145
|
+
muted?: boolean;
|
|
146
|
+
}
|
|
147
|
+
export interface Project {
|
|
148
|
+
id: string;
|
|
149
|
+
name: string;
|
|
150
|
+
width: number;
|
|
151
|
+
height: number;
|
|
152
|
+
fps: number;
|
|
153
|
+
/** Cor de fundo, #rrggbb. */
|
|
154
|
+
background: string;
|
|
155
|
+
/**
|
|
156
|
+
* Ordem de composicao visual: tracks "video" por ordem do array (indice 0 e
|
|
157
|
+
* o fundo), as tracks "text" por cima de todas, e os clips "fx" por cima do
|
|
158
|
+
* texto tambem (um flash apanha o frame inteiro). "audio" nao compoe imagem.
|
|
159
|
+
*/
|
|
160
|
+
tracks: Track[];
|
|
161
|
+
assets: Asset[];
|
|
162
|
+
/**
|
|
163
|
+
* Transcricoes, uma por asset, em tempo do SOURCE. Ficam aqui em vez de
|
|
164
|
+
* viverem num mp4 ja legendado: assim cortar ou reordenar nao as invalida
|
|
165
|
+
* (ver captions.ts) e o texto continua editavel depois de transcrito.
|
|
166
|
+
*/
|
|
167
|
+
captions?: CaptionSource[];
|
|
168
|
+
/** Estilo das legendas; omissao = DEFAULT_CAPTION_STYLE. */
|
|
169
|
+
captionStyle?: Partial<CaptionStyle>;
|
|
170
|
+
}
|
|
171
|
+
export declare const RESOLUTION_PRESETS: readonly [{
|
|
172
|
+
readonly id: "1080x1920";
|
|
173
|
+
readonly label: "9:16 (1080x1920)";
|
|
174
|
+
readonly width: 1080;
|
|
175
|
+
readonly height: 1920;
|
|
176
|
+
}, {
|
|
177
|
+
readonly id: "1920x1080";
|
|
178
|
+
readonly label: "16:9 (1920x1080)";
|
|
179
|
+
readonly width: 1920;
|
|
180
|
+
readonly height: 1080;
|
|
181
|
+
}, {
|
|
182
|
+
readonly id: "1080x1080";
|
|
183
|
+
readonly label: "1:1 (1080x1080)";
|
|
184
|
+
readonly width: 1080;
|
|
185
|
+
readonly height: 1080;
|
|
186
|
+
}, {
|
|
187
|
+
readonly id: "720x1280";
|
|
188
|
+
readonly label: "9:16 (720x1280)";
|
|
189
|
+
readonly width: 720;
|
|
190
|
+
readonly height: 1280;
|
|
191
|
+
}, {
|
|
192
|
+
readonly id: "1280x720";
|
|
193
|
+
readonly label: "16:9 (1280x720)";
|
|
194
|
+
readonly width: 1280;
|
|
195
|
+
readonly height: 720;
|
|
196
|
+
}];
|
|
197
|
+
export declare const projectDuration: (project: Project) => number;
|
|
198
|
+
export declare const findAsset: (project: Project, id: string) => Asset | undefined;
|
|
199
|
+
export declare const emptyProject: (width?: number, height?: number, fps?: number) => Project;
|
|
200
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@omelhorsite/video-sdk",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The engine of the omelhorsite video editor: the .omsv project model, placement math, effects, karaoke captions, compilation to ffmpeg arguments, and the omelhorsite cloud client. Isolate-safe: no node builtins, no environment access, no stdout.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"types": "./dist/types/index.d.ts",
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"typecheck": "tsc --noEmit -p . && tsc --noEmit -p tsconfig.test.json",
|
|
21
|
+
"check:isolate": "bun run scripts/check-isolate.ts",
|
|
22
|
+
"test": "bun run check:isolate && bun test",
|
|
23
|
+
"build": "rm -rf dist && bun build src/index.ts --target node --format esm --outdir dist --external fflate --external @omelhorsite/sdk && tsc -p tsconfig.build.json",
|
|
24
|
+
"prepublishOnly": "bun run build"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/bun": "^1.4.0",
|
|
28
|
+
"typescript": "^5.9.3"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@omelhorsite/sdk": "^0.5.1",
|
|
32
|
+
"fflate": "^0.8.3"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/afonsopc/omelhorsite-video-sdk.git"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"video",
|
|
40
|
+
"ffmpeg",
|
|
41
|
+
"omsv",
|
|
42
|
+
"editor",
|
|
43
|
+
"captions",
|
|
44
|
+
"omelhorsite"
|
|
45
|
+
]
|
|
46
|
+
}
|