ffmpeg-fore
v1.0.19-4
Published
ffmpeg+canvas
Readme
音视频编辑工具
npm install ffmpeg-fore
or
pnpm install ffmpeg-fore
集成: main.ts
...
import FF from 'ffmpeg-fore';
corePath: corePath地址,默认为空在线引入
corePath: workerPath,默认为空在线引入
corePath: wasmPath,默认为空在线引入
const ff = new FF(
corePath: '',
workerPath: '',
wasmPath: '',
);
或者:const ff = new FF((res: any) => {
const { ratio, time } = res;
});
const app = createApp(App);
app.config.globalProperties.$ff = ff;
...
本地https环境配置:vite.config.ts
server: ...
host: '0.0.0.0'
https: {
key: resolve(__dirname, 'key.pem'),
cert: resolve(__dirname, 'cert.pem'),
},
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp'
}
使用(demo.vue):
import { getCurrentInstance } from 'vue'
const { appContext } = getCurrentInstance()!;
const ff = appContext.config.globalProperties.$ff;
import { SPACE } from 'ffmpeg-fore';*来源文件:已存入虚拟缓存的文件/要操作的文件,默认名称: source
*无来源文件:ff.cache存入虚拟缓存 urls: 在线文件无需填写name,本地文件必填name
SPACE:
enum SOURCE {
LOCAL = 'local',
NETWORK = 'network',
}
interface RESULT {
startTime?: number | string;
endTime?: number | string;
path?: string;
url?: string;
subtitles?: SPACE.RESULT[];
text?: string;
}上传视频 / 音频 / 图片 至虚拟缓存(来源文件):
/*
* @params {string} url required 文件地址
* @params {string} name 文件名称 默认source.mp4
* @params {boolean} status 是否加载插件,默认false,单独调用true
*
* @returns {string} 文件url
* */
el-upload: file => { url: file.url, name: file.name }
const url: string = await ff.cache({
url: file.url,
name: `source.${ff.format(file.name)}`,
status: true,
})文件下载:
/*
* @params {string} url required 文件地址
* @params {string} name 文件下载名称
* @params {string} status 下载后是否清除缓存 默认 false
*
* @returns {boolean} 下载状态提示
* */
const status: boolean = await ff.download({
url: '',
name: 'download',
status: false
});获取文件格式:
/*
* @params {string} required 文件地址
*
* @returns {string} 文件格式
* */
const format: string = await ff.format('');视频剪辑:
/*
* @params {string} startTime required 开始时间 '00:00:00'
* @params {string} endTime required 开始时间 '00:00:00'
* @params {string} outputName 剪辑后名称(格式:mp4) 默认名称clip
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {string} 文件url
* */
const url: string = await ff.videoClip({
startTime: '00:00:00',
endTime: '00:00:01',
name: '',
url: '',
type: SPACE.SOURCE.NETWORK,
outputName: 'clip.mp4',
});音频剪辑:
/*
* @params {string} startTime required 开始时间 '00:00:00'
* @params {string} endTime required 开始时间 '00:00:00'
* @params {string} outputName 剪辑后名称(格式:mp3) 默认名称clip
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {string} 文件url
* */
const url: string = await ff.audioClip({
startTime: '00:00:00',
endTime: '00:00:01',
name: '',
url: '',
type: SPACE.SOURCE.NETWORK,
outputName: 'clip.mp3',
});视频合成:
/*
* @params {string} type 默认本地文件local,在线文件:network
* @params {string} outputName 合成名称(格式:mp4) 默认名称video-merge.mp4
* @params {string} sws 视频质量,默认bicubic
* @params sws = 'bicubic' :平衡速度与质量
* @params sws = 'lanczos' :高质量,但较慢
* @params sws = 'neighbor' :最快,低质量
* @params {number} width 合成视频宽度 默认0:对比最宽视频
* @params {number} height 合成视频高度 默认0:对比最高视频
* @params width+height同时输入>0有效,单一无效
* @params {<<string>object>[]} urls required
* @params {<string>object} type='local' url 文件地址
* @params {<string>object} type='local' name 文件名称 例:test.mp4
* @params {<string>object} type='network' url 文件在线地址
*
* @returns {string} 文件url
* */
type === 'local':
el-upload: file => { url: file.url, name: file.name }
urls: [{ url: file.url, name: file.name }]
type === 'network':
urls: [ {url: '视频在线地址'} , {url: '视频在线地址'}]
const url: string = await ff.videoMerge({
urls: [],
type: SPACE.SOURCE.LOCAL,
})视频添加字幕:
/*
* @params {<<string>object>[]} drawText required
* @params {<string>object} text 字幕内容
* @params {<string>object} fontSize 字体大小,
* @params {<string>object} fontColor 字体颜色,
* @params {<string>object} startTime 开始时间,
* @params {<string>object} endTime 结束时间,
* @params {<string>object} timeType 默认:number,可选string,
* timeType='number': startTime/endTime类型number,例:startTime = 0
* timeType='string': startTime/endTime类型string,例:startTime = '00:00:00'
* @params {<string>object} position 字幕位置,默认bottom, top / center,
* @params {string} fontUrl 字幕字体在线地址或上传的地址
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {string} 文件url
* */
const url: string = await ff.videoAddSubtitles({
fontUrl: '',
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
drawText: [
{ text: 'First Text',fontSize: 24, fontColor: 'yellow', startTime: 0, endTime: 5 },
],
})视频帧:
/*
* @params {string} source 来源文件 默认:source.mp4
* @params {string} dir 虚拟缓存目录 默认:frame
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {<string>[]} 帧地址,格式:jpeg
* */
const urls: string[] = await ff.frames({
url: '',
type: SPACE.SOURCE.NETWORK,
})音频比特率图:
/*
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {<string>[]} 比特率图地址
* */
const urls: string[] = await ff.bitRate({
url: '',
type: SPACE.SOURCE.NETWORK,
})初始化画布轨道(单轨道):
/*
* @params {<string>[]} trackList 帧图片列表
* @params {HTMLDivElement} container 容器DIV
* @params {boolean} baseLineStatus 默认false,基准线,true:显示,false:不显示
* @params {<object>[]} Fn 事件
* @params {<string>object} type click: 点击事件,scroll: 滑动事件
* @params {<string>object} time type=click 点击的时间节点
* @params {<string>object} path type=click 点击的帧地址
* @params {<string>object} time type=scroll 滑动到基准线的时间节点
* @params {<string>object} path type=scroll 滑动到基准线的帧地址
*
* */
const trackList: string[] = await ff.frames();
ff.initFrame({
trackList,
container: container.value,
Fn: (data: any) => {
const { path, time, index, type } = data;
// TODO OTHER THINGS
},
});轨道剪辑(单轨道):
/*
* @params {boolean} status
* @params status = true 开启
* @params status = false 关闭
* */
await ff.clipFrame({
status: boolean,
});轨道剪辑确认(单轨道):
/*
* @returns {<number | string>object} res
* @returns {number} code 0:成功,成功后自动关闭剪辑轨道
* @returns {string} startTime 开始时间
* @returns {string} endTime 结束时间
* @returns {string} msg 提示信息
* */
const res: SPACE.FRAME = await ff.confirmFrame();
const { startTime, endTime, code, msg } = res;
... TODO OTHER THINGS ...获取视频信息:
/*
* @params {string} 视频地址
*
* @returns {<number | string>object}
* @returns {number} width 视频宽
* @returns {number} height 视频高
* @returns {number} duration 视频时常/秒, 例: 9.05s
* @returns {string} durationTime 视频时常/时间,例:'00:00:09'
* */
const { width, height, duration, durationTime } = await ff.getVideoInfo('')获取音频信息:
/*
* @params {string} 音频地址
*
* @returns {<number | string>object}
* @returns {number} duration 视频时常/秒, 例: 9.05s
* @returns {string} durationTime 视频时常/时间,例:'00:00:09'
* @returns {string} bitrate 比特率(kbps)
* @returns {string} sampleRate 采样率(Hz)
* @returns {string} channels 声道数
* @returns {string} codec 编码格式(如 mp3、flac)
* */
const { duration, bitrate, sampleRate } = await ff.getAudioInfo('')视频截图:
/*
* @params {string} time required 截图时间 '00:00:00'
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {string} 文件url
* */
const url: string = await ff.videoCapture({
time: '00:00:00',
name: '',
url: '',
type: SPACE.SOURCE.NETWORK,
})音频剥离:
/*
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {string} 文件url,格式:mp3
* */
const url: string = await ff.audioPeel({
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
})视频剥离:
/*
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {string} 文件url,无声
* */
const url: string = await ff.videoPeel({
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
})音视频合成:
/*
* @params {string} url required 音频在线文件地址
* @params {string} name 音频缓存名称
* @params {string} source 来源文件,默认source.mp4
* @params {string} outputName 合成名称,默认名称av-merge.mp4
* @params {string} type 分类 默认:network
* @params type='local' required audioUrl 音频文件地址 el-upload -> file.url
* @params type='local' audioName 音频文件名称 el-upload -> file.name
* @params type='local' required videoUrl 视频文件地址 el-upload -> file.url
* @params type='local' videoName 视频文件名称 el-upload -> file.name
* @params type='network' required audioUrl 音频文件在线地址
* @params type='network' audioName 默认为空,无需填写
* @params type='network' required videoUrl 视频文件在线地址
* @params type='network' videoName 默认为空,无需填写
*
* @returns {string} 视频url,格式:mp4
* */
const url: string = await ff.avMerge({
audioUrl: '',
audioName: 'av-audio.mp3',
videoUrl: '',
videoName: 'av-video.mp4',
type: SPACE.SOURCE.NETWORK,
outputName: 'av-merge.mp4',
})音频合成:
/*
* @params {string} outputName 合成名称,默认audio-merge.mp3
* @params {string} type 默认本地文件local,在线文件:network
* @params {<any>[]} urls required
* @params {<string>object} type='local' url 文件地址
* @params {<string>object} type='local' name 文件名称 例:test.mp3
* @params {<string>object} type='network' url 文件在线地址
*
* @returns {string} 音频url,格式:mp3
* */
type === 'local':
el-upload: file => { url: file.url, name: file.name }
urls: [{ url: file.url, name: file.name }]
type === 'network':
urls: [{ url: '音频在线地址' }]
const url: string = await ff.audioMerge({
urls: [],
outputName: 'audio-merge.mp3',
type: SPACE.SOURCE.LOCAL,
})图生视频:
/*
* @params {number} seconds 每张图片展示时间 默认:1s
* @params {string} type 默认本地文件local,在线文件:network
* @params {<any>[]} urls required
* @params {<string>object} type='local' url 文件地址
* @params {<string>object} type='local' name 文件名称 例:test.jpg
* @params {<string>object} type='network' url 文件在线地址
*
* @returns {string} 视频url,格式:mp4
* */
type === 'local':
el-upload: file => { url: file.url, name: file.name }
urls: [{ url: file.url, name: file.name }]
type === 'network':
urls: [{ url: '图片在线地址'}]
const url: string = await ff.convertImageToVideo({
urls: [],
seconds: 1,
type: SPACE.SOURCE.LOCAL
})视频添加水印图:
/*
* @params {string} source 来源文件 默认:source.mp4
* @params {string} outputName 合成名称,默认watermark.mp4
* @params {string} position 水印位置,默认TopLeft:左上角
* @params {string} position='TopLeft' 左上角
* @params {string} position='TopRight' 右上角
* @params {string} position='BottomLeft' 左下角
* @params {string} position='BottomRight' 右下角
* @params {string} type 默认在线文件:network,本地文件:local
* @params type='local' watermark/url 水印图/视频地址 el-upload -> file.url
* @params type='local' watermarkName/name 水印图/视频名称 el-upload -> file.name
* @params type='network' watermark 文件在线地址
* @params type='network' watermarkName 默认为空
* Required:watermark、url
*
* @returns {string} 视频url,格式:源文件格式
* */
const url: string = await ff.videoWatermark({
url: '',
name: '',
watermark: 'source.jpg',
watermarkName: 'source.jpg',
position: 'TopLeft',
type: SPACE.SOURCE.LOCAL
});图片添加水印图:
/*
* @params {string} source 来源文件 默认:source.mp4
* @params {string} outputName 合成名称,默认watermark.jpeg
* @params {string} position 水印位置,默认TopLeft:左上角
* @params {string} position='TopLeft' 左上角
* @params {string} position='TopRight' 右上角
* @params {string} position='BottomLeft' 左下角
* @params {string} position='BottomRight' 右下角
* @params {string} type 默认在线文件:network,本地文件:local
* @params type='local' watermark/url 水印图/图片地址 el-upload -> file.url
* @params type='local' watermarkName/name 水印图/图片名称 el-upload -> file.name
* @params type='network' watermark 文件在线地址
* @params type='network' watermarkName 默认为空
* Required:watermark、url
*
* @returns {string} 图片url
* */
const url: string = await ff.imageWatermark({
url: '',
name: '',
watermark: 'source.jpg',
watermarkName: 'source.jpg',
position: 'TopLeft',
type: SPACE.SOURCE.LOCAL,
});时间间隔拆分视频:
/*
* @params {number | string} time 时间间隔/秒 默认:10,
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {<<string>object>[]} res
* @returns {string} url 视频地址
* @returns {string} startTime 开始时间
* @returns {string} endTime 结束时间
* */
const res: SPACE.RESULT[] = await ff.videoCut({
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
time: 10,
});转场拆分视频:
/*
* @params {string} scene 场景变化阈值 默认:0.5
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {<<string>object>[]} res
* @returns {string} url 视频地址
* @returns {string} startTime 开始时间
* @returns {string} endTime 结束时间
* */
const res: SPACE.RESULT[] = await ff.videoTransition({
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
scene: '0.5',
});声音拆分视频:
/*
* @params {number} volume 音量阈值,默认50 默认:1~100
* @params {number} interval 静音持续时长/秒 默认:1
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {<<string>object>[]} res
* @returns {string} url 视频地址
* @returns {string} startTime 开始时间
* @returns {string} endTime 结束时间
* */
const res: SPACE.RESULT[] = await ff.videoSilence({
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
volume: 50,
interval: 1,
});视频提取字幕(OCR字幕识别不精准):
/*
* @params {string} keywords 关键字 默认:空
* @params {string} type 分类 默认:network
* @params type='local' required url 文件地址 el-upload -> file.url
* @params type='local' name 文件名称 el-upload -> file.name
* @params type='network' required url 文件在线地址
* @params type='network' name 默认为空,无需填写
*
* @returns {<<string>object>[]} res 秒级
* keywords !== ''时:
* @returns {string} startTime 开始时间
* @returns {string} endTime 持续结束时间
* @returns {string} url 视频地址
* @returns {<<string>object>[]} subtitles 字幕组,内容如下
* @returns {string} startTime 开始时间
* @returns {string} endTime 结束时间
* @returns {string} text 字幕内容
* keywords === ''时:
* @returns {string} url 视频地址
* @returns {string} startTime 开始时间
* @returns {string} endTime 结束时间
* @returns {string} text 字幕内容
* */
const res: SPACE.RESULT[] = await ff.videoExtractSubtitles({
url: '',
name: '',
type: SPACE.SOURCE.NETWORK,
keywords: '',
});退出销毁:
await ff.exit();