@deepfish-ai/ffmpeg7-media-tools 1.0.1 → 1.0.3
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 +21 -5
- package/README_CN.md +21 -5
- package/ffmpeg-functions.js +55 -55
- package/index.js +5 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @deepfish-ai/ffmpeg7-media-tools
|
|
2
2
|
|
|
3
|
-
English | [中文](
|
|
3
|
+
English | [中文](https://github.com/qq306863030/deepfish-extensions/blob/master/deepfish-ffmpeg7-media-tools/README_CN.md)
|
|
4
4
|
|
|
5
5
|
A comprehensive FFmpeg 7 based audio and video processing toolkit with 24 media processing functions, supporting video format conversion, audio extraction, video editing, and other common media processing tasks.
|
|
6
6
|
|
|
@@ -14,22 +14,37 @@ A comprehensive FFmpeg 7 based audio and video processing toolkit with 24 media
|
|
|
14
14
|
|
|
15
15
|
## 🚀 Quick Start
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Follow these three steps to install and use this extension:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
### Step 1: Install DeepFish AI
|
|
20
|
+
First, install the global deepfish-ai library (if not already installed):
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
npm install deepfish-ai -g
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
###
|
|
26
|
-
|
|
26
|
+
### Step 2: Install This Extension
|
|
27
27
|
Install this package globally:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
npm install @deepfish-ai/ffmpeg7-media-tools -g
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
### Step 3: Use in DeepFish AI
|
|
34
|
+
Once installed, you can use the extension functions in DeepFish AI by simply asking the AI to perform media processing tasks. For example:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ai convert video.mp4 to avi format
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
or
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
ai extract audio from video.mp4
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The AI will automatically use the appropriate FFmpeg functions from this extension.
|
|
47
|
+
|
|
33
48
|
### FFmpeg Installation
|
|
34
49
|
|
|
35
50
|
This toolkit requires FFmpeg 7 or higher. Please install FFmpeg 7 before using:
|
|
@@ -144,6 +159,7 @@ MIT License - See LICENSE file
|
|
|
144
159
|
## 📞 Support
|
|
145
160
|
|
|
146
161
|
For questions or suggestions, please:
|
|
162
|
+
|
|
147
163
|
1. Check the Troubleshooting section in this documentation
|
|
148
164
|
2. Submit a GitHub Issue
|
|
149
165
|
3. Contact the maintenance team
|
package/README_CN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @deepfish-ai/ffmpeg7-media-tools
|
|
2
2
|
|
|
3
|
-
[English](
|
|
3
|
+
[English](https://github.com/qq306863030/deepfish-extensions/blob/master/deepfish-ffmpeg7-media-tools/README.md) | 中文
|
|
4
4
|
|
|
5
5
|
基于FFmpeg 7的音频视频处理工具函数集,包含24个媒体处理函数,支持视频格式转换、音频提取、视频编辑等常见媒体处理任务。
|
|
6
6
|
|
|
@@ -14,22 +14,37 @@
|
|
|
14
14
|
|
|
15
15
|
## 🚀 快速开始
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
按照以下三个步骤安装和使用此扩展:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
### 步骤1: 安装DeepFish AI
|
|
20
|
+
首先,安装全局deepfish-ai库(如果尚未安装):
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
npm install deepfish-ai -g
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
###
|
|
26
|
-
|
|
26
|
+
### 步骤2: 安装此扩展
|
|
27
27
|
全局安装本包:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
npm install @deepfish-ai/ffmpeg7-media-tools -g
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
### 步骤3: 在DeepFish AI中使用
|
|
34
|
+
安装完成后,您可以在DeepFish AI中通过简单的命令使用扩展功能。例如:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ai 将video.mp4转换为avi格式
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
或
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
ai 从video.mp4中提取音频
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
AI会自动使用此扩展中的相应FFmpeg函数。
|
|
47
|
+
|
|
33
48
|
### FFmpeg安装
|
|
34
49
|
|
|
35
50
|
本工具集需要FFmpeg 7或更高版本。使用前请先安装FFmpeg 7:
|
|
@@ -144,6 +159,7 @@ MIT License - 详见LICENSE文件
|
|
|
144
159
|
## 📞 支持
|
|
145
160
|
|
|
146
161
|
如有问题或建议,请:
|
|
162
|
+
|
|
147
163
|
1. 查看本文档的故障排除部分
|
|
148
164
|
2. 提交GitHub Issue
|
|
149
165
|
3. 联系维护团队
|
package/ffmpeg-functions.js
CHANGED
|
@@ -22,7 +22,7 @@ const checkFfmpeg = async () => {
|
|
|
22
22
|
command = 'which ffmpeg';
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
await this.Tools.executeCommand(command);
|
|
25
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
26
26
|
return { installed: true, error: null };
|
|
27
27
|
} catch (error) {
|
|
28
28
|
return {
|
|
@@ -38,7 +38,7 @@ const checkFfmpeg = async () => {
|
|
|
38
38
|
*/
|
|
39
39
|
const getFfmpegVersion = async () => {
|
|
40
40
|
try {
|
|
41
|
-
const result = await this.Tools.executeCommand('ffmpeg -version');
|
|
41
|
+
const result = await this.aiCl.Tools.executeCommand('ffmpeg -version');
|
|
42
42
|
// 从输出中提取版本号
|
|
43
43
|
const versionMatch = result.match(/ffmpeg version (\S+)/);
|
|
44
44
|
const version = versionMatch ? versionMatch[1] : '未知版本';
|
|
@@ -132,7 +132,7 @@ functions.ffmpeg_convertVideoFormat = async (params) => {
|
|
|
132
132
|
finalOutputPath = finalOutputPath.replace(/\.[^/.]+$/, "") + `.${format}`;
|
|
133
133
|
}
|
|
134
134
|
const command = `ffmpeg -i "${inputPath}" ${quality} "${finalOutputPath}"`;
|
|
135
|
-
await this.Tools.executeCommand(command);
|
|
135
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
136
136
|
return {
|
|
137
137
|
success: true,
|
|
138
138
|
message: `视频格式转换完成: ${finalOutputPath}`,
|
|
@@ -159,7 +159,7 @@ functions.ffmpeg_extractAudioFromVideo = async (params) => {
|
|
|
159
159
|
finalAudioPath = finalAudioPath.replace(/\.[^/.]+$/, "") + `.${audioFormat}`;
|
|
160
160
|
}
|
|
161
161
|
const command = `ffmpeg -i "${videoPath}" -q:a 0 -map a "${finalAudioPath}"`;
|
|
162
|
-
await this.Tools.executeCommand(command);
|
|
162
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
163
163
|
return {
|
|
164
164
|
success: true,
|
|
165
165
|
message: `音频提取完成: ${finalAudioPath}`,
|
|
@@ -187,7 +187,7 @@ functions.ffmpeg_resizeVideo = async (params) => {
|
|
|
187
187
|
scaleFilter = `scale=${width}:${height}`;
|
|
188
188
|
}
|
|
189
189
|
const command = `ffmpeg -i "${inputPath}" -vf "${scaleFilter}" -c:a copy "${outputPath}"`;
|
|
190
|
-
await this.Tools.executeCommand(command);
|
|
190
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
191
191
|
return {
|
|
192
192
|
success: true,
|
|
193
193
|
message: `视频尺寸调整完成: ${width}x${height}`,
|
|
@@ -209,7 +209,7 @@ functions.ffmpeg_trimVideo = async (params) => {
|
|
|
209
209
|
throw new Error(`FFmpeg检查失败: ${checkResult.message}`);
|
|
210
210
|
}
|
|
211
211
|
const command = `ffmpeg -i "${inputPath}" -ss ${startTime} -t ${duration} -c copy "${outputPath}"`;
|
|
212
|
-
await this.Tools.executeCommand(command);
|
|
212
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
213
213
|
return {
|
|
214
214
|
success: true,
|
|
215
215
|
message: `视频剪切完成: 从 ${startTime} 开始,持续 ${duration}`,
|
|
@@ -237,16 +237,16 @@ functions.ffmpeg_mergeVideos = async (params) => {
|
|
|
237
237
|
videoPaths.forEach(path => {
|
|
238
238
|
listContent += `file '${path}'\n`;
|
|
239
239
|
});
|
|
240
|
-
await this.Tools.createFile(listFilePath, listContent);
|
|
240
|
+
await this.aiCl.Tools.createFile(listFilePath, listContent);
|
|
241
241
|
const command = `ffmpeg -f concat -safe 0 -i "${listFilePath}" -c copy "${outputPath}"`;
|
|
242
|
-
await this.Tools.executeCommand(command);
|
|
242
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
243
243
|
// 删除临时文件
|
|
244
|
-
await this.Tools.deleteFile(listFilePath);
|
|
244
|
+
await this.aiCl.Tools.deleteFile(listFilePath);
|
|
245
245
|
} else if (method === 'overlay') {
|
|
246
246
|
// 简单叠加示例(实际应用中可能需要更复杂的处理)
|
|
247
247
|
if (videoPaths.length === 2) {
|
|
248
248
|
const command = `ffmpeg -i "${videoPaths[0]}" -i "${videoPaths[1]}" -filter_complex "[0:v][1:v]overlay=10:10" "${outputPath}"`;
|
|
249
|
-
await this.Tools.executeCommand(command);
|
|
249
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
250
250
|
} else {
|
|
251
251
|
throw new Error('叠加模式目前仅支持两个视频');
|
|
252
252
|
}
|
|
@@ -283,7 +283,7 @@ functions.ffmpeg_convertAudioFormat = async (params) => {
|
|
|
283
283
|
bitrateOption = `-b:a ${bitrate}`;
|
|
284
284
|
}
|
|
285
285
|
const command = `ffmpeg -i "${inputPath}" ${bitrateOption} "${finalOutputPath}"`;
|
|
286
|
-
await this.Tools.executeCommand(command);
|
|
286
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
287
287
|
return {
|
|
288
288
|
success: true,
|
|
289
289
|
message: `音频格式转换完成: ${format}`,
|
|
@@ -305,7 +305,7 @@ functions.ffmpeg_adjustAudioVolume = async (params) => {
|
|
|
305
305
|
throw new Error(`FFmpeg检查失败: ${checkResult.message}`);
|
|
306
306
|
}
|
|
307
307
|
const command = `ffmpeg -i "${inputPath}" -filter:a "volume=${volume}" "${outputPath}"`;
|
|
308
|
-
await this.Tools.executeCommand(command);
|
|
308
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
309
309
|
return {
|
|
310
310
|
success: true,
|
|
311
311
|
message: `音频音量调整完成: ${volume}倍`,
|
|
@@ -336,7 +336,7 @@ functions.ffmpeg_extractVideoThumbnail = async (params) => {
|
|
|
336
336
|
sizeOption = `-s ${size}`;
|
|
337
337
|
}
|
|
338
338
|
const command = `ffmpeg -i "${videoPath}" -ss ${time} -vframes 1 ${sizeOption} "${finalOutputPath}"`;
|
|
339
|
-
await this.Tools.executeCommand(command);
|
|
339
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
340
340
|
return {
|
|
341
341
|
success: true,
|
|
342
342
|
message: `视频缩略图提取完成: ${time}`,
|
|
@@ -359,7 +359,7 @@ functions.ffmpeg_getMediaInfo = async (params) => {
|
|
|
359
359
|
}
|
|
360
360
|
try {
|
|
361
361
|
const command = `ffprobe -v quiet -print_format json -show_format -show_streams "${mediaPath}"`;
|
|
362
|
-
const result = await this.Tools.executeCommand(command);
|
|
362
|
+
const result = await this.aiCl.Tools.executeCommand(command);
|
|
363
363
|
// 解析JSON结果
|
|
364
364
|
const info = JSON.parse(result);
|
|
365
365
|
// 提取关键信息
|
|
@@ -395,7 +395,7 @@ functions.ffmpeg_getMediaInfo = async (params) => {
|
|
|
395
395
|
// 如果ffprobe失败,尝试使用ffmpeg获取基本信息
|
|
396
396
|
try {
|
|
397
397
|
const fallbackCommand = `ffmpeg -i "${mediaPath}"`;
|
|
398
|
-
await this.Tools.executeCommand(fallbackCommand);
|
|
398
|
+
await this.aiCl.Tools.executeCommand(fallbackCommand);
|
|
399
399
|
} catch (ffmpegError) {
|
|
400
400
|
// 从错误信息中提取信息
|
|
401
401
|
const errorStr = ffmpegError.toString();
|
|
@@ -468,7 +468,7 @@ functions.ffmpeg_addWatermark = async (params) => {
|
|
|
468
468
|
// 添加输出路径
|
|
469
469
|
command += ` "${outputPath}"`;
|
|
470
470
|
try {
|
|
471
|
-
const result = await this.Tools.executeCommand(command);
|
|
471
|
+
const result = await this.aiCl.Tools.executeCommand(command);
|
|
472
472
|
return {
|
|
473
473
|
success: true,
|
|
474
474
|
message: `水印添加完成: ${outputPath}`,
|
|
@@ -502,7 +502,7 @@ functions.ffmpeg_adjustBitrate = async (params) => {
|
|
|
502
502
|
// 添加输出路径
|
|
503
503
|
command += ` "${outputPath}"`;
|
|
504
504
|
try {
|
|
505
|
-
const result = await this.Tools.executeCommand(command);
|
|
505
|
+
const result = await this.aiCl.Tools.executeCommand(command);
|
|
506
506
|
return {
|
|
507
507
|
success: true,
|
|
508
508
|
message: `视频比特率调整完成: ${outputPath}`,
|
|
@@ -535,7 +535,7 @@ functions.ffmpeg_mergeVideoAudio = async (params) => {
|
|
|
535
535
|
command = `ffmpeg -i "${videoPath}" -i "${audioPath}" -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 "${outputPath}"`;
|
|
536
536
|
}
|
|
537
537
|
try {
|
|
538
|
-
const result = await this.Tools.executeCommand(command);
|
|
538
|
+
const result = await this.aiCl.Tools.executeCommand(command);
|
|
539
539
|
return {
|
|
540
540
|
success: true,
|
|
541
541
|
message: `视频音频合并完成: ${outputPath}`,
|
|
@@ -582,7 +582,7 @@ functions.ffmpeg_videoToGif = async (params) => {
|
|
|
582
582
|
command += ` "${outputPath}"`;
|
|
583
583
|
|
|
584
584
|
// 执行命令
|
|
585
|
-
await this.Tools.executeCommand(command);
|
|
585
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
586
586
|
|
|
587
587
|
return {
|
|
588
588
|
success: true,
|
|
@@ -627,7 +627,7 @@ functions.ffmpeg_cropVideo = async (params) => {
|
|
|
627
627
|
const command = `ffmpeg -i "${videoPath}" -vf "crop=${width}:${height}:${x}:${y}" "${outputPath}"`;
|
|
628
628
|
|
|
629
629
|
// 执行命令
|
|
630
|
-
await this.Tools.executeCommand(command);
|
|
630
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
631
631
|
|
|
632
632
|
return {
|
|
633
633
|
success: true,
|
|
@@ -673,7 +673,7 @@ functions.ffmpeg_rotateVideo = async (params) => {
|
|
|
673
673
|
const command = `ffmpeg -i "${videoPath}" -vf "${filter}" "${outputPath}"`;
|
|
674
674
|
|
|
675
675
|
// 执行命令
|
|
676
|
-
await this.Tools.executeCommand(command);
|
|
676
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
677
677
|
|
|
678
678
|
return {
|
|
679
679
|
success: true,
|
|
@@ -712,7 +712,7 @@ functions.ffmpeg_changeVideoSpeed = async (params) => {
|
|
|
712
712
|
const command = `ffmpeg -i "${videoPath}" -filter_complex "[0:v]setpts=${1/speed}*PTS[v];[0:a]atempo=${speed}[a]" -map "[v]" -map "[a]" "${outputPath}"`;
|
|
713
713
|
|
|
714
714
|
// 执行命令
|
|
715
|
-
await this.Tools.executeCommand(command);
|
|
715
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
716
716
|
|
|
717
717
|
return {
|
|
718
718
|
success: true,
|
|
@@ -755,7 +755,7 @@ functions.ffmpeg_addSubtitles = async (params) => {
|
|
|
755
755
|
command += ` -c:a copy "${outputPath}"`;
|
|
756
756
|
|
|
757
757
|
// 执行命令
|
|
758
|
-
await this.Tools.executeCommand(command);
|
|
758
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
759
759
|
|
|
760
760
|
return {
|
|
761
761
|
success: true,
|
|
@@ -800,7 +800,7 @@ functions.ffmpeg_extractVideoFrames = async (params) => {
|
|
|
800
800
|
command += ` "${outputDir}/frame_%04d.${format || 'jpg'}"`;
|
|
801
801
|
|
|
802
802
|
// 执行命令
|
|
803
|
-
await this.Tools.executeCommand(command);
|
|
803
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
804
804
|
|
|
805
805
|
return {
|
|
806
806
|
success: true,
|
|
@@ -838,11 +838,11 @@ functions.ffmpeg_concatVideos = async (params) => {
|
|
|
838
838
|
// 创建临时文件列表
|
|
839
839
|
const listPath = `${outputPath}.txt`;
|
|
840
840
|
const listContent = videoPaths.map(path => `file '${path}'`).join('\n');
|
|
841
|
-
await this.Tools.fs.writeFile(listPath, listContent);
|
|
841
|
+
await this.aiCl.Tools.fs.writeFile(listPath, listContent);
|
|
842
842
|
const command = `ffmpeg -f concat -safe 0 -i "${listPath}" -c copy "${outputPath}"`;
|
|
843
843
|
|
|
844
844
|
// 执行命令
|
|
845
|
-
await this.Tools.executeCommand(command);
|
|
845
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
846
846
|
|
|
847
847
|
return {
|
|
848
848
|
success: true,
|
|
@@ -882,7 +882,7 @@ functions.ffmpeg_mixAudios = async (params) => {
|
|
|
882
882
|
const command = `ffmpeg ${inputs} -filter_complex "${mixFilter}" "${outputPath}"`;
|
|
883
883
|
|
|
884
884
|
// 执行命令
|
|
885
|
-
await this.Tools.executeCommand(command);
|
|
885
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
886
886
|
|
|
887
887
|
return {
|
|
888
888
|
success: true,
|
|
@@ -921,7 +921,7 @@ functions.ffmpeg_compressVideo = async (params) => {
|
|
|
921
921
|
const command = `ffmpeg -i "${videoPath}" -c:v libx264 -crf ${crf || 23} -preset ${preset || 'medium'} -c:a copy "${outputPath}"`;
|
|
922
922
|
|
|
923
923
|
// 执行命令
|
|
924
|
-
await this.Tools.executeCommand(command);
|
|
924
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
925
925
|
|
|
926
926
|
return {
|
|
927
927
|
success: true,
|
|
@@ -968,7 +968,7 @@ functions.ffmpeg_addTextOverlay = async (params) => {
|
|
|
968
968
|
const command = `ffmpeg -i "${videoPath}" -vf "${filter}" "${outputPath}"`;
|
|
969
969
|
|
|
970
970
|
// 执行命令
|
|
971
|
-
await this.Tools.executeCommand(command);
|
|
971
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
972
972
|
|
|
973
973
|
return {
|
|
974
974
|
success: true,
|
|
@@ -980,32 +980,32 @@ functions.ffmpeg_addTextOverlay = async (params) => {
|
|
|
980
980
|
throw new Error(`${name.replace('ffmpeg_', '')}失败: ${error.message}`);
|
|
981
981
|
}
|
|
982
982
|
};
|
|
983
|
-
|
|
984
|
-
/**
|
|
985
|
-
* 调整视频音量
|
|
986
|
-
* @param {object} params 参数对象
|
|
987
|
-
* @param {string} params.videoPath 输入视频文件路径
|
|
988
|
-
* @param {string} params.outputPath 输出视频文件路径
|
|
989
|
-
* @param {number} params.volume 音量倍数(如0.5为一半音量,2.0为两倍音量)
|
|
990
|
-
*/
|
|
991
|
-
functions.ffmpeg_adjustVideoVolume = async (params) => {
|
|
992
|
-
const { videoPath, outputPath, volume } = params;
|
|
993
|
-
// 检查ffmpeg安装
|
|
994
|
-
const checkResult = await functions.ffmpeg_checkFfmpegInstallation({ minVersion: '7.0.0' });
|
|
995
|
-
if (!checkResult.installed || !checkResult.versionOk) {
|
|
996
|
-
throw new Error(`FFmpeg检查失败: ${checkResult.message}`);
|
|
997
|
-
}
|
|
998
|
-
// 构建调整视频音量命令
|
|
999
|
-
// 使用-filter:a调整音频,-c:v copy保持视频流不重新编码
|
|
1000
|
-
const command = `ffmpeg -i "${videoPath}" -filter:a "volume=${volume}" -c:v copy "${outputPath}"`;
|
|
1001
|
-
await this.Tools.executeCommand(command);
|
|
1002
|
-
return {
|
|
1003
|
-
success: true,
|
|
1004
|
-
message: `视频音量调整完成: ${volume}倍`,
|
|
1005
|
-
outputPath: outputPath
|
|
1006
|
-
};
|
|
1007
|
-
};
|
|
1008
|
-
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* 调整视频音量
|
|
986
|
+
* @param {object} params 参数对象
|
|
987
|
+
* @param {string} params.videoPath 输入视频文件路径
|
|
988
|
+
* @param {string} params.outputPath 输出视频文件路径
|
|
989
|
+
* @param {number} params.volume 音量倍数(如0.5为一半音量,2.0为两倍音量)
|
|
990
|
+
*/
|
|
991
|
+
functions.ffmpeg_adjustVideoVolume = async (params) => {
|
|
992
|
+
const { videoPath, outputPath, volume } = params;
|
|
993
|
+
// 检查ffmpeg安装
|
|
994
|
+
const checkResult = await functions.ffmpeg_checkFfmpegInstallation({ minVersion: '7.0.0' });
|
|
995
|
+
if (!checkResult.installed || !checkResult.versionOk) {
|
|
996
|
+
throw new Error(`FFmpeg检查失败: ${checkResult.message}`);
|
|
997
|
+
}
|
|
998
|
+
// 构建调整视频音量命令
|
|
999
|
+
// 使用-filter:a调整音频,-c:v copy保持视频流不重新编码
|
|
1000
|
+
const command = `ffmpeg -i "${videoPath}" -filter:a "volume=${volume}" -c:v copy "${outputPath}"`;
|
|
1001
|
+
await this.aiCl.Tools.executeCommand(command);
|
|
1002
|
+
return {
|
|
1003
|
+
success: true,
|
|
1004
|
+
message: `视频音量调整完成: ${volume}倍`,
|
|
1005
|
+
outputPath: outputPath
|
|
1006
|
+
};
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
1009
|
|
|
1010
1010
|
|
|
1011
1011
|
|
package/index.js
CHANGED
|
@@ -6,8 +6,13 @@
|
|
|
6
6
|
const functions = require('./ffmpeg-functions.js');
|
|
7
7
|
const descriptions = require('./ffmpeg-descriptions.js');
|
|
8
8
|
|
|
9
|
+
const name = '@deepfish-ai/ffmpeg7-media-tools';
|
|
10
|
+
const description = 'A DeepFish AI extension tool for FFmpeg 7 media processing, including FFmpeg installation/version checks, video/audio format conversion, video trim/merge/concat/crop/rotate/resize, playback speed and bitrate/volume adjustment, video compression, GIF generation, frame and thumbnail extraction, subtitle and watermark/text overlay, audio extraction/mixing, video-audio muxing, and media metadata inspection.';
|
|
11
|
+
|
|
9
12
|
// 导出
|
|
10
13
|
module.exports = {
|
|
14
|
+
name,
|
|
15
|
+
description,
|
|
11
16
|
descriptions,
|
|
12
17
|
functions
|
|
13
18
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepfish-ai/ffmpeg7-media-tools",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"description": "A DeepFish AI extension tool for comprehensive FFmpeg 7 media processing with 24 audio/video manipulation functions",
|
|
5
6
|
"main": "index.js",
|
|
6
7
|
"scripts": {},
|
|
7
8
|
"keywords": [
|
|
@@ -23,4 +24,4 @@
|
|
|
23
24
|
"url": "https://github.com/qq306863030/deepfish-extensions/issues"
|
|
24
25
|
},
|
|
25
26
|
"homepage": "https://github.com/qq306863030/deepfish-extensions#readme"
|
|
26
|
-
}
|
|
27
|
+
}
|