flutter使用tauri實現(xiàn)一個一鍵視頻轉(zhuǎn)4K軟件_第1頁
flutter使用tauri實現(xiàn)一個一鍵視頻轉(zhuǎn)4K軟件_第2頁
flutter使用tauri實現(xiàn)一個一鍵視頻轉(zhuǎn)4K軟件_第3頁
flutter使用tauri實現(xiàn)一個一鍵視頻轉(zhuǎn)4K軟件_第4頁
flutter使用tauri實現(xiàn)一個一鍵視頻轉(zhuǎn)4K軟件_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第flutter使用tauri實現(xiàn)一個一鍵視頻轉(zhuǎn)4K軟件目錄前言開發(fā)原因工作原理開發(fā)過程

前言

先說結(jié)論,tauri是一個非常優(yōu)秀的前端桌面開發(fā)框架,但是,rust門檻太高了。

一開始我是用electron來開發(fā)的,但是打包后發(fā)現(xiàn)軟件運行不是很流暢,有那么一點卡頓。于是為了所謂的性能,我嘗試用tauri來做我的軟件。在學(xué)了兩星期的rust后,我發(fā)現(xiàn)rust真的太難學(xué)了,最后硬是邊做邊查勉強(qiáng)做出來了。

軟件運行起來是比electron做的絲滑很多,但是寫rust真的是很痛苦,rust的寫法和其他語言是截然不同的,在不知道之前我是個rust吹,覺得rust就是牛逼,真的上手后發(fā)現(xiàn)rust的門檻真的太高了,各種逆天的寫法直接把我勸退,tauri無縫銜接前端真的又很爽。

如果golang也出一個和tauri一樣的桌面端框架,那么golang將會是未來開發(fā)中的不二語言。

開發(fā)原因

我平時喜歡看一些動漫視頻或者是收藏一些做得不錯的動漫MAD,但是有時候因為番劇出的年代久遠(yuǎn)的問題,就算找最高清的資源,視頻也不過720P,又或者是在b站上看一些動漫MAD的時候,up主雖然用的轉(zhuǎn)場技巧比較不錯,但是使用的動漫素材的質(zhì)量比較差,十分可惜。

于是我想能不能做一個視頻轉(zhuǎn)4K的軟件?類似于修復(fù)視頻的功能。雖然網(wǎng)絡(luò)上的修復(fù)視頻軟件有很多了,但是效果還是達(dá)不到我的要求,于是說干就干。

工作原理

視頻其實就是一幀一幀的圖片組成,如果要把視頻轉(zhuǎn)成4K,那么只要把視頻分解成圖片,再將圖片轉(zhuǎn)4K圖片,最后將4K圖片合并成4K視頻就可以了。

于是我搜了一圈,了解到有Real-ESRGAN]這樣的一個將圖片轉(zhuǎn)成4K的軟件。并且里面也提供好了視頻轉(zhuǎn)4K的案例。

先用ffmpeg將視頻分解成圖片:

ffmpeg-i原視頻-qscale:v1-qmin1-qmax1-vsync0臨時圖片路徑/frame%08d.png

再用Real-ESRGAN將圖片轉(zhuǎn)4K圖片:

./realesrgan-ncnn-vulkan.exe-i臨時圖片目錄-o4K圖片目錄-nrealesr-animevideov3-s2-fjpg

最后查看原視頻的幀數(shù),然后用ffmpeg將4K圖片合成4K視頻:

ffmpeg-i原視頻

ffmpeg-r23.98-i4K圖片路徑/frame%08d.jpg-c:vlibx264-r幀數(shù)-pix_fmtyuv420p4K視頻

只不過這樣操作起來非常繁瑣,并且只能一個個轉(zhuǎn),不能批量操作,也不能看到進(jìn)度。雖然可以寫一個cmd腳本批量操作,但是看不到進(jìn)度,體驗不是很好的。于是說干就干,開發(fā)軟件!

開發(fā)過程

tauri提供了一些后端的操作權(quán)限給前端,也就是在前端就能完成讀寫文件,這就非常方便了!但是也是有一定限制的,比如要讀取任意文件,就要rust去操作。

前提工作先準(zhǔn)備一個文件,導(dǎo)出一個數(shù)組,pids,以便關(guān)閉軟件時殺死所有windows進(jìn)程。

exportconstpids:number[]=[]

首先是創(chuàng)建3個文件夾,臨時圖片文件夾,圖片轉(zhuǎn)4K圖片文件夾,輸出視頻文件夾,用來存放輸出的資源的:

