dev-toolkit-cli 1.0.8 → 1.0.10
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/bin/actions/action-compress.js +7 -37
- package/bin/actions/action-compress.js.map +1 -1
- package/bin/lib/bash.js +12 -70
- package/bin/lib/bash.js.map +1 -1
- package/bin/main.js +0 -0
- package/package.json +1 -1
- package/src/actions/action-compress.ts +12 -61
- package/src/lib/bash.ts +12 -83
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import { CommanderError } from "commander";
|
|
2
1
|
import fs from "fs/promises";
|
|
3
2
|
import mime from "mime";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { check_dependencies, ffmpeg_image_to_webp, ffmpeg_video_compress, } from "../lib/bash.js";
|
|
3
|
+
import { getFolderFiles, replaceFilenameExtension, } from "../lib/utils/index.js";
|
|
4
|
+
import { check_dependencies, ffmpeg_image_to_webp, ffmpeg_video_compress_webm, } from "../lib/bash.js";
|
|
7
5
|
export const FileType = ["image", "video"];
|
|
8
6
|
const unsupportedFormats = {
|
|
9
7
|
image: ["image/webp", "image/gif", "image/svg+xml"],
|
|
10
|
-
video: [],
|
|
8
|
+
video: ["video/webm"],
|
|
11
9
|
};
|
|
12
|
-
const compressedFlagPrefix = "compressed_";
|
|
13
|
-
const compressTempPrefix = "temp.";
|
|
14
10
|
export async function file(pathname, { verbose, type, resolution, force, horizontal }) {
|
|
15
11
|
await check_dependencies(["ffmpeg"]);
|
|
16
12
|
if (force)
|
|
@@ -25,9 +21,7 @@ export async function file(pathname, { verbose, type, resolution, force, horizon
|
|
|
25
21
|
continue;
|
|
26
22
|
const fileType = mimetype.split("/")[0];
|
|
27
23
|
if (!(type ? [type] : FileType).includes(fileType) ||
|
|
28
|
-
(unsupportedFormats[fileType] || []).includes(mimetype)
|
|
29
|
-
(!force &&
|
|
30
|
-
[compressedFlagPrefix, compressTempPrefix].some((pf) => getFilename(filePath).startsWith(pf))))
|
|
24
|
+
(unsupportedFormats[fileType] || []).includes(mimetype))
|
|
31
25
|
continue;
|
|
32
26
|
const title = filePath
|
|
33
27
|
.substring(pathname.length)
|
|
@@ -44,44 +38,20 @@ export async function file(pathname, { verbose, type, resolution, force, horizon
|
|
|
44
38
|
await compressVideo(filePath, resolution, horizontal);
|
|
45
39
|
}
|
|
46
40
|
catch (err) {
|
|
47
|
-
if (verbose)
|
|
41
|
+
if (verbose > 10)
|
|
48
42
|
console.error(" Error compressing", err);
|
|
49
43
|
else
|
|
50
44
|
console.error(" Error compressing", `"${filePath}"`);
|
|
51
|
-
// console.error("Error compressing", `"${filePath}"`, err.message);
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
47
|
console.log("\nCompression successfully finished 🚀");
|
|
55
48
|
}
|
|
56
49
|
async function compressImage(filePath) {
|
|
57
|
-
// await sharp(filePath)
|
|
58
|
-
// .webp()
|
|
59
|
-
// .toFile(replaceFilenameExtension(filePath, "webp"));
|
|
60
50
|
await ffmpeg_image_to_webp(filePath, replaceFilenameExtension(filePath, "webp"));
|
|
61
51
|
await fs.rm(filePath);
|
|
62
52
|
}
|
|
63
53
|
async function compressVideo(filePath, resolution, force) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const normalizedFilename = normalizeFilename(filename);
|
|
67
|
-
if (filename !== normalizedFilename) {
|
|
68
|
-
const oldPathname = path.join(directory, filename);
|
|
69
|
-
const newPathname = await getAvailablePathname(path.join(directory, normalizedFilename));
|
|
70
|
-
if (!newPathname) {
|
|
71
|
-
throw new CommanderError(1, "P003", "Could not find a new file destination");
|
|
72
|
-
}
|
|
73
|
-
const newFilename = getFilename(newPathname);
|
|
74
|
-
console.log(" File renamed. From:", `'${filename.trim()}'`, "to:", `'${newFilename.trim()}'`);
|
|
75
|
-
await fs.rename(oldPathname, newPathname);
|
|
76
|
-
filename = newFilename;
|
|
77
|
-
}
|
|
78
|
-
const input = path.join(directory, filename);
|
|
79
|
-
const output = addFilenamePrefix(input, compressTempPrefix);
|
|
80
|
-
await ffmpeg_video_compress(input, output, resolution, force).catch(async (err) => {
|
|
81
|
-
await fs.rm(output);
|
|
82
|
-
throw err;
|
|
83
|
-
});
|
|
84
|
-
await fs.rm(input);
|
|
85
|
-
await fs.rename(output, addFilenamePrefix(removeFilenamePrefix(input, compressedFlagPrefix), compressedFlagPrefix));
|
|
54
|
+
await ffmpeg_video_compress_webm(filePath, replaceFilenameExtension(filePath, "webm"), resolution, force);
|
|
55
|
+
await fs.rm(filePath);
|
|
86
56
|
}
|
|
87
57
|
//# sourceMappingURL=action-compress.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-compress.js","sourceRoot":"","sources":["../../src/actions/action-compress.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"action-compress.js","sourceRoot":"","sources":["../../src/actions/action-compress.ts"],"names":[],"mappings":"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"}
|
package/bin/lib/bash.js
CHANGED
|
@@ -72,8 +72,7 @@ async function detectGPU() {
|
|
|
72
72
|
}
|
|
73
73
|
return cachedGpuType;
|
|
74
74
|
}
|
|
75
|
-
export async function
|
|
76
|
-
// Exemplo de mapeamento (ajuste para bater com o seu código original)
|
|
75
|
+
export async function ffmpeg_video_compress_webm(input, output, resolution = "480p", forceResolution) {
|
|
77
76
|
const resolutionMapping = {
|
|
78
77
|
"4320p": { w: 7680, h: 4320 }, // 8K
|
|
79
78
|
"2160p": { w: 3840, h: 2160 }, // 4K
|
|
@@ -85,91 +84,34 @@ export async function ffmpeg_video_compress(input, output, resolution = "480p",
|
|
|
85
84
|
"240p": { w: 426, h: 240 }, // WQVGA
|
|
86
85
|
};
|
|
87
86
|
const { w, h } = resolutionMapping[resolution];
|
|
88
|
-
// 1. Detecta a GPU automaticamente
|
|
89
87
|
const gpu = await detectGPU();
|
|
90
|
-
// 2. Verifica se é Linux para usar a estratégia correta
|
|
91
88
|
const isLinux = os.platform() === "linux";
|
|
92
|
-
//
|
|
89
|
+
// Utilizamos o codec VP9, que é o padrão moderno de alta qualidade para vídeos WebM
|
|
93
90
|
const encoders = {
|
|
94
|
-
nvidia: "-c:v
|
|
95
|
-
amd: isLinux ? "-c:v
|
|
96
|
-
intel: isLinux ? "-c:v
|
|
97
|
-
mac: "-c:v
|
|
98
|
-
cpu: "-c:v
|
|
91
|
+
nvidia: "-c:v vp9_nvenc -preset p4",
|
|
92
|
+
amd: isLinux ? "-c:v vp9_vaapi" : "-c:v vp9_amf",
|
|
93
|
+
intel: isLinux ? "-c:v vp9_vaapi" : "-c:v vp9_qsv",
|
|
94
|
+
mac: "-c:v libvpx-vp9 -row-mt 1 -cpu-used 4",
|
|
95
|
+
cpu: "-c:v libvpx-vp9 -row-mt 1 -cpu-used 4",
|
|
99
96
|
};
|
|
100
97
|
const vcodec = encoders[gpu] || encoders.cpu;
|
|
101
|
-
|
|
102
|
-
let hwaccel = gpu === "cpu" ? "" : "-hwaccel auto";
|
|
98
|
+
let hwaccel = gpu === "cpu" || gpu === "mac" ? "" : "-hwaccel auto";
|
|
103
99
|
let videoFilter = "";
|
|
104
|
-
// Lógica específica para o VA-API (AMD/Intel no Linux)
|
|
105
100
|
if (isLinux && (gpu === "amd" || gpu === "intel")) {
|
|
106
|
-
// Aponta diretamente para a placa de vídeo no Linux
|
|
107
101
|
hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
108
|
-
// O VA-API precisa que o formato seja nv12 e faça o upload para a GPU
|
|
109
102
|
videoFilter = forceResolution
|
|
110
103
|
? `-vf "scale=${w}:${h},format=nv12,hwupload"`
|
|
111
104
|
: `-vf "scale=-1:${h},format=nv12,hwupload"`;
|
|
112
105
|
}
|
|
113
106
|
else {
|
|
114
|
-
// Lógica padrão para Windows, Mac e NVIDIA
|
|
115
107
|
videoFilter = forceResolution ? `-s ${w}x${h}` : `-filter:v scale=-1:${h}`;
|
|
116
108
|
}
|
|
117
|
-
//
|
|
118
|
-
const
|
|
119
|
-
|
|
109
|
+
// O vídeo WebM necessita de codecs de áudio específicos como o Opus
|
|
110
|
+
const acodec = "-c:a libopus -b:a 128k";
|
|
111
|
+
// A flag '-f webm' força explicitamente a criação de um contentor de vídeo WebM
|
|
112
|
+
const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} ${acodec} -f webm -y "${output}"`;
|
|
120
113
|
return execAsync(command);
|
|
121
114
|
}
|
|
122
|
-
// async function getBestEncoder(): Promise<string> {
|
|
123
|
-
// try {
|
|
124
|
-
// const { stdout } = (await execAsync("ffmpeg -encoders")) as {
|
|
125
|
-
// stdout: string;
|
|
126
|
-
// };
|
|
127
|
-
// // Prioridade para AMD (Windows: amf | Linux: vaapi)
|
|
128
|
-
// if (stdout.includes("h264_amf")) return "h264_amf";
|
|
129
|
-
// if (stdout.includes("h264_vaapi")) return "h264_vaapi";
|
|
130
|
-
// // Outros hardwares
|
|
131
|
-
// if (stdout.includes("h264_nvenc")) return "h264_nvenc";
|
|
132
|
-
// if (stdout.includes("h264_qsv")) return "h264_qsv";
|
|
133
|
-
// if (stdout.includes("h264_videotoolbox")) return "h264_videotoolbox";
|
|
134
|
-
// return "libx264"; // Fallback
|
|
135
|
-
// } catch {
|
|
136
|
-
// return "libx264";
|
|
137
|
-
// }
|
|
138
|
-
// }
|
|
139
|
-
// export async function ffmpeg_video_compress(
|
|
140
|
-
// input: string,
|
|
141
|
-
// output: string,
|
|
142
|
-
// resolution: Resolution = "480p",
|
|
143
|
-
// forceResolution?: boolean,
|
|
144
|
-
// ) {
|
|
145
|
-
// const { w, h } = resolutionMapping[resolution];
|
|
146
|
-
// const encoder = await getBestEncoder();
|
|
147
|
-
// // No VA-API (Linux), o redimensionamento deve ser feito via hardware para máxima performance
|
|
148
|
-
// let filter = forceResolution ? `scale=${w}:${h}` : `scale=-1:${h}`;
|
|
149
|
-
// if (encoder === "h264_vaapi") {
|
|
150
|
-
// // Adiciona upload para hardware se usar vaapi
|
|
151
|
-
// filter = `format=nv12,hwupload,scale_vaapi=w=${forceResolution ? w : -1}:h=${h}`;
|
|
152
|
-
// }
|
|
153
|
-
// const vaapiOpts =
|
|
154
|
-
// encoder === "h264_vaapi" ? "-vaapi_device /dev/dri/renderD128" : "";
|
|
155
|
-
// console.log("Compressing video using: ", encoder);
|
|
156
|
-
// return execAsync(
|
|
157
|
-
// `ffmpeg ${vaapiOpts} -i "${input}" -vf "${filter}" -c:v ${encoder} -pix_fmt yuv420p -acodec copy -y "${output}"`,
|
|
158
|
-
// );
|
|
159
|
-
// }
|
|
160
|
-
// export async function ffmpeg_video_compress(
|
|
161
|
-
// input: string,
|
|
162
|
-
// output: string,
|
|
163
|
-
// resolution: Resolution = "480p",
|
|
164
|
-
// forceResolution?: boolean
|
|
165
|
-
// ) {
|
|
166
|
-
// const { w, h } = resolutionMapping[resolution];
|
|
167
|
-
// return execAsync(
|
|
168
|
-
// forceResolution
|
|
169
|
-
// ? `ffmpeg -i "${input}" -s ${w}x${h} -acodec copy -y "${output}"`
|
|
170
|
-
// : `ffmpeg -i "${input}" -filter:v scale=-1:${h} -acodec copy -y "${output}"`
|
|
171
|
-
// );
|
|
172
|
-
// }
|
|
173
115
|
export async function ffmpeg_image_to_webp(input, output) {
|
|
174
116
|
return execAsync(`ffmpeg -i "${input}" -c:v libwebp "${output}"`);
|
|
175
117
|
}
|
package/bin/lib/bash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/lib/bash.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/lib/bash.ts"],"names":[],"mappings":"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"}
|
package/bin/main.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
check_dependencies,
|
|
19
19
|
ffmpeg_image_to_webp,
|
|
20
|
-
|
|
20
|
+
ffmpeg_video_compress_webm,
|
|
21
21
|
} from "../lib/bash.js";
|
|
22
22
|
|
|
23
23
|
export const FileType = ["image", "video"] as const;
|
|
@@ -25,11 +25,11 @@ type FileType = (typeof FileType)[number];
|
|
|
25
25
|
|
|
26
26
|
const unsupportedFormats: { [key in FileType]: string[] } = {
|
|
27
27
|
image: ["image/webp", "image/gif", "image/svg+xml"],
|
|
28
|
-
video: [],
|
|
28
|
+
video: ["video/webm"],
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
const compressedFlagPrefix = "compressed_" as const;
|
|
32
|
-
const compressTempPrefix = "temp." as const;
|
|
31
|
+
// const compressedFlagPrefix = "compressed_" as const;
|
|
32
|
+
// const compressTempPrefix = "temp." as const;
|
|
33
33
|
|
|
34
34
|
export type CompressFileArgs = {
|
|
35
35
|
verbose: number;
|
|
@@ -58,11 +58,7 @@ export async function file(
|
|
|
58
58
|
const fileType = mimetype.split("/")[0] as FileType;
|
|
59
59
|
if (
|
|
60
60
|
!(type ? [type] : FileType).includes(fileType as FileType) ||
|
|
61
|
-
(unsupportedFormats[fileType] || []).includes(mimetype)
|
|
62
|
-
(!force &&
|
|
63
|
-
[compressedFlagPrefix, compressTempPrefix].some((pf) =>
|
|
64
|
-
getFilename(filePath).startsWith(pf),
|
|
65
|
-
))
|
|
61
|
+
(unsupportedFormats[fileType] || []).includes(mimetype)
|
|
66
62
|
)
|
|
67
63
|
continue;
|
|
68
64
|
|
|
@@ -82,9 +78,8 @@ export async function file(
|
|
|
82
78
|
else if (fileType === "video")
|
|
83
79
|
await compressVideo(filePath, resolution, horizontal);
|
|
84
80
|
} catch (err) {
|
|
85
|
-
if (verbose) console.error(" Error compressing", err);
|
|
81
|
+
if (verbose > 10) console.error(" Error compressing", err);
|
|
86
82
|
else console.error(" Error compressing", `"${filePath}"`);
|
|
87
|
-
// console.error("Error compressing", `"${filePath}"`, err.message);
|
|
88
83
|
}
|
|
89
84
|
}
|
|
90
85
|
|
|
@@ -92,9 +87,6 @@ export async function file(
|
|
|
92
87
|
}
|
|
93
88
|
|
|
94
89
|
async function compressImage(filePath: string) {
|
|
95
|
-
// await sharp(filePath)
|
|
96
|
-
// .webp()
|
|
97
|
-
// .toFile(replaceFilenameExtension(filePath, "webp"));
|
|
98
90
|
await ffmpeg_image_to_webp(
|
|
99
91
|
filePath,
|
|
100
92
|
replaceFilenameExtension(filePath, "webp"),
|
|
@@ -107,52 +99,11 @@ async function compressVideo(
|
|
|
107
99
|
resolution: Resolution,
|
|
108
100
|
force?: boolean,
|
|
109
101
|
) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const oldPathname = path.join(directory, filename);
|
|
116
|
-
const newPathname = await getAvailablePathname(
|
|
117
|
-
path.join(directory, normalizedFilename),
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
if (!newPathname) {
|
|
121
|
-
throw new CommanderError(
|
|
122
|
-
1,
|
|
123
|
-
"P003",
|
|
124
|
-
"Could not find a new file destination",
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const newFilename = getFilename(newPathname);
|
|
129
|
-
console.log(
|
|
130
|
-
" File renamed. From:",
|
|
131
|
-
`'${filename.trim()}'`,
|
|
132
|
-
"to:",
|
|
133
|
-
`'${newFilename.trim()}'`,
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
await fs.rename(oldPathname, newPathname);
|
|
137
|
-
filename = newFilename;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const input = path.join(directory, filename);
|
|
141
|
-
const output = addFilenamePrefix(input, compressTempPrefix);
|
|
142
|
-
|
|
143
|
-
await ffmpeg_video_compress(input, output, resolution, force).catch(
|
|
144
|
-
async (err) => {
|
|
145
|
-
await fs.rm(output);
|
|
146
|
-
throw err;
|
|
147
|
-
},
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
await fs.rm(input);
|
|
151
|
-
await fs.rename(
|
|
152
|
-
output,
|
|
153
|
-
addFilenamePrefix(
|
|
154
|
-
removeFilenamePrefix(input, compressedFlagPrefix),
|
|
155
|
-
compressedFlagPrefix,
|
|
156
|
-
),
|
|
102
|
+
await ffmpeg_video_compress_webm(
|
|
103
|
+
filePath,
|
|
104
|
+
replaceFilenameExtension(filePath, "webm"),
|
|
105
|
+
resolution,
|
|
106
|
+
force,
|
|
157
107
|
);
|
|
108
|
+
await fs.rm(filePath);
|
|
158
109
|
}
|
package/src/lib/bash.ts
CHANGED
|
@@ -92,13 +92,12 @@ async function detectGPU(): Promise<GpuType> {
|
|
|
92
92
|
return cachedGpuType;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export async function
|
|
95
|
+
export async function ffmpeg_video_compress_webm(
|
|
96
96
|
input: string,
|
|
97
97
|
output: string,
|
|
98
98
|
resolution: Resolution = "480p",
|
|
99
99
|
forceResolution?: boolean,
|
|
100
100
|
) {
|
|
101
|
-
// Exemplo de mapeamento (ajuste para bater com o seu código original)
|
|
102
101
|
const resolutionMapping: { [key in Resolution]: { w: number; h: number } } = {
|
|
103
102
|
"4320p": { w: 7680, h: 4320 }, // 8K
|
|
104
103
|
"2160p": { w: 3840, h: 2160 }, // 4K
|
|
@@ -111,111 +110,41 @@ export async function ffmpeg_video_compress(
|
|
|
111
110
|
};
|
|
112
111
|
|
|
113
112
|
const { w, h } = resolutionMapping[resolution];
|
|
114
|
-
|
|
115
|
-
// 1. Detecta a GPU automaticamente
|
|
116
113
|
const gpu = await detectGPU();
|
|
117
|
-
|
|
118
|
-
// 2. Verifica se é Linux para usar a estratégia correta
|
|
119
114
|
const isLinux = os.platform() === "linux";
|
|
120
115
|
|
|
121
|
-
//
|
|
116
|
+
// Utilizamos o codec VP9, que é o padrão moderno de alta qualidade para vídeos WebM
|
|
122
117
|
const encoders = {
|
|
123
|
-
nvidia: "-c:v
|
|
124
|
-
amd: isLinux ? "-c:v
|
|
125
|
-
intel: isLinux ? "-c:v
|
|
126
|
-
mac: "-c:v
|
|
127
|
-
cpu: "-c:v
|
|
118
|
+
nvidia: "-c:v vp9_nvenc -preset p4",
|
|
119
|
+
amd: isLinux ? "-c:v vp9_vaapi" : "-c:v vp9_amf",
|
|
120
|
+
intel: isLinux ? "-c:v vp9_vaapi" : "-c:v vp9_qsv",
|
|
121
|
+
mac: "-c:v libvpx-vp9 -row-mt 1 -cpu-used 4",
|
|
122
|
+
cpu: "-c:v libvpx-vp9 -row-mt 1 -cpu-used 4",
|
|
128
123
|
};
|
|
129
124
|
|
|
130
125
|
const vcodec = encoders[gpu] || encoders.cpu;
|
|
131
126
|
|
|
132
|
-
|
|
133
|
-
let hwaccel = gpu === "cpu" ? "" : "-hwaccel auto";
|
|
127
|
+
let hwaccel = gpu === "cpu" || gpu === "mac" ? "" : "-hwaccel auto";
|
|
134
128
|
let videoFilter = "";
|
|
135
129
|
|
|
136
|
-
// Lógica específica para o VA-API (AMD/Intel no Linux)
|
|
137
130
|
if (isLinux && (gpu === "amd" || gpu === "intel")) {
|
|
138
|
-
// Aponta diretamente para a placa de vídeo no Linux
|
|
139
131
|
hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
140
|
-
|
|
141
|
-
// O VA-API precisa que o formato seja nv12 e faça o upload para a GPU
|
|
142
132
|
videoFilter = forceResolution
|
|
143
133
|
? `-vf "scale=${w}:${h},format=nv12,hwupload"`
|
|
144
134
|
: `-vf "scale=-1:${h},format=nv12,hwupload"`;
|
|
145
135
|
} else {
|
|
146
|
-
// Lógica padrão para Windows, Mac e NVIDIA
|
|
147
136
|
videoFilter = forceResolution ? `-s ${w}x${h}` : `-filter:v scale=-1:${h}`;
|
|
148
137
|
}
|
|
149
138
|
|
|
150
|
-
//
|
|
151
|
-
const
|
|
139
|
+
// O vídeo WebM necessita de codecs de áudio específicos como o Opus
|
|
140
|
+
const acodec = "-c:a libopus -b:a 128k";
|
|
152
141
|
|
|
153
|
-
|
|
142
|
+
// A flag '-f webm' força explicitamente a criação de um contentor de vídeo WebM
|
|
143
|
+
const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} ${acodec} -f webm -y "${output}"`;
|
|
154
144
|
|
|
155
145
|
return execAsync(command);
|
|
156
146
|
}
|
|
157
147
|
|
|
158
|
-
// async function getBestEncoder(): Promise<string> {
|
|
159
|
-
// try {
|
|
160
|
-
// const { stdout } = (await execAsync("ffmpeg -encoders")) as {
|
|
161
|
-
// stdout: string;
|
|
162
|
-
// };
|
|
163
|
-
|
|
164
|
-
// // Prioridade para AMD (Windows: amf | Linux: vaapi)
|
|
165
|
-
// if (stdout.includes("h264_amf")) return "h264_amf";
|
|
166
|
-
// if (stdout.includes("h264_vaapi")) return "h264_vaapi";
|
|
167
|
-
|
|
168
|
-
// // Outros hardwares
|
|
169
|
-
// if (stdout.includes("h264_nvenc")) return "h264_nvenc";
|
|
170
|
-
// if (stdout.includes("h264_qsv")) return "h264_qsv";
|
|
171
|
-
// if (stdout.includes("h264_videotoolbox")) return "h264_videotoolbox";
|
|
172
|
-
|
|
173
|
-
// return "libx264"; // Fallback
|
|
174
|
-
// } catch {
|
|
175
|
-
// return "libx264";
|
|
176
|
-
// }
|
|
177
|
-
// }
|
|
178
|
-
|
|
179
|
-
// export async function ffmpeg_video_compress(
|
|
180
|
-
// input: string,
|
|
181
|
-
// output: string,
|
|
182
|
-
// resolution: Resolution = "480p",
|
|
183
|
-
// forceResolution?: boolean,
|
|
184
|
-
// ) {
|
|
185
|
-
// const { w, h } = resolutionMapping[resolution];
|
|
186
|
-
// const encoder = await getBestEncoder();
|
|
187
|
-
|
|
188
|
-
// // No VA-API (Linux), o redimensionamento deve ser feito via hardware para máxima performance
|
|
189
|
-
// let filter = forceResolution ? `scale=${w}:${h}` : `scale=-1:${h}`;
|
|
190
|
-
// if (encoder === "h264_vaapi") {
|
|
191
|
-
// // Adiciona upload para hardware se usar vaapi
|
|
192
|
-
// filter = `format=nv12,hwupload,scale_vaapi=w=${forceResolution ? w : -1}:h=${h}`;
|
|
193
|
-
// }
|
|
194
|
-
|
|
195
|
-
// const vaapiOpts =
|
|
196
|
-
// encoder === "h264_vaapi" ? "-vaapi_device /dev/dri/renderD128" : "";
|
|
197
|
-
|
|
198
|
-
// console.log("Compressing video using: ", encoder);
|
|
199
|
-
|
|
200
|
-
// return execAsync(
|
|
201
|
-
// `ffmpeg ${vaapiOpts} -i "${input}" -vf "${filter}" -c:v ${encoder} -pix_fmt yuv420p -acodec copy -y "${output}"`,
|
|
202
|
-
// );
|
|
203
|
-
// }
|
|
204
|
-
// export async function ffmpeg_video_compress(
|
|
205
|
-
// input: string,
|
|
206
|
-
// output: string,
|
|
207
|
-
// resolution: Resolution = "480p",
|
|
208
|
-
// forceResolution?: boolean
|
|
209
|
-
// ) {
|
|
210
|
-
// const { w, h } = resolutionMapping[resolution];
|
|
211
|
-
|
|
212
|
-
// return execAsync(
|
|
213
|
-
// forceResolution
|
|
214
|
-
// ? `ffmpeg -i "${input}" -s ${w}x${h} -acodec copy -y "${output}"`
|
|
215
|
-
// : `ffmpeg -i "${input}" -filter:v scale=-1:${h} -acodec copy -y "${output}"`
|
|
216
|
-
// );
|
|
217
|
-
// }
|
|
218
|
-
|
|
219
148
|
export async function ffmpeg_image_to_webp(input: string, output: string) {
|
|
220
149
|
return execAsync(`ffmpeg -i "${input}" -c:v libwebp "${output}"`);
|
|
221
150
|
}
|