@zwa73/utils 1.0.60 → 1.0.62
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/dist/UtilCodecs.d.ts +16 -16
- package/dist/UtilCodecs.js +16 -16
- package/dist/UtilCom.d.ts +22 -25
- package/dist/UtilCom.js +35 -38
- package/dist/UtilDecorators.d.ts +15 -8
- package/dist/UtilDecorators.js +79 -25
- package/dist/UtilFP.d.ts +46 -0
- package/dist/UtilFP.js +52 -0
- package/dist/UtilFfmpegTools.d.ts +30 -30
- package/dist/UtilFfmpegTools.js +32 -32
- package/dist/UtilFileTools.d.ts +30 -35
- package/dist/UtilFileTools.js +17 -18
- package/dist/UtilFunctions.d.ts +37 -78
- package/dist/UtilFunctions.js +27 -62
- package/dist/UtilInterfaces.d.ts +26 -11
- package/dist/UtilInterfaces.js +12 -3
- package/dist/UtilLogger.d.ts +55 -55
- package/dist/UtilLogger.js +55 -55
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/test/composeTest.d.ts +26 -0
- package/dist/test/composeTest.js +50 -0
- package/dist/test/importtest.d.ts +1 -0
- package/dist/test/importtest.js +4 -0
- package/dist/test/test.js +5 -3
- package/package.json +1 -1
- package/src/UtilClass.ts +1051 -1051
- package/src/UtilCodecs.ts +117 -117
- package/src/UtilCom.ts +171 -174
- package/src/UtilDecorators.ts +174 -116
- package/src/UtilFP.ts +98 -0
- package/src/UtilFfmpegTools.ts +271 -271
- package/src/UtilFileTools.ts +231 -236
- package/src/UtilFunctions.ts +289 -364
- package/src/UtilInterfaces.ts +158 -138
- package/src/UtilLogger.ts +386 -386
- package/src/index.ts +10 -9
- package/src/test/composeTest.ts +50 -0
- package/src/test/importtest.ts +5 -0
- package/src/test/test.ts +8 -6
- package/src/test/test2.ts +2 -3
- package/tsconfig.json +2 -7
package/src/UtilFfmpegTools.ts
CHANGED
|
@@ -1,271 +1,271 @@
|
|
|
1
|
-
import { FfmpegCommand, FfprobeData } from "fluent-ffmpeg";
|
|
2
|
-
import * as fluentFfmpeg from "fluent-ffmpeg";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import * as fs from "fs";
|
|
5
|
-
import { SList, SStream } from "
|
|
6
|
-
import { SLogger } from "
|
|
7
|
-
|
|
8
|
-
/**输入输出路径映射
|
|
9
|
-
* 输入路径:输入路径
|
|
10
|
-
*/
|
|
11
|
-
export type IOMap = { [key: string]: string };
|
|
12
|
-
|
|
13
|
-
/**ffmpeg工具类
|
|
14
|
-
*/
|
|
15
|
-
class SFfmpegTool {
|
|
16
|
-
/**静态构造函数
|
|
17
|
-
*/
|
|
18
|
-
static init() {
|
|
19
|
-
let ffmpegPath = process.env.FFMPEG_PATH;
|
|
20
|
-
if(ffmpegPath!=null){
|
|
21
|
-
let exepath = path.join(ffmpegPath,"ffmpeg.exe");
|
|
22
|
-
SFfmpegTool.setFfmpegPath(exepath);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**设置ffmpeg路径
|
|
26
|
-
*/
|
|
27
|
-
static setFfmpegPath(ffmpegPath: string) {
|
|
28
|
-
fluentFfmpeg.setFfmpegPath(ffmpegPath);
|
|
29
|
-
}
|
|
30
|
-
/**获取音频文件的元数据
|
|
31
|
-
* @param
|
|
32
|
-
* @returns
|
|
33
|
-
*/
|
|
34
|
-
static async getAudioMetaData(
|
|
35
|
-
inputWavPath: string
|
|
36
|
-
): Promise<FfprobeData | null> {
|
|
37
|
-
return new Promise((resolve, reject) => {
|
|
38
|
-
fluentFfmpeg.ffprobe(inputWavPath, function (err, metadata) {
|
|
39
|
-
if (err) {
|
|
40
|
-
SLogger.error("SFfmpegTool.getAudioMetaData 错误",err);
|
|
41
|
-
resolve(null);
|
|
42
|
-
} else {
|
|
43
|
-
resolve(metadata);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
/**flac转ogg
|
|
49
|
-
* @param
|
|
50
|
-
* @param
|
|
51
|
-
* @param
|
|
52
|
-
*/
|
|
53
|
-
static async flac2ogg(
|
|
54
|
-
inputFlacFile: string,
|
|
55
|
-
outputOggPath: string,
|
|
56
|
-
quality: number = 10
|
|
57
|
-
): Promise<boolean> {
|
|
58
|
-
let wavPath = path.join(
|
|
59
|
-
path.dirname(inputFlacFile),
|
|
60
|
-
`tmp_${path.basename(inputFlacFile, ".flac")}.wav`
|
|
61
|
-
);
|
|
62
|
-
await new Promise((resolve, reject) => {
|
|
63
|
-
fluentFfmpeg(inputFlacFile)
|
|
64
|
-
.audioCodec("pcm_s16le")
|
|
65
|
-
.save(wavPath)
|
|
66
|
-
.on("end", function () {
|
|
67
|
-
resolve(null);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
await SFfmpegTool.wav2ogg(wavPath, outputOggPath, quality);
|
|
71
|
-
await new Promise((resolve, reject) => {
|
|
72
|
-
fs.unlink(wavPath, function (err) {
|
|
73
|
-
if (err) SLogger.error("SFfmpegTool.flac2ogg unlink 错误",err);
|
|
74
|
-
resolve(null);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
/**wav转ogg
|
|
80
|
-
* @param
|
|
81
|
-
* @param
|
|
82
|
-
* @param
|
|
83
|
-
*/
|
|
84
|
-
static async wav2ogg(
|
|
85
|
-
inputWavPath: string,
|
|
86
|
-
outputOggPath: string,
|
|
87
|
-
quality: number = 10
|
|
88
|
-
): Promise<boolean> {
|
|
89
|
-
//.audioQuality(10)
|
|
90
|
-
//.audioBitrate("192k")
|
|
91
|
-
//.audioChannels(channels)
|
|
92
|
-
//.noMetadata()
|
|
93
|
-
return new Promise((resolve, reject) => {
|
|
94
|
-
fluentFfmpeg(inputWavPath)
|
|
95
|
-
.audioQuality(quality)
|
|
96
|
-
.audioCodec("libvorbis")
|
|
97
|
-
.save(outputOggPath)
|
|
98
|
-
.on("end", () => resolve(true))
|
|
99
|
-
.on("error", (err) => reject(err));
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
/**剪切音频
|
|
103
|
-
* @param
|
|
104
|
-
* @param
|
|
105
|
-
* @param
|
|
106
|
-
* @param
|
|
107
|
-
*/
|
|
108
|
-
static async cutAudio(
|
|
109
|
-
audioPath: string,
|
|
110
|
-
outPath: string,
|
|
111
|
-
start: number,
|
|
112
|
-
time: number
|
|
113
|
-
): Promise<boolean> {
|
|
114
|
-
return new Promise((resolve, reject) => {
|
|
115
|
-
fluentFfmpeg(audioPath)
|
|
116
|
-
.setStartTime(start)
|
|
117
|
-
.setDuration(time)
|
|
118
|
-
.save(outPath)
|
|
119
|
-
.on("end", () => resolve(true))
|
|
120
|
-
.on("error", (err) => reject(err));
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
/**删除首尾静音
|
|
124
|
-
* @param
|
|
125
|
-
* @param
|
|
126
|
-
* @param
|
|
127
|
-
* @param
|
|
128
|
-
*/
|
|
129
|
-
static async trimSilence(
|
|
130
|
-
inputWavPath: string,
|
|
131
|
-
outputWavPath: string,
|
|
132
|
-
threshold: number = -50,
|
|
133
|
-
silence: number = 0.2
|
|
134
|
-
): Promise<boolean> {
|
|
135
|
-
return new Promise((resolve, reject) => {
|
|
136
|
-
fluentFfmpeg(inputWavPath)
|
|
137
|
-
.audioFilters(
|
|
138
|
-
`silenceremove=start_periods=1:start_threshold=${threshold}dB:start_silence=${silence}`
|
|
139
|
-
)
|
|
140
|
-
.audioFilters("areverse")
|
|
141
|
-
.audioFilters(
|
|
142
|
-
`silenceremove=start_periods=1:start_threshold=${threshold}dB:start_silence=${silence}`
|
|
143
|
-
)
|
|
144
|
-
.audioFilters("areverse")
|
|
145
|
-
.save(outputWavPath)
|
|
146
|
-
.on("end", () => resolve(true))
|
|
147
|
-
.on("error", (err) => reject(err));
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
/**重采样
|
|
151
|
-
* @param
|
|
152
|
-
* @param
|
|
153
|
-
*/
|
|
154
|
-
static async resample(inputWavPath: string, outputWavPath: string, rate: number = 22050): Promise<boolean> {
|
|
155
|
-
return new Promise((resolve, reject) => {
|
|
156
|
-
fluentFfmpeg(inputWavPath)
|
|
157
|
-
.audioFrequency(rate)
|
|
158
|
-
.save(outputWavPath)
|
|
159
|
-
.on("end", () => resolve(true))
|
|
160
|
-
.on("error", (err) => reject(err));
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
//多线程处理
|
|
165
|
-
/**wav转ogg多线程
|
|
166
|
-
* @param
|
|
167
|
-
* @param
|
|
168
|
-
* @param
|
|
169
|
-
*/
|
|
170
|
-
static async wav2oggMP(ioMap: IOMap, quality = 10, cpCount = 16) {
|
|
171
|
-
await new SList(Object.entries(ioMap))
|
|
172
|
-
.toSStream(cpCount)
|
|
173
|
-
.map(async ([inPath, outPath]) => {
|
|
174
|
-
SLogger.info("SFfmpegTool.wav2oggMP 正在处理:" + outPath);
|
|
175
|
-
await SFfmpegTool.wav2ogg(inPath, outPath, quality);
|
|
176
|
-
})
|
|
177
|
-
.appendOperations();
|
|
178
|
-
}
|
|
179
|
-
/**flac转ogg多线程
|
|
180
|
-
* @param
|
|
181
|
-
* @param
|
|
182
|
-
* @param
|
|
183
|
-
*/
|
|
184
|
-
static async flac2oggMP(
|
|
185
|
-
ioMap: IOMap,
|
|
186
|
-
quality: number = 10,
|
|
187
|
-
cpCount: number = 16
|
|
188
|
-
) {
|
|
189
|
-
await new SList(Object.entries(ioMap))
|
|
190
|
-
.toSStream(cpCount)
|
|
191
|
-
.map(async ([inPath, outPath]) => {
|
|
192
|
-
SLogger.info("SFfmpegTool.flac2oggMP 正在处理:" + outPath);
|
|
193
|
-
await SFfmpegTool.flac2ogg(inPath, outPath, quality);
|
|
194
|
-
})
|
|
195
|
-
.appendOperations();
|
|
196
|
-
}
|
|
197
|
-
/**删除静音多线程
|
|
198
|
-
* @param
|
|
199
|
-
* @param
|
|
200
|
-
* @param
|
|
201
|
-
*/
|
|
202
|
-
static async trimSilenceMP(
|
|
203
|
-
ioMap: IOMap,
|
|
204
|
-
threshold: number = -50,
|
|
205
|
-
silence: number = 0.2,
|
|
206
|
-
cpCount: number = 16
|
|
207
|
-
) {
|
|
208
|
-
await new SList(Object.entries(ioMap))
|
|
209
|
-
.toSStream(cpCount)
|
|
210
|
-
.map(async ([inPath, outPath]) => {
|
|
211
|
-
SLogger.info("SFfmpegTool.trimSilenceMP 正在处理:" + outPath);
|
|
212
|
-
await SFfmpegTool.trimSilence(inPath, outPath, threshold, silence);
|
|
213
|
-
})
|
|
214
|
-
.appendOperations();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**重采样多线程
|
|
218
|
-
* @param
|
|
219
|
-
* @param
|
|
220
|
-
* @param
|
|
221
|
-
*/
|
|
222
|
-
static async resampleMP(ioMap: IOMap, rate: number = 22050, cpCount: number = 16) {
|
|
223
|
-
await new SList(Object.entries(ioMap))
|
|
224
|
-
.toSStream(cpCount)
|
|
225
|
-
.map(async ([inPath, outPath]) => {
|
|
226
|
-
SLogger.info("SFfmpegTool.resampleMP 正在处理:" + outPath);
|
|
227
|
-
await SFfmpegTool.resample(inPath, outPath, rate);
|
|
228
|
-
})
|
|
229
|
-
.appendOperations();
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
SFfmpegTool.init();
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
/**多线程任务分割器
|
|
236
|
-
* @param
|
|
237
|
-
* @param
|
|
238
|
-
*/
|
|
239
|
-
function MPClip(iomap: IOMap, cpCount: number = 16) {
|
|
240
|
-
let cpList: Array<IOMap> = [];
|
|
241
|
-
for (let i = 0; i < cpCount; i++) cpList.push({});
|
|
242
|
-
let cpCounter = 0;
|
|
243
|
-
for (let key in iomap) {
|
|
244
|
-
let cpIndex = cpCounter % cpCount;
|
|
245
|
-
cpCounter++;
|
|
246
|
-
cpList[cpIndex][key] = iomap[key];
|
|
247
|
-
}
|
|
248
|
-
return cpList;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
type SFfmpegCmd = {
|
|
252
|
-
name: string;
|
|
253
|
-
opt: string | null;
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
/**ffmpeg流
|
|
257
|
-
*/
|
|
258
|
-
class SFfmpegStream {
|
|
259
|
-
iomap;
|
|
260
|
-
cmdList: Array<SFfmpegCmd> = [];
|
|
261
|
-
constructor(iomap: IOMap) {
|
|
262
|
-
this.iomap = iomap;
|
|
263
|
-
}
|
|
264
|
-
async save() {}
|
|
265
|
-
|
|
266
|
-
//执行函数
|
|
267
|
-
private async cmdAreverse() {}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export default SFfmpegTool;
|
|
271
|
-
export { SFfmpegTool };
|
|
1
|
+
import { FfmpegCommand, FfprobeData } from "fluent-ffmpeg";
|
|
2
|
+
import * as fluentFfmpeg from "fluent-ffmpeg";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import { SList, SStream } from "@src/UtilClass";
|
|
6
|
+
import { SLogger } from "@src/UtilLogger";
|
|
7
|
+
|
|
8
|
+
/**输入输出路径映射
|
|
9
|
+
* 输入路径:输入路径
|
|
10
|
+
*/
|
|
11
|
+
export type IOMap = { [key: string]: string };
|
|
12
|
+
|
|
13
|
+
/**ffmpeg工具类
|
|
14
|
+
*/
|
|
15
|
+
class SFfmpegTool {
|
|
16
|
+
/**静态构造函数
|
|
17
|
+
*/
|
|
18
|
+
static init() {
|
|
19
|
+
let ffmpegPath = process.env.FFMPEG_PATH;
|
|
20
|
+
if(ffmpegPath!=null){
|
|
21
|
+
let exepath = path.join(ffmpegPath,"ffmpeg.exe");
|
|
22
|
+
SFfmpegTool.setFfmpegPath(exepath);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**设置ffmpeg路径
|
|
26
|
+
*/
|
|
27
|
+
static setFfmpegPath(ffmpegPath: string) {
|
|
28
|
+
fluentFfmpeg.setFfmpegPath(ffmpegPath);
|
|
29
|
+
}
|
|
30
|
+
/**获取音频文件的元数据
|
|
31
|
+
* @param inputWavPath - 输入音频文件路径
|
|
32
|
+
* @returns 返回音频文件的元数据
|
|
33
|
+
*/
|
|
34
|
+
static async getAudioMetaData(
|
|
35
|
+
inputWavPath: string
|
|
36
|
+
): Promise<FfprobeData | null> {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
fluentFfmpeg.ffprobe(inputWavPath, function (err, metadata) {
|
|
39
|
+
if (err) {
|
|
40
|
+
SLogger.error("SFfmpegTool.getAudioMetaData 错误",err);
|
|
41
|
+
resolve(null);
|
|
42
|
+
} else {
|
|
43
|
+
resolve(metadata);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**flac转ogg
|
|
49
|
+
* @param inputFlacFile - 输入flac文件路径
|
|
50
|
+
* @param outputOggPath - 输出ogg文件路径
|
|
51
|
+
* @param quality - 质量
|
|
52
|
+
*/
|
|
53
|
+
static async flac2ogg(
|
|
54
|
+
inputFlacFile: string,
|
|
55
|
+
outputOggPath: string,
|
|
56
|
+
quality: number = 10
|
|
57
|
+
): Promise<boolean> {
|
|
58
|
+
let wavPath = path.join(
|
|
59
|
+
path.dirname(inputFlacFile),
|
|
60
|
+
`tmp_${path.basename(inputFlacFile, ".flac")}.wav`
|
|
61
|
+
);
|
|
62
|
+
await new Promise((resolve, reject) => {
|
|
63
|
+
fluentFfmpeg(inputFlacFile)
|
|
64
|
+
.audioCodec("pcm_s16le")
|
|
65
|
+
.save(wavPath)
|
|
66
|
+
.on("end", function () {
|
|
67
|
+
resolve(null);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
await SFfmpegTool.wav2ogg(wavPath, outputOggPath, quality);
|
|
71
|
+
await new Promise((resolve, reject) => {
|
|
72
|
+
fs.unlink(wavPath, function (err) {
|
|
73
|
+
if (err) SLogger.error("SFfmpegTool.flac2ogg unlink 错误",err);
|
|
74
|
+
resolve(null);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
/**wav转ogg
|
|
80
|
+
* @param inputWavPath - 输入wav文件路径
|
|
81
|
+
* @param outputOggPath - 输出ogg文件路径
|
|
82
|
+
* @param quality - 质量
|
|
83
|
+
*/
|
|
84
|
+
static async wav2ogg(
|
|
85
|
+
inputWavPath: string,
|
|
86
|
+
outputOggPath: string,
|
|
87
|
+
quality: number = 10
|
|
88
|
+
): Promise<boolean> {
|
|
89
|
+
//.audioQuality(10)
|
|
90
|
+
//.audioBitrate("192k")
|
|
91
|
+
//.audioChannels(channels)
|
|
92
|
+
//.noMetadata()
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
fluentFfmpeg(inputWavPath)
|
|
95
|
+
.audioQuality(quality)
|
|
96
|
+
.audioCodec("libvorbis")
|
|
97
|
+
.save(outputOggPath)
|
|
98
|
+
.on("end", () => resolve(true))
|
|
99
|
+
.on("error", (err) => reject(err));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**剪切音频
|
|
103
|
+
* @param audioPath - 输入音频文件路径
|
|
104
|
+
* @param outPath - 输出音频文件路径
|
|
105
|
+
* @param start - 开始时间
|
|
106
|
+
* @param time - 时长
|
|
107
|
+
*/
|
|
108
|
+
static async cutAudio(
|
|
109
|
+
audioPath: string,
|
|
110
|
+
outPath: string,
|
|
111
|
+
start: number,
|
|
112
|
+
time: number
|
|
113
|
+
): Promise<boolean> {
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
fluentFfmpeg(audioPath)
|
|
116
|
+
.setStartTime(start)
|
|
117
|
+
.setDuration(time)
|
|
118
|
+
.save(outPath)
|
|
119
|
+
.on("end", () => resolve(true))
|
|
120
|
+
.on("error", (err) => reject(err));
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**删除首尾静音
|
|
124
|
+
* @param inputWavPath - 输入wav文件路径
|
|
125
|
+
* @param outputWavPath - 输出wav文件路径
|
|
126
|
+
* @param threshold - 静音阈值/dB
|
|
127
|
+
* @param silence - 保留静音时长
|
|
128
|
+
*/
|
|
129
|
+
static async trimSilence(
|
|
130
|
+
inputWavPath: string,
|
|
131
|
+
outputWavPath: string,
|
|
132
|
+
threshold: number = -50,
|
|
133
|
+
silence: number = 0.2
|
|
134
|
+
): Promise<boolean> {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
fluentFfmpeg(inputWavPath)
|
|
137
|
+
.audioFilters(
|
|
138
|
+
`silenceremove=start_periods=1:start_threshold=${threshold}dB:start_silence=${silence}`
|
|
139
|
+
)
|
|
140
|
+
.audioFilters("areverse")
|
|
141
|
+
.audioFilters(
|
|
142
|
+
`silenceremove=start_periods=1:start_threshold=${threshold}dB:start_silence=${silence}`
|
|
143
|
+
)
|
|
144
|
+
.audioFilters("areverse")
|
|
145
|
+
.save(outputWavPath)
|
|
146
|
+
.on("end", () => resolve(true))
|
|
147
|
+
.on("error", (err) => reject(err));
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**重采样
|
|
151
|
+
* @param inputWavPath - 输入wav文件路径
|
|
152
|
+
* @param outputWavPath - 输出wav文件路径
|
|
153
|
+
*/
|
|
154
|
+
static async resample(inputWavPath: string, outputWavPath: string, rate: number = 22050): Promise<boolean> {
|
|
155
|
+
return new Promise((resolve, reject) => {
|
|
156
|
+
fluentFfmpeg(inputWavPath)
|
|
157
|
+
.audioFrequency(rate)
|
|
158
|
+
.save(outputWavPath)
|
|
159
|
+
.on("end", () => resolve(true))
|
|
160
|
+
.on("error", (err) => reject(err));
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
//多线程处理
|
|
165
|
+
/**wav转ogg多线程
|
|
166
|
+
* @param ioMap - 输入输出路径映射
|
|
167
|
+
* @param quality - 质量
|
|
168
|
+
* @param cpCount - 并发数
|
|
169
|
+
*/
|
|
170
|
+
static async wav2oggMP(ioMap: IOMap, quality = 10, cpCount = 16) {
|
|
171
|
+
await new SList(Object.entries(ioMap))
|
|
172
|
+
.toSStream(cpCount)
|
|
173
|
+
.map(async ([inPath, outPath]) => {
|
|
174
|
+
SLogger.info("SFfmpegTool.wav2oggMP 正在处理:" + outPath);
|
|
175
|
+
await SFfmpegTool.wav2ogg(inPath, outPath, quality);
|
|
176
|
+
})
|
|
177
|
+
.appendOperations();
|
|
178
|
+
}
|
|
179
|
+
/**flac转ogg多线程
|
|
180
|
+
* @param ioMap - 输入输出路径映射
|
|
181
|
+
* @param quality - 质量
|
|
182
|
+
* @param cpCount - 并发数
|
|
183
|
+
*/
|
|
184
|
+
static async flac2oggMP(
|
|
185
|
+
ioMap: IOMap,
|
|
186
|
+
quality: number = 10,
|
|
187
|
+
cpCount: number = 16
|
|
188
|
+
) {
|
|
189
|
+
await new SList(Object.entries(ioMap))
|
|
190
|
+
.toSStream(cpCount)
|
|
191
|
+
.map(async ([inPath, outPath]) => {
|
|
192
|
+
SLogger.info("SFfmpegTool.flac2oggMP 正在处理:" + outPath);
|
|
193
|
+
await SFfmpegTool.flac2ogg(inPath, outPath, quality);
|
|
194
|
+
})
|
|
195
|
+
.appendOperations();
|
|
196
|
+
}
|
|
197
|
+
/**删除静音多线程
|
|
198
|
+
* @param ioMap - 输入输出路径映射
|
|
199
|
+
* @param threshold - 静音阈值/dB
|
|
200
|
+
* @param silence - 保留静音时长
|
|
201
|
+
*/
|
|
202
|
+
static async trimSilenceMP(
|
|
203
|
+
ioMap: IOMap,
|
|
204
|
+
threshold: number = -50,
|
|
205
|
+
silence: number = 0.2,
|
|
206
|
+
cpCount: number = 16
|
|
207
|
+
) {
|
|
208
|
+
await new SList(Object.entries(ioMap))
|
|
209
|
+
.toSStream(cpCount)
|
|
210
|
+
.map(async ([inPath, outPath]) => {
|
|
211
|
+
SLogger.info("SFfmpegTool.trimSilenceMP 正在处理:" + outPath);
|
|
212
|
+
await SFfmpegTool.trimSilence(inPath, outPath, threshold, silence);
|
|
213
|
+
})
|
|
214
|
+
.appendOperations();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**重采样多线程
|
|
218
|
+
* @param ioMap - 输入输出路径映射
|
|
219
|
+
* @param rate - 采样率
|
|
220
|
+
* @param cpCount - 并发数
|
|
221
|
+
*/
|
|
222
|
+
static async resampleMP(ioMap: IOMap, rate: number = 22050, cpCount: number = 16) {
|
|
223
|
+
await new SList(Object.entries(ioMap))
|
|
224
|
+
.toSStream(cpCount)
|
|
225
|
+
.map(async ([inPath, outPath]) => {
|
|
226
|
+
SLogger.info("SFfmpegTool.resampleMP 正在处理:" + outPath);
|
|
227
|
+
await SFfmpegTool.resample(inPath, outPath, rate);
|
|
228
|
+
})
|
|
229
|
+
.appendOperations();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
SFfmpegTool.init();
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
/**多线程任务分割器
|
|
236
|
+
* @param iomap - 输入输出路径映射
|
|
237
|
+
* @param cpCount - 并发数
|
|
238
|
+
*/
|
|
239
|
+
function MPClip(iomap: IOMap, cpCount: number = 16) {
|
|
240
|
+
let cpList: Array<IOMap> = [];
|
|
241
|
+
for (let i = 0; i < cpCount; i++) cpList.push({});
|
|
242
|
+
let cpCounter = 0;
|
|
243
|
+
for (let key in iomap) {
|
|
244
|
+
let cpIndex = cpCounter % cpCount;
|
|
245
|
+
cpCounter++;
|
|
246
|
+
cpList[cpIndex][key] = iomap[key];
|
|
247
|
+
}
|
|
248
|
+
return cpList;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
type SFfmpegCmd = {
|
|
252
|
+
name: string;
|
|
253
|
+
opt: string | null;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/**ffmpeg流
|
|
257
|
+
*/
|
|
258
|
+
class SFfmpegStream {
|
|
259
|
+
iomap;
|
|
260
|
+
cmdList: Array<SFfmpegCmd> = [];
|
|
261
|
+
constructor(iomap: IOMap) {
|
|
262
|
+
this.iomap = iomap;
|
|
263
|
+
}
|
|
264
|
+
async save() {}
|
|
265
|
+
|
|
266
|
+
//执行函数
|
|
267
|
+
private async cmdAreverse() {}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export default SFfmpegTool;
|
|
271
|
+
export { SFfmpegTool };
|