awaitreadDir(`${basePath.value}/img_temp`).catch(()={

createDir(`${basePath.value}/img_temp`)

awaitreadDir(`${basePath.value}/img_out`).catch(()={

createDir(`${basePath.value}/img_out`)

awaitreadDir(`${basePath.value}/output`).catch(()={

createDir(`${basePath.value}/output`)

然后是選定一個input文件夾,然后讀取文件夾下面的視頻,是rust實現(xiàn):

fnread_dir_file(path:String)-VecString{

letmutarr:VecString=vec![];

foriteminread_dir(path).unwrap(){

if!item.as_ref().unwrap().path().is_dir(){

arr.push(item.unwrap().file_name().into_string().unwrap());

returnarr;

因為返回的是一個數(shù)組,前端獲取到之后,就遍歷去操作。但后面為了方便,我則是遍歷這個數(shù)組,然后創(chuàng)建子組件,傳入文件路徑,讓子組件去操作:

import{invoke}from'@tauri-apps/api/tauri'

constfileList=awaitinvokestring[]('read_dir_file',{path:path.value})

首先還是遍歷創(chuàng)建子文件夾,方便管理:

awaitreadDir(`${props.basePath}/img_temp/${fileName}`).catch(()={

createDir(`${props.basePath}/img_temp/${fileName}`)

awaitreadDir(`${props.basePath}/img_out/${fileName}`).catch(()={

createDir(`${props.basePath}/img_out/${fileName}`)

接著調(diào)用tauri提供的shell指令:不過在此之前,先要配置tauri.conf.json,讓tauri支持任意命令

"tauri":{

"allowlist":{

"shell":{

"scope":[

"name":"ffmpeg",

"cmd":"cmd",

"args":["/C",{"validator":"\\S+"}]

然后先執(zhí)行讀取視頻的信息得到幀數(shù)和視頻的總秒數(shù),以便計算進(jìn)度,并且把返回的pid存到數(shù)組中:

import{Command}from'@tauri-apps/api/shell'

constfps=ref('5')

constduration=ref('')

constcmd1=`ffmpeg-i${props.basePath}/input/${props.file}`

constcommand1=newCommand('ffmpeg',['/C',cmd1])

constchild1=awaitcommand1.spawn()

command1.stderr.on('data',(line)={

constfpsResult=line.match(/\w{2}\.\w{0,2}(=fps)/)

/**匹配視頻持續(xù)時間的信息*/

constdurationResult=line.match(/(=Duration:).+(=,start)/)

if(fpsResult){

fps.value=fpsResult[0]

console.log('fps',fps.value)

if(durationResult){

duration.value=durationResult[0]

console.log('duration',duration.value)

pids.push(child1.pid)

用正則匹配幀數(shù)和持續(xù)時間,存到變量中。在命令執(zhí)行完畢后,接著執(zhí)行將視頻分解圖片的任務(wù):

command1.on('close',async()={

constcmd2=`${props.ffmpegPath}-i${props.basePath}/input/${props.file}-qscale:v1-qmin1-qmax1-vsync0${props.basePath}/img_temp/${fileName}/frame%08d.png`

constcommand2=newCommand('ffmpeg',['/C',cmd2])

constchild2=awaitcommand2.spawn()

pids.push(child2.pid)

至于監(jiān)聽進(jìn)度,圖片的總數(shù)是可以通過幀數(shù)和視頻總秒數(shù)計算出來的,總秒數(shù)乘以幀數(shù),就是要轉(zhuǎn)換的圖片總數(shù)。由于得到的持續(xù)時間是00:04:32這種格式的,先寫一個函數(shù)將時間轉(zhuǎn)成秒數(shù):

/**

*@description將字符串的時間轉(zhuǎn)成總秒數(shù)的時間00:04:35

*@paramtime字符串的時間

*@returns返回秒數(shù)的時間

exportfunctionformatTime(time:string){

consthours=Number(time.split(':')[0])

constmimutes=Number(time.split(':')[1])

constseconds=Number(time.split(':')[2])

returnhours*60*60+mimutes*60+seconds

總圖片就可以計算出來了,然后在輸出時,使用節(jié)流,每隔1秒讀取一次該文件夾下面的圖片數(shù)量,則進(jìn)度就是當(dāng)前的圖片數(shù)量/圖片總數(shù)。

讀取文件數(shù)量需要rust操作

fnread_dir_file_count(path:String)-i32{

letdir=read_dir(path).unwrap();

letmutcount:i32=0;

for_indir{

count+=1;

returncount;

則整體是:

consttotal=formatTime(duration.value)*Number(fps.value)

command2.stderr.on('data',async(line)={

constcurrent=awaitinvokenumber('read_dir_file_count',{

path:`${props.basePath}/img_temp/${fileName}`,

console.log(current,total)

precent1.value=Math.round((current/total)*100)

precent1就是綁定的進(jìn)度條的變量。

在任務(wù)關(guān)閉后,執(zhí)行優(yōu)化圖片的命令:

command2.on('close',async()={

constcmd3=`${props.realesrgan}-i${props.basePath}/img_temp/${fileName}-o${props.basePath}/img_out/${fileName}-nrealesr-animevideov3-s2-fjpg`

constcommand3=newCommand('ffmpeg',['/C',cmd3])

constchild3=awaitcommand3.spawn()

pids.push(child3.pid)

監(jiān)聽轉(zhuǎn)換的進(jìn)度仍是讀取文件夾下面當(dāng)前的圖片數(shù)量,用節(jié)流函數(shù),優(yōu)化性能:

command3.stderr.on('data',throttle(fn,2000))

asyncfunctionfn(){

constcurrent=awaitinvokenumber('read_dir_file_count',{

path:`${props.basePath}/img_out/${fileName}`,

precent2.value=Math.round((current/total)*100)

console.log(current,total,(current/total)*100)

//console.log(line)

最后在命令完成后,執(zhí)行4K圖片轉(zhuǎn)4K視頻的命令:

command3.on('close',async()={

constcmd4=`${props.ffmpegPath}-r${fps.value}-i${props.basePath}/img_out/${fileName}/frame%08d.jpg-i${props.basePath}/input/${props.file}-map0:v:0-map1:a:0-c:acopy-c:v${props.model}-r${fps.value}-pix_fmtyuv420p${props.basePath}/output/${props.file}`

constcommand4=newCommand('ffmpeg',['/C',cmd4])

constchild4=awaitcommand4.spawn()

pids.push(child4.pid)

監(jiān)聽進(jìn)度此時則是去獲取stderr輸出的信息,然后匹配到當(dāng)前轉(zhuǎn)換的時間,再除以總時間

consttotal=formatTime(duration.value)

command4.stderr.on('data',throttle(fn,200))

asyncfunctionfn(data:string){

/**控制臺的信息*/

constresult=data.mat

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論