說起Minicap絮姆,不得不提到STF,STF (Smartphone Test Farm) 是一個(gè)開源的web架構(gòu)應(yīng)用,用戶可通過瀏覽器遠(yuǎn)程操作Android設(shè)備篙悯、調(diào)試Android應(yīng)用蚁阳、在設(shè)備上進(jìn)行測試,實(shí)現(xiàn)真正意義云端使用鸽照、調(diào)試螺捐、測試、管理真機(jī)器移宅。STF出現(xiàn)以后归粉,國內(nèi)幾個(gè)大互聯(lián)網(wǎng)公司也紛紛跟進(jìn)效仿,出現(xiàn)了類似的真機(jī)調(diào)試漏峰、管理平臺(tái)糠悼,較為知名的有騰訊Wetest官觅、阿里MQC谅畅、百度MTC熊锭、TestIn等翘地∶┙可見遠(yuǎn)程真機(jī)調(diào)試在移動(dòng)研發(fā)領(lǐng)域的作用還是受到了比較高的重視嘶朱,也能為公司以及用戶帶來比較直接的收益挑秉。下面是STF官方的介紹動(dòng)畫捶朵。
minicap簡介
minicap屬于STF框架的一個(gè)工具贤壁,由STF團(tuán)隊(duì)自身開發(fā)悼枢,屬于較為核心的一部分,minicap運(yùn)行于android設(shè)備端脾拆,負(fù)責(zé)設(shè)備屏幕視頻的實(shí)時(shí)采集并通過socket接口發(fā)送馒索,github下載地址:https://github.com/openstf/minicapmicicap。minicap采集屏幕的原理很簡單:通過ndk的截屏接口不停的截屏并通過socket接口實(shí)時(shí)發(fā)送名船,這樣客戶端便可以得到一序列的圖片流绰上,圖片流合成后就成為視頻;
構(gòu)建minicap
micicap由Android ndk開發(fā)渠驼,包含一個(gè)可執(zhí)行的二進(jìn)制文件以及一個(gè)so文件蜈块,運(yùn)行minicap前,需要通過adb命令將設(shè)備對應(yīng)CPU架構(gòu)以及設(shè)備對應(yīng)SDK版本的minicap文件拷貝到設(shè)備后迷扇,再執(zhí)行百揭。由于github上并沒有上傳編譯完成后的產(chǎn)物,因此我們需要自行編譯蜓席。
編譯依賴環(huán)境:
1)信峻、NDK;
2)、make瓮床;
3)、git;
環(huán)境依賴較為簡單隘庄,如果沒有NDK以及make環(huán)境的踢步,可自行百度安裝;
構(gòu)建過程:
1)丑掺、通過git下載minicamp源碼:
git clone https://github.com/openstf/minicap.git
2)获印、micicap項(xiàng)目還依賴于libjpeg-turbo,首先我們需要在minicap引入libjpeg-turbo項(xiàng)目源碼:
git submodule init
git submodule update
3)街州、執(zhí)行ndk-build兼丰,構(gòu)建完成后,minicap編譯后的產(chǎn)物將會(huì)在libs目錄下找到唆缴;
ndk-build
運(yùn)行minicap
1)鳍征、獲取設(shè)備CPU支持的ABI,minicap針對4種不同的ABI構(gòu)建了不同的so文件和可執(zhí)行文件面徽,分別是:x86_64/x86/arm64-v8a/armeabi-v7a艳丛;
ABI=$(adb shell getprop ro.product.cpu.abi|tr -d'\r')
2)、拷貝對應(yīng)ABI版本的文件到設(shè)備趟紊,這里使用的是adb push氮双;
adb push libs/$ABI/minicap /data/local/tmp/
3)、獲取設(shè)備對應(yīng)的SDK版本霎匈;
SDK=$(adb shell getprop ro.build.version.sdk|tr -d'\r')
4)戴差、只有可執(zhí)行文件是不夠的,我們還需要拷貝對應(yīng)sdk版本的共享庫到設(shè)備铛嘱;
adb push jni/minicap-shared/aosp/libs/android-$SDK/$ABI/minicap.so /data/local/tmp/
5)暖释、每次啟動(dòng)minicap,我們都需要設(shè)置LD_LIBRARY_PATH弄痹,不然會(huì)提示找不到公共庫饭入,-P后面的參數(shù)為:{RealWidth}x{RealHeight}@{VirtualWidth}x{VirtualHeight}/{Orientation},可以指定采集的實(shí)際大小肛真、虛擬大小以及屏幕方向谐丢,實(shí)際大小一般設(shè)置成設(shè)備物理分辨率大小,虛擬大小是通過socket接口發(fā)送的大小蚓让,屏幕實(shí)際窗口大小我們可以通過adb命令獲惹馈;
adb shell dumpsys window | grep -Eo 'init=\d+x\d+' | head -1 | cut -d= -f 2
6)历极、啟動(dòng)minicap窄瘟,下面我們假設(shè)獲取到的實(shí)際屏幕大小是1080x1920,需要發(fā)送的虛擬窗口大小是540x960趟卸,采集的屏幕方向是縱向蹄葱;
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1080x1920@1080x1920/0
7)氏义、端口轉(zhuǎn)發(fā),通過adb forward命令图云,可以把minicap端口映射到我們PC指定的端口惯悠,localabstract:minicap是UNIX域名的SOCKET名稱,把minicap的socket端口映射到PC的1313端口竣况,這樣我們就可以在PC通過連接1313端口獲取到設(shè)備的實(shí)時(shí)視頻流克婶;
adb forward tcp:1313 localabstract:minicap
minicap協(xié)議解析
minicap啟動(dòng)并用adb forward命令映射端口后,我們就可以通過socket與minicap建立連接丹泉。
1)情萤、Global header
minicap協(xié)議是一種簡單的二進(jìn)制流推送流協(xié)議,一旦與minicap建立連接摹恨,minicap首先會(huì)推送長度為24字節(jié)的global header筋岛,global header只會(huì)推送一次,后續(xù)推送的數(shù)據(jù)不會(huì)再包括global header睬塌,而是不斷的推送實(shí)時(shí)圖片流數(shù)據(jù)泉蝌,直到客戶端關(guān)閉socket連接。
Global header說包含了基本的一些信息揩晴,如minicap的版本信息勋陪、頭長度、實(shí)際大小以及虛擬大小硫兰、設(shè)備方向等诅愚,這些信息我們可以保存起來,方便后面使用劫映,這里我使用python解析了Global header违孝,代碼參考如下:
2)、Frame binary format
接下來泳赋,minicap會(huì)不斷的推送一幀一幀的圖片流雌桑,每一幀都包含兩部分信息:0-3字節(jié),表示這一幀圖片的長度n祖今,由4個(gè)字節(jié)的32位整型小端格式存儲(chǔ)校坑;4-(n+4)字節(jié),是具體的圖片數(shù)據(jù)千诬,由JPG格式存儲(chǔ)耍目,這部分才是我們想要的最關(guān)鍵數(shù)據(jù);
至此徐绑,我們完成了minicap協(xié)議的解析邪驮,并獲取到了minicap推送過來的每一幀圖片。需要注意的是傲茄,由于minicap是實(shí)時(shí)推送流毅访,因此流的數(shù)據(jù)可能會(huì)比較大沮榜,客戶端獲取的buffer需要盡可能的大,不然我們在渲染每一幀的時(shí)候喻粹,可能會(huì)出現(xiàn)卡頓的現(xiàn)象敞映,具體多大合適,我們可以稍微推算一下磷斧,一張由minicap推送過來的1080x1920大小的png圖片,大概是100-200KB捷犹,minicap宣稱幀率可以達(dá)到20 FPS左右弛饭,因此我們的buffer可以設(shè)置為:200KB * 20 = 4096000字節(jié),每隔一秒recv()一次萍歉;
PyQt實(shí)時(shí)渲染
獲取到圖片流數(shù)據(jù)后侣颂,我們可以使用PyQt中的paintEvent進(jìn)行渲染,下面的refreshFrame()方法枪孩,關(guān)聯(lián)了獲取圖片線程中的一個(gè)信號槽憔晒,一旦獲取圖片線程從minicap解析到一幀的圖片,便會(huì)通知refreshFrame()中的self.update()方法蔑舞,self.update()方法則會(huì)調(diào)用paintEvent進(jìn)行界面的刷新: