為Raspberry Pi 64bit OS編譯可硬件加速的FFmpeg(arm64)
》》》 Hi~ o(* ̄▽ ̄*)ブ 《《《
起因是我去年7月份在b站上偶然看到了這樣一個比較有意思的樹莓派教學(xué)視頻:
【樹莓派排坑指南】如何為你64位系統(tǒng)的樹莓派4B編譯可使用硬件編碼的FFMPEG
看完之后的我大為震撼,決定多多少少都要做些什么 ( ?? ω ?? )!因為視頻中整個編譯過程全部是在Raspberry Pi 4B上面完成的,又恰巧在這不久之前第一次了解到嵌入式交叉編譯技術(shù)的存在,可以利用計算資源更豐富、性能更強(qiáng)勁的x86平臺給其他架構(gòu)的設(shè)備編譯軟件,所以就在評論區(qū)里面請教了一下有關(guān)“交叉編譯樹莓派64位FFmpeg”教程的問題(當(dāng)時我還沒有意思到,想要交叉編譯出可以使用特定平臺硬件編碼ffmpeg需要面臨的問題的嚴(yán)重性),視頻的UP主也是很有耐心地跟我分析了交叉編譯方案的難點(diǎn)所在:
交叉編譯不現(xiàn)實,因為很多依賴全部都要交叉編譯,太累人。在樹莓派上編譯的話,可以省去編譯很多共享庫的時間,只需要編譯一個ffmpeg,而且編譯硬件解碼支持必須要Linux內(nèi)核頭文件,這些都只有官方版系統(tǒng)有,所以交叉編譯ffmpeg是不支持硬件編解碼的。想要交叉編譯好的靜態(tài)ffmpeg(單文件可運(yùn)行)的話,可以去ffmpeg官網(wǎng)下載,官方有編譯好的。
初生牛犢不怕虎,當(dāng)時的我對交叉編譯這一概念僅僅是停留在理論階段,并沒有實踐經(jīng)驗,所以對UP主所說的這段話理解還不夠深刻 (〒▽〒),后來我真的嘗試去交叉編譯可以硬件加速的FFmpeg,然后就沒然后了。。。
在交叉編譯這條路上碰了一鼻子灰之后,除了在真正的Raspberry Pi 4B平臺上編譯全過程以外,暫時也沒有其他辦法。所幸的是,我并不急需要在樹莓派上使用FFmpeg,所以有一段時間也沒多在意這個事情。直到幾天前得到了一位大佬的回復(fù),提供了使用QEMU模擬aarch64環(huán)境,同時利用樹莓派系統(tǒng)鏡像中的RootFS編譯FFmpeg的方案,讓我有了繼續(xù)填坑的動力(非常感謝大佬的技術(shù)知識分享?ヾ(≧▽≦*)o ),于是在接下來的幾天內(nèi),我抽空前往大佬的個人博客拜讀了相關(guān)的技術(shù)文章,并完成了全過程的實踐驗證,這篇專欄才得以公之于眾。大佬的個人博客文章鏈接,供大家參考閱讀:https://haruto.zone/post/132
下面我會將實踐過程連同遇到的一些問題和解決方案,以及個人的思考感悟分享給大家,一庫走!
》》》 (。???)ノ 《《《
在開始之前我先總結(jié)性的回答幾個問題(權(quán)當(dāng)你還沒看過上面的視頻和文章,建議先去看一遍視頻和博客文章):
為什么要在樹莓派上使用64位系統(tǒng)?
答:Raspberry Pi 4B搭載了一顆4核心的64bit armv8 SoC,實踐證明,在樹莓派上使用64位系統(tǒng)的性能發(fā)揮與32位系統(tǒng)相比有明顯提升,特別是8GB內(nèi)存容量的樹莓派,64位系統(tǒng)能充分利用內(nèi)存空間。
為什么要自己編譯適用于樹莓派64位系統(tǒng)的、可硬件加速的FFmpeg?
答:從官方64位系統(tǒng)源中直接下載的FFmpeg無法正常使用硬件編解碼器(不知道官方現(xiàn)在有沒有修復(fù)這個問題),會出現(xiàn)偏色等奇怪的問題,總之非常讓人頭疼,所以要自己手搓FFmpeg。
我為什么總是執(zhí)著于在樹莓派開發(fā)板以外的平臺上編譯FFmpeg?
答:也是因為個人“潔癖”,我使用的樹莓派系統(tǒng)是raspios-buster-arm64-lite,沒有圖形界面以及其他額外的軟件包,一切從簡,而編譯FFmpeg不僅需要安裝大量額外的dev軟件包,還會占用“大量”的存儲空間(家境貧寒,我目前在用樹莓派SDCard容量僅有16GB)。另外Raspberry Pi 4B雖然在性能上較前一代有了顯著提升,但綜合來看還是很弱雞,更何況編譯軟件是非常消耗設(shè)備資源的,所以首選是在其他性能更強(qiáng)勁的平臺上編譯。
好,答疑結(jié)束,準(zhǔn)備手搓一個FFmpeg ( ?? ω ?? )y
再次確認(rèn)你的樹莓派上目前所使用的系統(tǒng)發(fā)行版本和硬件架構(gòu),并準(zhǔn)備好相對應(yīng)的64位樹莓派系統(tǒng)鏡像:
樹莓派系統(tǒng)鏡像可以前往官網(wǎng)或者國內(nèi)主流鏡像站下載,以我的Raspberry Pi 4B為例,基本信息如下,所以我準(zhǔn)備的系統(tǒng)鏡像是2021-05-07-raspios-buster-arm64-lite.img:

本次實踐過程中我使用的“宿主機(jī)”環(huán)境是Ubuntu 20.04.1 LTS amd64虛擬機(jī)??,別問,問就是家境貧寒,被迫套娃。如果條件允許的話,建議還是直接上性能強(qiáng)勁一點(diǎn)的物理機(jī)或者云服務(wù)器,除非你愿意在編譯階段等上個2~3小時,那還不如直接在樹莓派上編譯。。。

在宿主機(jī)命令行下執(zhí)行以下命令,安裝相關(guān)的工具,沒什么好說的:
覺得多敲幾個“sudo”麻煩的話,可以在Root用戶模式下執(zhí)行這些命令,我個人在操作時比較謹(jǐn)慎,基本都是用sudo提權(quán)。
繼續(xù)在宿主機(jī)中進(jìn)行下一項操作,將準(zhǔn)備好的樹莓派鏡像文件與loop設(shè)備綁定:
這里可能會遇到一些問題,例如我在驗證上述步驟的過程中碰到了loop設(shè)備忙的情況,嘗試掙扎后無果,于是換成其他的loop設(shè)備再做嘗試。

如果是自己做實驗的話,還是得根據(jù)自己的實際情況來,必要的時候需要靈活處理遇到的各種突發(fā)問題。

想要知道宿主機(jī)上有哪些可用的loop設(shè)備,可以執(zhí)行這條命令:
接下來創(chuàng)建兩個空的文件目錄,用來掛載和轉(zhuǎn)存樹莓派鏡像文件中的RootFS;接著以只讀模式將樹莓派鏡像中的RootFS掛載到空文件目錄;這里的空目錄命名并沒有固定要求,待掛載的loop設(shè)備一定要根據(jù)自己的實際情況來,選擇p2分區(qū):
為什么是掛載loop設(shè)備的p2分區(qū)?給樹莓派燒錄過系統(tǒng)鏡像的同學(xué)都知道,樹莓派系統(tǒng)鏡像默認(rèn)有兩個分區(qū),一個是/boot分區(qū),F(xiàn)AT32格式;另外一個是根分區(qū)(/),Ext4格式;p1是/boot,p2就是我們需要的RootFS。通過宿主機(jī)的資源管理器我們也可以驗證上述猜想:

