【CANN訓練營進階班應用課筆記】在Atlas 200DK上體驗VENC-VDEC-RESIZE-JPEGE
根據進階班作業貼:https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=182679&fromuid=446160
大作業2題目如下:
開發媒體數據處理的應用,應用的輸入為視頻碼流、輸出為 JPEG 圖片,且 JPEG 圖片與視頻的分辨率不同。
根據作業提示,轉換的思路如下:
原始MP4視頻=》H264/H265視頻=>使用dvpp的vdec解碼成yuv圖片(多張)-》使用dvpp的進行resize縮放-》使用dvpp的jpege將yuv圖片編碼=》JPEG圖片(多張)
下面看看如何實戰:
一、準備MP4視頻文件
先去搞個MP4過來。
張小白手頭有一個:黑寡婦.2021.BD1080p.中英雙字.mp4
打開格式工廠FormatFactory官網:
http://www.pcfreetime.com/formatfactory/CN/index.html
下載,安裝:
耐心等待安裝完畢:
點擊下一步:
點擊立即體驗:
進入主頁面:
點擊->MP4
點擊添加文件,選擇剛才的MP4文件。
點擊右上角的輸出配置:
可以看到視頻編碼為 H264,這種格式按理說 dvpp是能解析的吧。。
由于影片長達2個多小時,只截取1分鐘的片段,點擊文件右邊的“選項”按鈕:
根據預覽畫面,選中 31:18到32:18之間的影像進行剪輯:
點擊確定:
點擊頁面中的開始,進行轉換:
很快就轉換成功了。
打開MP4文件看看:
確實是1分鐘時長。且可以播放。
那么H264格式的視頻已經準備好了。我們可以試vdec,看看能不能解出成YUV吧。
二、視頻解碼VDEC的樣例嘗試
接著我們來看dvpp的vdec的文檔:
https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/51RC1alpha003/infacldevg/aclcppdevg/aclcppdevg_03_0186.html
按理說剛才做好的1分鐘視頻是應該支持的。到底行不行呢?
再看看具體說明:https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/51RC1alpha003/infacldevg/aclcppdevg/aclcppdevg_000025.html
這個圖的流程示意很清楚了,下面也有具體的解釋,就不一一說明了。大概的意思是:
循環處理輸入視頻流,調用aclvdecSendFrame進行視頻解碼,然后判斷是否觸發回調。一直到視頻流結束為止。
查看對用的sample倉代碼吧:https://gitee.com/ascend/samples/tree/master/cplusplus/level2_simple_inference/0_data_process/vdec
主代碼在此:
https://gitee.com/ascend/samples/blob/master/cplusplus/level2_simple_inference/0_data_process/vdec/src/main.cpp
我們編譯試試:
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec
cd scripts
bash ./sample_build.sh
記住,現在編譯的樣例代碼。
運行樣例代碼試試:
bash ./sample_run.sh
去output目錄看看:
生成了10張yuv的文件。
我們可以把原來的H265文件下載下來,然后把這幾個yuv文件做jpege編碼,看看圖片是啥樣子.
切換到jpege目錄:
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/data
cp ~/samples/cplusplus/level2_simple_inference/0_data_process/vdec/out/output/*.yuv .
修改 jpege的運行腳本:(先改一個yuv看看)
運行:
查看結果文件:
下載下來:
好像是個兔子:
唉,不知道原視頻是不是兔子啊。。。
有沒有什么辦法知道呢?從文件名感知一下:vdec_h265_lframe_rabbit_1280X720.h265,好像跟兔子有關。
三、用VDEC解析自己準備的MP4視頻的初步嘗試
回到 vdec,把 黑寡婦的1分鐘短視頻傳進去:
(我是不是應該把視頻轉成H265的再試試呢?)
黑寡婦.2021.BD1080p.中英雙字 00_31_18-00_32_18.mp4
把名字改改吧:
00_31_18-00_32_18.mp4
去對應的main.cpp修改下文件名和分辨率:
去scripts下執行編譯:
bash ./sample_build.sh
運行:
bash ./sample_run.sh
查看結果文件,這個文件只有10個(奇怪),但是文件比原來的大小大了。因為分辨率高了。
我們再把這個文件jpege編碼后看看是什么圖片吧!
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege/data
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/out/output/*.yuv .
文件名不變,但是分辨率變了,修改下 sample_run.sh
執行:
bash sample_run.sh
查看結果圖片:
下載下來看看:
打開:
芭比Q了。。
四、重做一個H265的視頻試試VDEC視頻解碼
張小白再用前面的方法,使用格式工廠將H264格式的MP4轉換為H265視頻的MP4:
源文件改名為H264.MP4
點擊開始進行轉換:
并將D:\FFOutput下的H264.MP4:
改名為H265.MP4,并使用MobaXterm上傳到vdec的data目錄下:
結果如下圖所示:
這里面需要更新 vdec的main.cpp
(前面對于H264的轉換時,也需要修改enType)
對于H265,需要將enType設為0
同樣進行編譯,運行:
然后再切換到jpege目錄下,將yuv文件拷貝到jpege的data目錄下
接著做jpege編碼,將結果文件download下來一看,仍然跟前面的結果一樣,啥也看不到。。。
五、失敗的問題分析與H264視頻流的VDEC-JPEGE
張小白有點蒙圈。只好在群里咨詢。
這時候,西瓜哥給了一盞明燈:
原來dvpp只認識h264和h265,如果是mp4文件,需要先解碼成流文件。
可以用opencv解碼成流文件,但是張小白突然發現200DK上安裝了ffmpeg.
那就用ffmepg將mp4轉換成H264文件吧!
ffmpeg -i 00_31_18-00_32_18.mp4 -vcodec h264 my.h264
成功生成了my.h264文件。
再回到vdec目錄,修改src/main.cpp:
文件名改為 my.h264, 分辨率改為 1920X1080,enType=3(H264 high level)
切換到 ../scripts下重新編譯:
切換到 ../out/output目錄,清空 *.yuv文件:
再切回到 ../../scripts下運行:
回到../out/output下檢查生成的文件:
切換到jpege目錄
cd ~/samples/cplusplus/level2_simple_inference/0_data_process/jpege/scripts
編輯sample_run.sh
將編碼1個yuv文件改為循環編碼所有的yuv文件,且把分辨率改為1920X1080
切換到 ../data目錄,清除當前目錄下的yuv文件:
并將 前面vdec生成的文件拷貝到這里:
cp ~/samples/cplusplus/level2_simple_inference/0_data_process/vdec/out/output/*.yuv .
檢查文件時間,已保證拷貝到了最新的文件。
清空jpege/out/output下的結果文件
cd ../out/output
rm -f *.jpg
切換回../../scripts目錄,開始運行:
bash? ./sample_run.sh
...
代碼會循環10次進行JPEGE編碼。
檢查最新的JPEG文件已經生成。
使用MobaXterm將這10個文件下載到本地:
發現10個一模一樣的文件:
打開其中一個文件:
看來my.h264文件已經成功解析出了第一幀。但是后面似乎還不對頭。但是萬里長征總算走了第一步了。。
六、VDEC解析后的圖片10張一模一樣的分析與VENC解決方案的嘗試
關于那10張圖片為啥都一模一樣的問題,張小白仔細看了下vdec的sample代碼,發現在主程序部分:
盡管是循環了10次,但是每次aclvdecSendFrame送的都是一模一樣的東西。這樣子肯定是圖片一模一樣的了。
張小白曾經將10改為100,結果就生成了100張一模一樣的圖片。
張小白以為在這個代碼上,通過幀的偏移進行計算,循環的時候送下一幀的內容就行了,后來咨詢后才知道:每幀的大小是不一樣的。
毛老師是這么解釋的:
那么,這種情形下,應該怎么去處理呢?毛老師建議使用 ffmpeg切幀。切完幀后,可以得到幀數據和幀大小,送給dvpp的vdec就行了。
張小白詢問:ffmpeg如果可以直接將含有多幀的h264的文件保存成文件,那么又何必使用dvpp呢?dvpp能不能也具備切幀能力呢?
大毛老師在這里進行了詳盡的解釋:
背景知識: mp4是封裝格式(里面可能包括視頻、音頻或者多個音頻、中英文字幕等等); h264/h265是視頻編碼(主要是壓縮)格式,注意僅僅是視頻編碼格式; 對于視頻場景: 切幀:從視頻流或者視頻文件中找出視頻的那個流,并抽出一幀一幀的視頻數據,并為每一幀添加解碼頭信息(用于后面解碼,否則解碼時不知道該怎么解);這時候的每一幀數據還是按照壓縮標準(h264或者h265)壓縮著的數據,所以這時還叫h264或者h265數據。 解碼:將h264/h265數據解碼,實質上就是按照壓縮標準逆向恢復原始數據的過程,例如恢復到yuv444、RGB888等; VPC: resize、摳圖、貼圖、批量摳圖、貼圖等等,是真正為了匹配你的神經網絡推理需要而做的處理; 再編碼:編碼成JPEG或者H264/H265. 上面這么些過程中,除了切幀建議用ffmpeg外,其他過程都可以使用dvpp加速;因為切幀速度很快,用ffmpeg在cpu上完成切幀過程也完全不是瓶頸,但是其他過程cpu上是比較慢的,一般情況下是跟不上NPU上的推理速度的,所以建議使用dvpp。 當然,dvpp目前也沒有切幀能力,個人認為當前也沒有必要,畢竟,cpu如果能行,為何要選擇用dvpp呢?
西瓜哥也追加說道:
我也覺得確實沒必要dvpp切幀數據,這基本上就是個普通的數據讀取加載的過程,并不是那種高密度計算的任務類型;而且尤其是對于AI推理芯片的使用場景來說,310通常的使用場景很可能是直接接收了一個攝像頭的碼流,或者rtmp協議的推流服務推過來的碼流,都不需要這種切幀操作,實際場景很少會丟一個mp4視頻文件到服務器的磁盤上,讓310芯片去做處理的
至此,解開了張小白的疑問。
既然這樣,那么下面就去好好考慮切幀的問題吧!
張小白仔細研究了下 samples代碼倉數據處理相關案例的代碼:
https://gitee.com/ascend/samples/tree/master/cplusplus/level2_simple_inference/0_data_process
發現,ffmpegdecode的切幀案例,好像不大適用本作業。倒是venc的處理方式吸引了我。
venc輸入是mp4,輸出是.h264/h265碼流。
先運行一下試試:
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/venc
cd scripts
bash ./sample_build.sh
bash ./sample_run.sh
...
從打印出來的內容來看,似乎每幀都在解析中。張小白很是欣喜,覺得如果是這樣,那么MP4文件被解析成一幀一個的.H264文件,那就非常棒了。
于是切換到out/output目錄下一看:
還是生成了一個H264文件。
但既然有源碼,就難不倒張小白。
張小白又開始了他的魔改代碼之旅。
七、視頻編碼VENC的正式處理
看下圖:
在原來的回調程序中,venc一直在寫一個文件。所以即便是它每幀都解了,但是依然是往outfileFp去寫。既然這樣,我們就找個辦法,每次回調寫不同的文件就行了。
于是,張小白這樣寫:
每次回調的時候都生成一個新的文件名,然后打開這個文件寫入,寫完后立即關閉。
改完之后編譯、運行下試試:(一樣的過程就不細寫命令了,全是 bash ./sample_build.sh, bash ./sample_run.sh)
這次居然能生成不同的文件了。(其實不用居然,就是張小白努力的結果)
而且,通過文件的大小可以看到,每一幀是不一樣的。
那么,我們更換一下前面的解題思路:
(1)修改venc代碼,打開MP4文件,將每一幀保存成一個 xx.h264文件。
(2)改造vdec代碼,打開不同的 xx.h264文件,對于不同的文件都轉換成yuv圖片
(3)改造resize代碼,打開不同的1080p的 yuv文件,進行縮放:1920X1080-》1280X720 生成不同的 720p的yuv文件。
(4)改造jpege代碼,打開不同的 720p的yuv文件,生成不同的720p的jpg文件。
現在只是將第一步基本實現了,但是尚未讀取 張小白自制的 1分鐘黑寡婦的MP4。
下面開始操作:
將 H264的文件拷貝到 ~/samples/cplusplus/level2_simple_inference/0_data_process/venc/data 目錄:
修改 sample_run.sh 讓其讀取這個MP4:
運行:
...
耐心等待,一共會生成1439多個H264文件(從0到1438),其中out_video.h264 0個字節,是原來的文件,張小白沒有把代碼刪掉,所以還會有個空文件。
。。。
這1439個文件各不相同,保證了不會出現像前面那樣圖片都一樣的情況。
八、視頻解碼VDEC的正式處理
切換到 vdec目錄下:
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/data
將前面的輸出拷貝到vdec的輸入目錄data:
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/venc/out/output/*.h264 .
修改vdec的源碼,讓其在aclvdecSendFrame的時候送 不同的H264文件對應的不同幀:
因為有1000多個文件,為了容量和時間考慮,暫時處理200個H264文件吧:
編譯venc代碼
清空 vdec/out/output目錄:
運行vdec代碼:
打出的日志標明了讀取哪個H264文件,寫入哪個yuv文件。。。
執行完畢后,在vdec/out/output目錄下生成了200個imagexxx.yuv文件:
但是,由于都是1920X1080的size,所以yuv文件倒變成了一樣的大小:
九、YUV圖片縮放RESIZE的正式處理
進入resize的data目錄,將上一步的200個yuv文件拷貝過來:
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/data
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/vdec/out/output/image*.yuv .
resize的main.cpp代碼需要打印一下輸出的文件名:
編譯:
resize的sample_run.sh 需要把現在的處理單個yuv文件變成一個循環:
去 resize的out/output目錄下清空文件:
回來運行 bash ./sample_run.sh
...
耐心等待200個文件resize完畢:
生成的文件查看一下:
生成了200個yuv文件,大小均為:1382400.
前面data下的文件大小均為:3110400
可見應該是被縮小了的。
十、圖片編碼JPEGE的正式處理
切換到 jpege目錄
cd /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/jpege
cd data
將resize的結果yuv文件拷貝過來:
cp /home/HwHiAiUser/samples/cplusplus/level2_simple_inference/0_data_process/resize/out/output/image*.yuv .
清空jpege的output目錄
修改sample_run.sh
執行jpege編碼的編譯:
執行:
耐心等待200個文件執行結束:
去output目錄下查看結果的jpg文件:
可見,這200個文件都不一樣。
十一、運行結果的檢查
使用MobaXterm將其下載下來仔細看看:
可以看到文件各不相同:
隨便打開幾個看看:
恩,我們能像成年人一樣談談嗎?
這就完成了本次的大作業2。
(全文完,謝謝閱讀)
Atlas 200 DK開發者套件 云端實踐 昇騰 AI Ubuntu
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。