国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【新項(xiàng)目開發(fā)】vue3+ts+elementPlus+ffmpegjs開發(fā)純web端的視頻編輯器

這篇具有很好參考價值的文章主要介紹了【新項(xiàng)目開發(fā)】vue3+ts+elementPlus+ffmpegjs開發(fā)純web端的視頻編輯器。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

新項(xiàng)目開發(fā)的流程

當(dāng)在項(xiàng)目中使用新技術(shù)時,我們應(yīng)該首先進(jìn)行調(diào)研,了解其特點(diǎn)和使用方法。在實(shí)現(xiàn)功能時,我們可以采用最簡單的方式,而不必過于關(guān)注項(xiàng)目的設(shè)計(jì)和結(jié)構(gòu)。一旦掌握了新技術(shù),我們可以根據(jù)其API屬性進(jìn)行代碼設(shè)計(jì),以便更好地開發(fā)。以開發(fā)一個純web端的視頻編輯處理器為例,我們打算采用vite、vue3、elementPlus、pinia和ffmpegjs等技術(shù)。雖然第一次接觸ffmpegjs庫可能會感到陌生,但我們需要先了解其API屬性,并能夠?qū)崿F(xiàn)所需的功能。在此基礎(chǔ)上,我們可以考慮如何將ffmpegjs集成到項(xiàng)目中,并設(shè)計(jì)好項(xiàng)目架構(gòu)和代碼結(jié)構(gòu),以便更好地使用和維護(hù)。

視頻編輯器項(xiàng)目操作介紹:

web視頻編輯器

1.功能列表:

  • 上傳視頻
  • 視頻分割
  • 添加字幕文件
  • 文字軌道:自定義時間,文字內(nèi)容
  • 貼圖軌道:自定義時間
  • 預(yù)覽
  • 導(dǎo)出功能
    2.代碼:
    git倉庫:https://github.com/huhaibiao/video-edit-demo.git
    3.線上演示vercel url:
    https://video-edit-demo.vercel.app/#/
  1. 項(xiàng)目運(yùn)行
  • pnpm i安裝依賴
  • pnpm dev 項(xiàng)目本地運(yùn)行
  • pnpm build 項(xiàng)目打包

ffmpegjs是什么

ffmpegjs是一個基于JavaScript的開源庫,它提供了一個在瀏覽器中運(yùn)行FFmpeg的解決方案。FFmpeg是一個廣泛使用的開源跨平臺音視頻處理工具,可以用于音視頻的編解碼、轉(zhuǎn)碼、剪輯、合并等操作。ffmpegjs庫通過將FFmpeg編譯為WebAssembly格式,并使用JavaScript封裝其API,使得我們可以在瀏覽器中使用FFmpeg進(jìn)行音視頻處理,而無需安裝任何本地軟件。ffmpegjs庫可以用于開發(fā)各種基于Web的音視頻應(yīng)用,如視頻編輯器、音視頻轉(zhuǎn)換器、在線直播等。

安裝ffmpegjs

需要安裝 @ffmpeg/ffmpeg @ffmpeg/core 這兩個npm包
pnpm install @ffmpeg/ffmpeg @ffmpeg/core

在項(xiàng)目中引入

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

項(xiàng)目核心模塊

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導(dǎo)入視頻 */
export const initVideo = async (video: Blob) => {
  ffmpeg.FS('writeFile', videoName, await fetchFile(video))
  await ffmpeg.run('-i', videoName)
}

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

let imageName = 'imageMark'
/**ffmpeg導(dǎo)入貼圖 */
export const writeImage = async (image: Blob) => {
  ffmpeg.FS('writeFile', imageName, await fetchFile(image))
}

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

/**通過url獲取文件blob數(shù)據(jù) */
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)
  }
}

/**導(dǎo)出視頻,降幀 */
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
}

項(xiàng)目常見的問題:

1、shareArrayBuffer問題,shareArrayBuffer not defined
給服務(wù)響應(yīng)頭加入'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp'這兩個字段,引發(fā)這個問題主要是因?yàn)闉g覽器廠商因?yàn)閮?nèi)存安全問題而對shareArrayBuffer這個api做了限制,只需要在服務(wù)器響應(yīng)頭中設(shè)置這個字段即可解決。文章來源地址http://www.zghlxwxcb.cn/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: {}
    },

到了這里,關(guān)于【新項(xiàng)目開發(fā)】vue3+ts+elementPlus+ffmpegjs開發(fā)純web端的視頻編輯器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 微信小程序(一)小程序與web開發(fā)的區(qū)別&創(chuàng)建新項(xiàng)目

    微信小程序(一)小程序與web開發(fā)的區(qū)別&創(chuàng)建新項(xiàng)目

    1.小程序的開發(fā)準(zhǔn)備 1.1小程序的安裝與創(chuàng)建 1.1.1 生產(chǎn)appid 前往小程序官網(wǎng),注冊(不贅述了);登錄上去之后,需要獲得小程序的appid 由于后期調(diào)?微信?程序的接?等功能,需要索取開發(fā)者的?程序中的 APPID ,所以在注冊成功后, 可登錄,然后獲取APPID。 登錄成功后可看

    2024年02月12日
    瀏覽(23)
  • 新項(xiàng)目搞完啦?。。? decoding=

    新項(xiàng)目搞完啦?。?!

    大家好,我是魚皮。 經(jīng)過了 7 場直播,總時長近 20 小時,我在 自己的編程導(dǎo)航 的第 5 個 全程直播開發(fā) 的項(xiàng)目 —— 智能 BI 項(xiàng)目,完結(jié)啦! 我在這里對該項(xiàng)目做一個簡單的總結(jié),希望讓更多需要它的同學(xué)看到,把它變成自己的項(xiàng)目~ 這次做的是一個順應(yīng)潮流的項(xiàng)目, 基于

    2024年02月11日
    瀏覽(94)
  • Gitlab 新項(xiàng)目搭建

    Gitlab 新項(xiàng)目搭建

    項(xiàng)目名稱與本地新建項(xiàng)目名稱相同 進(jìn)入本地項(xiàng)目根目錄下,右擊 git bash here打開命令窗口; 初始化本地倉庫; 提交至?xí)捍鎱^(qū); 提交項(xiàng)目。 建立本地倉庫和遠(yuǎn)端 Gitlab 倉庫關(guān)系; 2.拉取一下遠(yuǎn)程倉庫內(nèi)容; 推送本地內(nèi)容到遠(yuǎn)程倉庫。 出現(xiàn)以下問題: 原因就是 Gitlab 的倉庫中

    2024年02月13日
    瀏覽(94)
  • 筆記 | FastAPI創(chuàng)建新項(xiàng)目

    筆記 | FastAPI創(chuàng)建新項(xiàng)目

    當(dāng)使用FastAPI創(chuàng)建項(xiàng)目時,首先需要安裝FastAPI和其依賴項(xiàng)??梢允褂胮ip來安裝它們。請確保已經(jīng)安裝了Python和pip。 創(chuàng)建項(xiàng)目文件夾并進(jìn)入該文件夾: 創(chuàng)建并激活一個新的Python虛擬環(huán)境(可選,但強(qiáng)烈推薦): 安裝FastAPI和uvicorn(FastAPI的服務(wù)器): 創(chuàng)建一個名為 main.py 的文件

    2024年02月06日
    瀏覽(99)
  • 新項(xiàng)目如何推送Git

    新項(xiàng)目如何推送Git

    一、在git新建一個空的倉庫,不用任何模版,直接創(chuàng)建即可 完成后,copy倉庫地址 二、本地新建項(xiàng)目,進(jìn)入到本地項(xiàng)目命令行,也可以打開終端,其實(shí)是相通的:執(zhí)行命令git init, 此時在項(xiàng)目上右擊就發(fā)想有g(shù)it選項(xiàng),點(diǎn)擊add添加,接著正常commit,然后push 在push的時候會發(fā)現(xiàn)有

    2024年02月12日
    瀏覽(93)
  • 中國省市區(qū)地區(qū)選擇組件(ElementPlus + Vue3 + TS )

    中國省市區(qū)地區(qū)選擇組件(ElementPlus + Vue3 + TS )

    1.引用 2.用法 provinceAndCityData :省市數(shù)據(jù)(不帶“全部”選項(xiàng)) regionData :省市區(qū)數(shù)據(jù)(不帶“全部”選項(xiàng)) provinceAndCityDataPlus :省市區(qū)數(shù)據(jù)(帶“全部”選項(xiàng)) regionDataPlus :省市區(qū)數(shù)據(jù)(帶“全部”選項(xiàng)) CodeToText :例如:CodeToText[‘110000’]輸出北京市 TextToCode :例如:

    2023年04月27日
    瀏覽(33)
  • idea新項(xiàng)目上傳git

    idea新項(xiàng)目上傳git

    關(guān)于idea新項(xiàng)目怎么上傳到git,今天整理一下操作的步驟。來做一個記錄! 1.首先要在項(xiàng)目上右擊打開終端或者在idea的下方有一個快捷按鈕 按照上面的截圖進(jìn)行操作,打開終端窗口 2.然后在終端窗口中輸入 git init 命令,會出現(xiàn)如圖樣子 3.然后右擊項(xiàng)目會出現(xiàn)git的選項(xiàng),然后按

    2024年02月12日
    瀏覽(92)
  • 本地新項(xiàng)目推送至gitlab倉庫

    本地新項(xiàng)目推送至gitlab倉庫

    1. gitlab上新建一個空白項(xiàng)目 gitlab上點(diǎn)擊new project按鈕,新建一個項(xiàng)目 ? 新建空白項(xiàng)目 ?項(xiàng)目名稱與本地新建項(xiàng)目名稱相同,其余根據(jù)具體需要選擇 2. 初始化本地倉庫并commit項(xiàng)目 ? 進(jìn)入本地項(xiàng)目根目錄下,右擊 git bash here打開命令窗口 ?初始化本地倉庫: git init ?提交至?xí)捍?/p>

    2024年02月13日
    瀏覽(93)
  • gitlab合并新項(xiàng)目和分支切換

    gitlab合并新項(xiàng)目和分支切換

    1、創(chuàng)建空白項(xiàng)目? ?2、先創(chuàng)建一個群組 ? ?3、編寫群組信息 ?4、創(chuàng)建群組完成以后新建項(xiàng)目 1、初始化 2、關(guān)聯(lián)gitlab地址 3、查看是否關(guān)聯(lián)成功 4、添加文件 5、提交到本地倉庫 6、進(jìn)行推送(注意推送分支) 7、查看結(jié)果 記得選擇對應(yīng)的分支 1、修改默認(rèn)分支, 將默認(rèn)分支修改成

    2024年02月12日
    瀏覽(226)
  • 搭建新項(xiàng)目 前端環(huán)境 及啟動項(xiàng)目前的相關(guān)配置

    搭建新項(xiàng)目 前端環(huán)境 及啟動項(xiàng)目前的相關(guān)配置

    ** ** 提示:這里可以添加本文要記錄的大概內(nèi)容: 搭建新項(xiàng)目 前端環(huán)境 下圖所示為開發(fā)時前端所用的編輯器 提示:以下是本篇文章正文內(nèi)容,下面案例可供參考 注意:在配置時 有時候 localhost 可能 不太好用,所以我們 最好配置 成 127.0.0.1 指向我們的電腦 代碼如下(示例

    2024年01月23日
    瀏覽(89)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包