將掛載目錄下RootFS全部內(nèi)容轉(zhuǎn)存到準(zhǔn)備好的空目錄當(dāng)中。比較奇怪的是,在博客文章中有以下描述:
這里必須使用mv來代替復(fù)制,如果使用cp命令會丟失文件的suid導(dǎo)致sudo等功能報廢
我大致能理解作者的用意了,這里所說的“丟失suid導(dǎo)致sudo不能正常使用”,指的是在QEMU模擬樹莓派環(huán)境中無法正常使用,所以在實際操作中選擇了遵從原文以驗證結(jié)果。那么我之所以覺得奇怪是因為當(dāng)初在掛載鏡像的時候選擇了只讀模式,mv一般是用作重命名或移動文件內(nèi)容,雖然最終結(jié)果是驗證通過的,但邏輯上多少有點(diǎn)別扭(強(qiáng)迫癥害死人!??)。
于是待整個實驗結(jié)束后,我重新驗證了cp結(jié)果,稍做調(diào)整能夠保留文件原始屬性,讓sudo等功能正常使用,選項參數(shù)的具體含義可自行查閱:
*? 2> /dev/null 是重定向錯誤輸出信息到“設(shè)備黑洞”,忽略錯誤信息在屏幕上輸出的意思,可選
耐心等待文件轉(zhuǎn)存完畢之后,根據(jù)自己的實際情況卸載并解綁loop設(shè)備。至于本項第2條命令以及之后刪除鏡像文件,普通人隨意,強(qiáng)迫癥必備:
至此,在宿主機(jī)上的準(zhǔn)備工作已全部準(zhǔn)備完畢,可以起身去喝杯養(yǎng)身茶稍作休息了(正在播放 飲茶哥.mp3)
》》》 o(*^▽^*)┛ 《《《
書接上文,在正式進(jìn)入QEMU模擬aarch64環(huán)境的容器之前,當(dāng)然需要在宿主機(jī)上啟動容器了(廢話),這也是最后一條需要在宿主機(jī)中執(zhí)行的操作,之后如果沒有特別提醒,全部是在容器中完成。博客原文如下:
#可以使用快捷鍵ctrl+a+d暫時離開
#可以使用命令screen -r build重新回到控制臺
screen -S build systemd-nspawn -D rpi-env --hostname=raspberrypi --user=pi
這條命令可以拆分成兩段來看,前半段是screen -S build,使用多重視窗管理工具創(chuàng)建了一個名為build的作業(yè)視窗,文章博主使用的是遠(yuǎn)程連接到云服務(wù)器進(jìn)行編譯,誰也不想在編譯中途因為意外斷開連接而重新來過對吧?后半段才是啟用容器的執(zhí)行操作,雖然是進(jìn)入到作業(yè)視窗之后執(zhí)行的操作,但此時依舊是在宿主機(jī)環(huán)境中,只有等容器完全啟用后,才算是真正意義上進(jìn)入到容器模擬的環(huán)境中。如果你是遠(yuǎn)程連接或者想要在編譯的同時執(zhí)行其他工作的話,建議加上screen,否則可以直接執(zhí)行:
具體含義不用我解釋,基本都能猜到。不出意外的話出現(xiàn)以下內(nèi)容則說明成功啟用容器并進(jìn)入到模擬環(huán)境中。

按照流程接下來是更新軟件源,然后獲取相關(guān)的軟件依賴庫、工具包,不過博主開篇有提示說在執(zhí)行這一步操作時國內(nèi)的網(wǎng)絡(luò)會比較糟心:
推薦在境外服務(wù)器進(jìn)行編譯,國內(nèi)由于網(wǎng)絡(luò)問題非常蛋疼
非常貼心的提醒,事實證明也是如此。所以有多余閑錢的話,還是租個綜合性能不錯的境外服務(wù)器耍耍比較好,如果跟我一樣家境貧寒的話建議考慮換源。雖然這是個模擬出來的aarch64平臺環(huán)境,但好歹也是用了樹莓派系統(tǒng)的RootFS,所有的操作是依靠arm轉(zhuǎn)譯給宿主機(jī)內(nèi)核執(zhí)行的(就是這個轉(zhuǎn)譯效率確實挺感人的),理論上和在真實的樹莓派系統(tǒng)環(huán)境下沒多大差別。按照給樹莓派換源的步驟操作就行,沒多大難度。
以我實際操作為例全部替換為中國科技大學(xué)的鏡像源,注意需要修改兩個軟件源文件,特別是raspi.list中的內(nèi)容一定要修改成對應(yīng)的國內(nèi)鏡像源(不然你會后悔的,很多樹莓派專有的軟件依賴包都要根據(jù)這個源獲取):

另外,中科大鏡像站里面有關(guān)Debian軟件源配置的幫助文檔中提供了一個非常好用的工具,能夠快速根據(jù)自己的發(fā)行版本生成相應(yīng)的軟件源配置內(nèi)容:


換完軟件源之后,正常執(zhí)行更新和獲取操作,等待時間的多少取決于你的網(wǎng)絡(luò)狀況(誰想要交叉編譯的快過來看看!至少lib打頭依賴庫和工具包都需要自己交叉編譯!。。。哦原來是我,那沒事了):
源碼編譯沒源碼包怎么行呢?前往FFmpeg的官網(wǎng)下載最新的stable版本源碼包;喜歡“追新”的同學(xué)可以下載snapshot版本,但不建議用于生產(chǎn)環(huán)境。以我的為例,下載的是代號為“Rao” FFmpeg4.4.1的穩(wěn)定版本,解壓tar.xz使用?-J?選項,解壓tar.bz2使用?-j?選項,解壓tar.gz使用?-z?選項:
進(jìn)入到源碼包根目錄之后,就可以開始進(jìn)行configure配置和編譯工作了,編譯選項配置如原文所示,--prefix是編譯好之后軟件包的安裝路徑,不用默認(rèn)配置是方便打包;如果只是需要編譯FFmpeg,繼續(xù)添加 --disable-ffprobe、--disable-ffplay 這兩個編譯選項;更多編譯選項請參考 ./configure --help:
因為需要arm轉(zhuǎn)譯執(zhí)行,所以執(zhí)行配置編譯選項這一環(huán)節(jié)會花個3~4分鐘(看你的平臺性能,就算是虛擬機(jī)建議資源配置也盡量多給一點(diǎn)),中間不報錯,最后出配置成功的結(jié)果就行。
開始編譯,-j?選項要不要加?加多少?請謹(jǐn)慎考慮,arm轉(zhuǎn)譯真的很吃CPU資源:
少女祈禱中……
等待編譯完成大概需要2~3小時(取決于你的平臺性能),如果沒其他什么事的話,建議去看一會兒番劇、一部電影或者小睡一會兒什么的。除非在編譯過程意外中斷,需要排查錯誤。。。 (╯‵□′)╯︵┻━┻
編譯并安裝完成后,前往你的prefix安裝路徑,可以先在模擬環(huán)境下測試一下編譯出來的軟件是否可用:


接下來就可以退出容器模擬環(huán)境,進(jìn)入宿主機(jī)操作了,從轉(zhuǎn)存樹莓派系統(tǒng)RootFS的文件目錄中拷貝出編譯好的安裝文件,就是prefix所指定的目錄,打包發(fā)送到樹莓派準(zhǔn)備實戰(zhàn)演示,可以用scp工具。啊,忘記說了,退出容器和多任務(wù)視窗直接執(zhí)行exit即可
》》》 \(0^◇^0)/ 《《《
當(dāng)你迫不及待地想要在樹莓派上使用剛剛編譯好的FFmpeg的時候,大概率會獲得一個錯誤提示,缺少一些必要的共享庫!解決方法也很簡單,直接回到剛剛的RootFS把需要的共享庫一個一個拷貝出來、轉(zhuǎn)存到樹莓派的/usr/lib/aarch64-linux-gnu/目錄中
當(dāng)然是先檢查一下缺少哪些共享庫,以我的實際情況為例,進(jìn)入FFmpeg軟件本體所在目錄:

然后在樹莓派上按需獲取對應(yīng)的依賴庫軟件包,和編譯的時候不同,這里我們只取所需,dev開發(fā)工具包中額外的內(nèi)容都是不需要,最小化安裝:
如果還缺少其他依賴庫,可以自行百度(找規(guī)律,特別是共享庫名稱與軟件包的聯(lián)系,應(yīng)該很容易就能總結(jié)出規(guī)律),有時候只要解決一個依賴庫可以連同解決多個,apt工具很智能。

下面正式進(jìn)入實戰(zhàn),這里準(zhǔn)備了一個時長00:01:30的視頻文件test.mp4,大小為13MB左右;樹莓派為GPU劃分的內(nèi)存大小為128MB:

首先是使用軟件解碼器和CPU進(jìn)行軟編碼,用了將近1分鐘的時間完成測試:

接下來是使用GPU硬件解碼器與編碼器進(jìn)行測試,用時大約12.5秒完成,證明編譯得到的FFmpeg能夠利用樹莓派平臺的GPU硬件加速:

終于,我們通過在非樹莓派平臺上編譯出了支持arm64系統(tǒng)、可硬件加速的FFmpeg,完結(jié)撒花! ヽ(。???)ノ?

番外篇
還記得我最開始說想要交叉編譯一個可支持樹莓派硬件加速的FFmpeg計劃嗎?試過,最后“有幸”獲得了一件失敗品! (?_?")

當(dāng)我得知要從頭交叉編譯各種依賴庫、手動配置頭文件的時候,作為初學(xué)者基本上已經(jīng)放棄了,所以只嘗試了交叉編譯其中兩個依賴庫libx264和libsdl2-2.0,在交叉編譯過程中解決的各種蜜汁報錯且不說,各種配置以及查閱文檔就讓人頭大得不得了,實在是劃不來,大家就看個樂呵吧。



雖然把玩樹莓派只是我的業(yè)余興趣,不過說到底還是自己的能力有限,第一次接觸到交叉編譯和QEMU虛擬機(jī),所以對這方面的知識積累基本沒有,本文有些地方肯定還有我個人的誤解和疏漏,歡迎有懂行的大佬批評指正。
貌似我可以學(xué)習(xí)一下QEMU,因為我感覺要發(fā)現(xiàn)新大陸了…… (???)
推薦觀看/閱讀:
https://haruto.zone/post/132
https://holmesian.org/Raspberry-Pi-optimized-FFmpeg-with-HW-Acceleration
參考資料:
https://haruto.zone/post/132
https://holmesian.org/Raspberry-Pi-optimized-FFmpeg-with-HW-Acceleration
https://ffmpeg.org/
https://mirrors.ustc.edu.cn/help/debian.html
https://mirrors.ustc.edu.cn/repogen