版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 醫(yī)生診療過程中儀態(tài)舉止
- 2026年河南工業(yè)貿(mào)易職業(yè)學(xué)院單招綜合素質(zhì)筆試參考題庫帶答案解析
- 醫(yī)療器械使用與維護(hù)禮儀
- 2026年呼和浩特職業(yè)學(xué)院單招綜合素質(zhì)筆試備考試題帶答案解析
- 2026年福建師范大學(xué)協(xié)和學(xué)院高職單招職業(yè)適應(yīng)性考試參考題庫帶答案解析
- 個性化藥物治療在罕見病治療中的應(yīng)用
- 醫(yī)院臨床科研能力提升
- 2026年保險職業(yè)學(xué)院高職單招職業(yè)適應(yīng)性考試備考試題帶答案解析
- 2026年合肥信息技術(shù)職業(yè)學(xué)院單招綜合素質(zhì)筆試備考試題帶答案解析
- 護(hù)理健康教育方法創(chuàng)新
- 電商行業(yè)個性化服務(wù)2025年用戶需求分析報告
- Web滲透測試與防護(hù)(虞菊花慕課版)單元設(shè)計
- 湘教版(2024)八上地理教學(xué)設(shè)計-第二章第三節(jié) 中國的河流 第二課時 長江
- 2024年全國職業(yè)院校技能大賽中職組(舞蹈表演賽項)考試題庫(含答案)
- 中醫(yī)外治技術(shù)之穴位注射操作指南:精準(zhǔn)操作與安全優(yōu)化的臨床應(yīng)用解析
- 農(nóng)業(yè)物聯(lián)網(wǎng)技術(shù)服務(wù)合同
- 湖湘文廟建筑文化傳承與保護(hù)研究
- 數(shù)據(jù)中心消防培訓(xùn)課件教學(xué)
- JJF(蒙) 042-2023 零碳產(chǎn)業(yè)園計量評價規(guī)范
- 2025年資產(chǎn)評估師《資產(chǎn)評估實務(wù)》真題及答案
- JJF(陜) 133-2025 亞甲藍(lán)攪拌器校準(zhǔn)規(guī)范
評論
0/150
提交評論