simple-ffmpegjs 0.3.0 → 0.3.1
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 +2 -2
- package/package.json +1 -1
- package/src/ffmpeg/command_builder.js +18 -2
- package/src/ffmpeg/text_renderer.js +16 -5
package/README.md
CHANGED
|
@@ -48,8 +48,8 @@ The library handles FFmpeg's complexity internally while exposing a clean interf
|
|
|
48
48
|
## Example Output
|
|
49
49
|
|
|
50
50
|
<p align="center">
|
|
51
|
-
<a href="https://7llpl63xkl8jovgt.public.blob.vercel-storage.com/wonders-showcase.mp4">
|
|
52
|
-
<img src="https://7llpl63xkl8jovgt.public.blob.vercel-storage.com/wonders-thumbnail.jpg" alt="Example video - click to watch" width="640">
|
|
51
|
+
<a href="https://7llpl63xkl8jovgt.public.blob.vercel-storage.com/wonders-showcase-1.mp4">
|
|
52
|
+
<img src="https://7llpl63xkl8jovgt.public.blob.vercel-storage.com/simple-ffmpeg/wonders-thumbnail-1.jpg" alt="Example video - click to watch" width="640">
|
|
53
53
|
</a>
|
|
54
54
|
</p>
|
|
55
55
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simple-ffmpegjs",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Lightweight Node.js library for programmatic video composition using FFmpeg. Concatenate clips, add transitions, mix audio, overlay text, and more.",
|
|
5
5
|
"author": "Brayden Blackwell <braydenblackwell21@gmail.com> (https://github.com/Fats403)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -75,6 +75,11 @@ function buildMainCommand({
|
|
|
75
75
|
if (hasVideo && !audioOnly) {
|
|
76
76
|
cmd += `-c:v ${videoCodec} `;
|
|
77
77
|
|
|
78
|
+
// Cross-browser compatibility flags for libx264 (Firefox, Safari, older devices)
|
|
79
|
+
if (videoCodec === "libx264") {
|
|
80
|
+
cmd += `-profile:v main -pix_fmt yuv420p `;
|
|
81
|
+
}
|
|
82
|
+
|
|
78
83
|
// Preset (for software encoders)
|
|
79
84
|
if (
|
|
80
85
|
videoPreset &&
|
|
@@ -174,14 +179,25 @@ function buildTextBatchCommand({
|
|
|
174
179
|
intermediateCrf,
|
|
175
180
|
outputPath,
|
|
176
181
|
}) {
|
|
177
|
-
|
|
182
|
+
// Add compatibility flags for libx264
|
|
183
|
+
const compatFlags =
|
|
184
|
+
intermediateVideoCodec === "libx264"
|
|
185
|
+
? "-profile:v main -pix_fmt yuv420p "
|
|
186
|
+
: "";
|
|
187
|
+
return `ffmpeg -y -i "${escapeFilePath(
|
|
188
|
+
inputPath
|
|
189
|
+
)}" -filter_complex "[0:v]null[invid];${filterString}" -map "[outVideoAndText]" -map 0:a? -c:v ${intermediateVideoCodec} ${compatFlags}-preset ${intermediatePreset} -crf ${intermediateCrf} -c:a copy -movflags +faststart "${escapeFilePath(
|
|
190
|
+
outputPath
|
|
191
|
+
)}"`;
|
|
178
192
|
}
|
|
179
193
|
|
|
180
194
|
/**
|
|
181
195
|
* Build command to generate a thumbnail
|
|
182
196
|
*/
|
|
183
197
|
function buildThumbnailCommand({ inputPath, outputPath, time, width, height }) {
|
|
184
|
-
let cmd = `ffmpeg -y -ss ${time} -i "${escapeFilePath(
|
|
198
|
+
let cmd = `ffmpeg -y -ss ${time} -i "${escapeFilePath(
|
|
199
|
+
inputPath
|
|
200
|
+
)}" -vframes 1 `;
|
|
185
201
|
|
|
186
202
|
if (width || height) {
|
|
187
203
|
const w = width || -1;
|
|
@@ -88,11 +88,22 @@ function buildFontsizeParam(baseClip, start, end) {
|
|
|
88
88
|
if (type === "pop-bounce") {
|
|
89
89
|
const entry =
|
|
90
90
|
typeof anim.in === "number" ? anim.in : C.DEFAULT_TEXT_ANIM_IN;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
// Two-phase bounce: grow with overshoot, then settle smoothly
|
|
92
|
+
const growEnd = start + entry * 0.6;
|
|
93
|
+
const minSize = (baseSize * 0.7).toFixed(3);
|
|
94
|
+
const overshoot = (baseSize * 1.1).toFixed(3);
|
|
95
|
+
const growAmount = (baseSize * 0.4).toFixed(3);
|
|
96
|
+
const settleAmount = (baseSize * 0.1).toFixed(3);
|
|
97
|
+
const phase1Duration = (entry * 0.6).toFixed(4);
|
|
98
|
+
const phase2Duration = (entry * 0.4).toFixed(4);
|
|
99
|
+
// Phase 1: 0.7 -> 1.1 (ease-out), Phase 2: 1.1 -> 1.0 (ease-in-out)
|
|
100
|
+
return `:fontsize=if(lt(t\\,${growEnd.toFixed(
|
|
101
|
+
4
|
|
102
|
+
)})\\,${minSize}+${growAmount}*sin(PI/2*(t-${start})/${phase1Duration})\\,if(lt(t\\,${
|
|
103
|
+
start + entry
|
|
104
|
+
})\\,${overshoot}-${settleAmount}*sin(PI/2*(t-${growEnd.toFixed(
|
|
105
|
+
4
|
|
106
|
+
)})/${phase2Duration})\\,${baseSize}))`;
|
|
96
107
|
}
|
|
97
108
|
|
|
98
109
|
if (type === "scale-in") {
|