【新项目开发】vue3+ts+elementPlus+ffmpegjs开发纯web端的视频编辑器

这篇具有很好参考价值的文章主要介绍了【新项目开发】vue3+ts+elementPlus+ffmpegjs开发纯web端的视频编辑器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

新项目开发的流程

当在项目中使用新技术时,我们应该首先进行调研,了解其特点和使用方法。在实现功能时,我们可以采用最简单的方式,而不必过于关注项目的设计和结构。一旦掌握了新技术,我们可以根据其API属性进行代码设计,以便更好地开发。以开发一个纯web端的视频编辑处理器为例,我们打算采用vite、vue3、elementPlus、pinia和ffmpegjs等技术。虽然第一次接触ffmpegjs库可能会感到陌生,但我们需要先了解其API属性,并能够实现所需的功能。在此基础上,我们可以考虑如何将ffmpegjs集成到项目中,并设计好项目架构和代码结构,以便更好地使用和维护。

视频编辑器项目操作介绍:

web视频编辑器

1.功能列表:

  • 上传视频
  • 视频分割
  • 添加字幕文件
  • 文字轨道:自定义时间,文字内容
  • 贴图轨道:自定义时间
  • 预览
  • 导出功能
    2.代码:
    git仓库:https://github.com/huhaibiao/video-edit-demo.git
    3.线上演示vercel url:
    https://video-edit-demo.vercel.app/#/
  1. 项目运行
  • pnpm i安装依赖
  • pnpm dev 项目本地运行
  • pnpm build 项目打包

ffmpegjs是什么

ffmpegjs是一个基于JavaScript的开源库,它提供了一个在浏览器中运行FFmpeg的解决方案。FFmpeg是一个广泛使用的开源跨平台音视频处理工具,可以用于音视频的编解码、转码、剪辑、合并等操作。ffmpegjs库通过将FFmpeg编译为WebAssembly格式,并使用JavaScript封装其API,使得我们可以在浏览器中使用FFmpeg进行音视频处理,而无需安装任何本地软件。ffmpegjs库可以用于开发各种基于Web的音视频应用,如视频编辑器、音视频转换器、在线直播等。

安装ffmpegjs

需要安装 @ffmpeg/ffmpeg @ffmpeg/core 这两个npm包
pnpm install @ffmpeg/ffmpeg @ffmpeg/core

在项目中引入

import { fetchFile, createFFmpeg } from '@ffmpeg/ffmpeg'

项目核心模块

import { fetchFile, createFFmpeg } from '@ffmpeg/ffmpeg'
import { processData, tickCounts } from '../store'
// @ts-ignore
// const { fetchFile, createFFmpeg } = FFmpeg

const ffmpeg = createFFmpeg({
  corePath: '/plugin/ffmpeg-core.js'
})
ffmpeg.load()
ffmpeg.setProgress(progress => {
  processData.value = progress.ratio
})

const videoInfo = {
  duration: '',
  bitRate: ''
}
ffmpeg.setLogger(logs => {
  if (logs.message.includes('Duration')) {
    videoInfo.duration = logs.message.slice(
      logs.message.indexOf('Duration:') + 'Duration: '.length,
      logs.message.indexOf(',')
    )
    videoInfo.bitRate = logs.message.slice(
      logs.message.indexOf('bitrate:') + 'bitrate: '.length
    )
    console.log(videoInfo)
  }
})

let videoName = 'initVideo'
/**ffmpeg导入视频 */
export const initVideo = async (video: Blob) => {
  ffmpeg.FS('writeFile', videoName, await fetchFile(video))
  await ffmpeg.run('-i', videoName)
}

let fontName = 'font1'
/** ffmpeg导入字体 */
export const writeFontFile = async (font: Blob) => {
  ffmpeg.FS('writeFile', fontName, await fetchFile(font))
}

let imageName = 'imageMark'
/**ffmpeg导入贴图 */
export const writeImage = async (image: Blob) => {
  ffmpeg.FS('writeFile', imageName, await fetchFile(image))
}

let subTitle = 'subtitle.srt'
/**ffmpeg导入字幕文件 */
export const writeSubTitle = async (subtitle: Blob) => {
  ffmpeg.FS('writeFile', subTitle, await fetchFile(subtitle))
}

/**通过url获取文件blob数据 */
export const urlGetData = async (fileUrl: string, type = 'video/mp4') => {
  const tmp = 'tmpFile'
  ffmpeg.FS('writeFile', tmp, await fetchFile(fileUrl))
  const outputData = ffmpeg.FS('readFile', tmp)
  return new Blob([outputData.buffer], { type })
}

/** 切分视频 */
export const ffmpegSliceVideo = async (
  fileUrl: string,
  fileName: string,
  middleTime: string
) => {
  ffmpeg.FS('writeFile', fileName, await fetchFile(fileUrl))
  // 将视频分割为两个部分
  const command = `-i ${fileName} -t ${middleTime} -c copy output1.mp4 -ss ${middleTime} -c copy output2.mp4`
  await ffmpeg.run(...command.split(' '))

  const video1 = ffmpeg.FS('readFile', 'output1.mp4')
  const video1Url = URL.createObjectURL(
    new Blob([video1.buffer], { type: 'video/mp4' })
  )
  const video2 = ffmpeg.FS('readFile', 'output2.mp4')
  const video2Url = URL.createObjectURL(
    new Blob([video2.buffer], { type: 'video/mp4' })
  )

  return [video1Url, video2Url]
}

/**给视频添加字幕 */
export const addSubTitle = async (fileUrl: string, fileName: string) => {
  ffmpeg.FS('writeFile', fileName, await fetchFile(fileUrl))
  const cmd = `-i ${fileName} -vf subtitles=${subTitle} output.mp4`

  await ffmpeg.run(...cmd.split(' '))

  const outputData = ffmpeg.FS('readFile', 'output.mp4')

  const outputBlob = new Blob([outputData.buffer], { type: 'video/mp4' })
  return URL.createObjectURL(outputBlob)
}

/** 获取视频的每一秒帧 */
export const gVideoFrame = async (
  fileUrl: string,
  timeArr: number[],
  videoName: string = 'initVideo'
) => {
  const frameDir = videoName
  ffmpeg.FS('writeFile', videoName, await fetchFile(fileUrl))
  ffmpeg.FS('mkdir', frameDir + 'Frame')

  const second = tickCounts.value / timeArr[timeArr.length - 1]
  let cmd = `-i ${videoName} -vf fps=${second} -q:v 5 -s 320x240 -an -preset fast /${frameDir}Frame/%3d.jpeg -hide_banner`
  let args = cmd.split(' ')
  await ffmpeg.run(...args)
  const fileList = ffmpeg.FS('readdir', '/' + frameDir + 'Frame')
  let urls: { url: string }[] = []
  fileList.forEach(v => {
    if (v !== '.' && v !== '..') {
      const path = frameDir + 'Frame' + '/' + v
      const img = ffmpeg.FS('readFile', path)
      let url = URL.createObjectURL(
        new Blob([img.buffer], { type: 'image/jpeg' })
      )
      urls.push({
        url
      })
    }
  })
  return urls
}

/** 给视频添加文字 */
export const addText = async (
  fileUrl: string,
  videoName: string = 'initVideo',
  text: string = 'hello',
  startT: number = 5,
  endT: number = 7
) => {
  ffmpeg.FS('writeFile', videoName, await fetchFile(fileUrl))
  const cmd = `-re -i ${videoName} -vf`
  const textT =
    `drawtext=fontfile=font1:text=${text}` +
    `:fontcolor=white:fontsize=80:x=100:y=10:box=1:boxcolor=#0000007d:enable='between(t,${startT},${endT})'`
  let args = cmd.split(' ')
  await ffmpeg.run(...args, textT, 'outfile.mp4')
  const data = ffmpeg.FS('readFile', 'outfile.mp4')
  return URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }))
}

/** 给视频添加贴图 */
export const addImage = async (
  fileUrl: string,
  videoName: string = 'initVideo',
  startT: number = 5,
  endT: number = 7
) => {
  ffmpeg.FS('writeFile', videoName, await fetchFile(fileUrl))
  const cmd = `-i ${videoName} -i ${imageName} -filter_complex overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2:enable='between(t,${startT},${endT})' outfile.mp4`
  let args = cmd.split(' ')
  await ffmpeg.run(...args, '-hide_banner')
  const data = ffmpeg.FS('readFile', 'outfile.mp4')
  return URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }))
}

/** 获取视频的第一帧图片 */
export const getFirstFrame = async (
  fileUrl: string,
  fileName: string,
  initTime = '00:00:00.001'
) => {
  ffmpeg.FS('writeFile', fileName, await fetchFile(fileUrl))
  console.log('视频的第一帧图片')
  await ffmpeg.run(
    '-hwaccel',
    'auto',
    '-i',
    fileName,
    '-ss',
    initTime,
    '-vframes',
    '1',
    '-s',
    '640x480',
    '-an',
    '-threads',
    '4',
    '-preset',
    'fast',
    'output.jpg'
  )
  const data = ffmpeg.FS('readFile', 'output.jpg')
  const url = URL.createObjectURL(
    new Blob([data.buffer], { type: 'image/jpeg' })
  )
  return {
    url,
    videoInfo: JSON.stringify(videoInfo)
  }
}

/**导出视频,降帧 */
export const videoLower = async (fileUrl: string, fileName: string) => {
  ffmpeg.FS('writeFile', fileName, await fetchFile(fileUrl))
  const cmd = `-i ${fileName} -b:v 2000k -q:v 2 -r 24 -s 1240x960 output.mp4`
  let args = cmd.split(' ')
  await ffmpeg.run(...args)
  const data = ffmpeg.FS('readFile', 'output.mp4')
  const url = URL.createObjectURL(
    new Blob([data.buffer], { type: 'video/mp4' })
  )
  return url
}

项目常见的问题:

1、shareArrayBuffer问题,shareArrayBuffer not defined
给服务响应头加入'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp'这两个字段,引发这个问题主要是因为浏览器厂商因为内存安全问题而对shareArrayBuffer这个api做了限制,只需要在服务器响应头中设置这个字段即可解决。文章来源地址https://www.toymoban.com/news/detail-615197.html

 server: {
      open: true,
      host: '0.0.0.0',
      headers: {
        'Cross-Origin-Opener-Policy': 'same-origin',
        'Cross-Origin-Embedder-Policy': 'require-corp'
      },
      proxy: {}
    },

到了这里,关于【新项目开发】vue3+ts+elementPlus+ffmpegjs开发纯web端的视频编辑器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序(一)小程序与web开发的区别&创建新项目

    1.小程序的开发准备 1.1小程序的安装与创建 1.1.1 生产appid 前往小程序官网,注册(不赘述了);登录上去之后,需要获得小程序的appid 由于后期调⽤微信⼩程序的接⼝等功能,需要索取开发者的⼩程序中的 APPID ,所以在注册成功后, 可登录,然后获取APPID。 登录成功后可看

    2024年02月12日
    浏览(47)
  • 新项目搞完啦!!!

    大家好,我是鱼皮。 经过了 7 场直播,总时长近 20 小时,我在 自己的编程导航 的第 5 个 全程直播开发 的项目 —— 智能 BI 项目,完结啦! 我在这里对该项目做一个简单的总结,希望让更多需要它的同学看到,把它变成自己的项目~ 这次做的是一个顺应潮流的项目, 基于

    2024年02月11日
    浏览(51)
  • Gitlab 新项目搭建

    项目名称与本地新建项目名称相同 进入本地项目根目录下,右击 git bash here打开命令窗口; 初始化本地仓库; 提交至暂存区; 提交项目。 建立本地仓库和远端 Gitlab 仓库关系; 2.拉取一下远程仓库内容; 推送本地内容到远程仓库。 出现以下问题: 原因就是 Gitlab 的仓库中

    2024年02月13日
    浏览(50)
  • 笔记 | FastAPI创建新项目

    当使用FastAPI创建项目时,首先需要安装FastAPI和其依赖项。可以使用pip来安装它们。请确保已经安装了Python和pip。 创建项目文件夹并进入该文件夹: 创建并激活一个新的Python虚拟环境(可选,但强烈推荐): 安装FastAPI和uvicorn(FastAPI的服务器): 创建一个名为 main.py 的文件

    2024年02月06日
    浏览(47)
  • 新项目如何推送Git

    一、在git新建一个空的仓库,不用任何模版,直接创建即可 完成后,copy仓库地址 二、本地新建项目,进入到本地项目命令行,也可以打开终端,其实是相通的:执行命令git init, 此时在项目上右击就发想有git选项,点击add添加,接着正常commit,然后push 在push的时候会发现有

    2024年02月12日
    浏览(52)
  • 中国省市区地区选择组件(ElementPlus + Vue3 + TS )

    1.引用 2.用法 provinceAndCityData :省市数据(不带“全部”选项) regionData :省市区数据(不带“全部”选项) provinceAndCityDataPlus :省市区数据(带“全部”选项) regionDataPlus :省市区数据(带“全部”选项) CodeToText :例如:CodeToText[‘110000’]输出北京市 TextToCode :例如:

    2023年04月27日
    浏览(55)
  • idea新项目上传git

    关于idea新项目怎么上传到git,今天整理一下操作的步骤。来做一个记录! 1.首先要在项目上右击打开终端或者在idea的下方有一个快捷按钮 按照上面的截图进行操作,打开终端窗口 2.然后在终端窗口中输入 git init 命令,会出现如图样子 3.然后右击项目会出现git的选项,然后按

    2024年02月12日
    浏览(38)
  • 本地新项目推送至gitlab仓库

    1. gitlab上新建一个空白项目 gitlab上点击new project按钮,新建一个项目   新建空白项目  项目名称与本地新建项目名称相同,其余根据具体需要选择 2. 初始化本地仓库并commit项目   进入本地项目根目录下,右击 git bash here打开命令窗口  初始化本地仓库: git init  提交至暂存

    2024年02月13日
    浏览(35)
  • gitlab合并新项目和分支切换

    1、创建空白项目   2、先创建一个群组    3、编写群组信息  4、创建群组完成以后新建项目 1、初始化 2、关联gitlab地址 3、查看是否关联成功 4、添加文件 5、提交到本地仓库 6、进行推送(注意推送分支) 7、查看结果 记得选择对应的分支 1、修改默认分支, 将默认分支修改成

    2024年02月12日
    浏览(41)
  • 搭建新项目 前端环境 及启动项目前的相关配置

    ** ** 提示:这里可以添加本文要记录的大概内容: 搭建新项目 前端环境 下图所示为开发时前端所用的编辑器 提示:以下是本篇文章正文内容,下面案例可供参考 注意:在配置时 有时候 localhost 可能 不太好用,所以我们 最好配置 成 127.0.0.1 指向我们的电脑 代码如下(示例

    2024年01月23日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包