提及Minicap,不得不提到STF,STF (Smartphone Test Farm) 是一個開源的web架構應用,用戶可經過瀏覽器遠程操做Android設備、調試Android應用、在設備上進行測試,實現真正意義雲端使用、調試、測試、管理真機器。STF出現之後,國內幾個大互聯網公司也紛紛跟進效仿,出現了相似的真機調試、管理平臺,較爲知名的有騰訊Wetest、阿里MQC、百度MTC、TestIn等。可見遠程真機調試在移動研發領域的做用仍是受到了比較高的重視,也能爲公司以及用戶帶來比較直接的收益。下面是STF官方的介紹動畫。html
minicap屬於STF框架的一個工具,由STF團隊自身開發,屬於較爲核心的一部分,minicap運行於android設備端,負責設備屏幕視頻的實時採集並經過socket接口發送,github下載地址:https://github.com/openstf/minicapmicicap。minicap採集屏幕的原理很簡單:經過ndk的截屏接口不停的截屏並經過socket接口實時發送,這樣客戶端即可以獲得一序列的圖片流,圖片流合成後就成爲視頻;python
micicap由Android ndk開發,包含一個可執行的二進制文件以及一個so文件,運行minicap前,須要經過adb命令將設備對應CPU架構以及設備對應SDK版本的minicap文件拷貝到設備後,再執行。因爲github上並無上傳編譯完成後的產物,所以咱們須要自行編譯。android
編譯依賴環境:git
1)、NDK;github
2)、make;web
3)、git;shell
環境依賴較爲簡單,若是沒有NDK以及make環境的,可自行百度安裝;瀏覽器
構建過程:架構
1)、經過git下載minicamp源碼:框架
git clone https://github.com/openstf/minicap.git
2)、micicap項目還依賴於libjpeg-turbo,首先咱們須要在minicap引入libjpeg-turbo項目源碼:
git submodule init
git submodule update
3)、執行ndk-build,構建完成後,minicap編譯後的產物將會在libs目錄下找到;
ndk-build
1)、獲取設備CPU支持的ABI,minicap針對4種不一樣的ABI構建了不一樣的so文件和可執行文件,分別是:x86_64/x86/arm64-v8a/armeabi-v7a;
ABI=$(adb shell getprop ro.product.cpu.abi|tr -d'\r')
2)、拷貝對應ABI版本的文件到設備,這裏使用的是adb push;
adb push libs/$ABI/minicap /data/local/tmp/
3)、獲取設備對應的SDK版本;
SDK=$(adb shell getprop ro.build.version.sdk|tr -d'\r')
4)、只有可執行文件是不夠的,咱們還須要拷貝對應sdk版本的共享庫到設備;
adb push jni/minicap-shared/aosp/libs/android-$SDK/$ABI/minicap.so /data/local/tmp/
5)、每次啓動minicap,咱們都須要設置LD_LIBRARY_PATH,否則會提示找不到公共庫,-P後面的參數爲:{RealWidth}x{RealHeight}@{VirtualWidth}x{VirtualHeight}/{Orientation},能夠指定採集的實際大小、虛擬大小以及屏幕方向,實際大小通常設置成設備物理分辨率大小,虛擬大小是經過socket接口發送的大小,屏幕實際窗口大小咱們能夠經過adb命令獲取;
adb shell dumpsys window | grep -Eo 'init=\d+x\d+' | head -1 | cut -d= -f 2
6)、啓動minicap,下面咱們假設獲取到的實際屏幕大小是1080x1920,須要發送的虛擬窗口大小是540x960,採集的屏幕方向是縱向;
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1080x1920@1080x1920/0
7)、端口轉發,經過adb forward命令,能夠把minicap端口映射到咱們PC指定的端口,localabstract:minicap是UNIX域名的SOCKET名稱,把minicap的socket端口映射到PC的1313端口,這樣咱們就能夠在PC經過鏈接1313端口獲取到設備的實時視頻流;
adb forward tcp:1313 localabstract:minicap
minicap啓動並用adb forward命令映射端口後,咱們就能夠經過socket與minicap創建鏈接。
1)、Global header
minicap協議是一種簡單的二進制流推送流協議,一旦與minicap創建鏈接,minicap首先會推送長度爲24字節的global header,global header只會推送一次,後續推送的數據不會再包括global header,而是不斷的推送實時圖片流數據,直到客戶端關閉socket鏈接。
Global header說包含了基本的一些信息,如minicap的版本信息、頭長度、實際大小以及虛擬大小、設備方向等,這些信息咱們能夠保存起來,方便後面使用,這裏我使用python解析了Global header,代碼參考以下:
2)、Frame binary format
接下來,minicap會不斷的推送一幀一幀的圖片流,每一幀都包含兩部分信息:0-3字節,表示這一幀圖片的長度n,由4個字節的32位整型小端格式存儲;4-(n+4)字節,是具體的圖片數據,由JPG格式存儲,這部分纔是咱們想要的最關鍵數據;
至此,咱們完成了minicap協議的解析,並獲取到了minicap推送過來的每一幀圖片。須要注意的是,因爲minicap是實時推送流,所以流的數據可能會比較大,客戶端獲取的buffer須要儘量的大,否則咱們在渲染每一幀的時候,可能會出現卡頓的現象,具體多大合適,咱們能夠稍微推算一下,一張由minicap推送過來的1080x1920大小的png圖片,大概是100-200KB,minicap宣稱幀率能夠達到20 FPS左右,所以咱們的buffer能夠設置爲:200KB * 20 = 4096000字節,每隔一秒recv()一次;
獲取到圖片流數據後,咱們可使用PyQt中的paintEvent進行渲染,下面的refreshFrame()方法,關聯了獲取圖片線程中的一個信號槽,一旦獲取圖片線程從minicap解析到一幀的圖片,便會通知refreshFrame()中的self.update()方法,self.update()方法則會調用paintEvent進行界面的刷新: