這一周過的是夠有意思的掌动,先停兩天電粗恢,然后感冒了眷射,然后項(xiàng)目出Bug了罚屋,然后發(fā)燒了脾猛,呵呵噠猛拴,趕緊只能過來寫點(diǎn)東西壓壓驚。鑒于最近正好在研究Android投屏及反像控制和Android雙開的技術(shù)原理跛溉,本周就先寫寫Android投影以及反向控制的原理了。
1 目標(biāo)
- Android投影屏幕到電腦
- 電腦端反向控制Android手機(jī)(如QQ刹勃,微信伍宦,淘寶...)
2 背景
最近在項(xiàng)目小組中遇到一件事,小組有時(shí)候需要演示demo供大家參考遇骑,當(dāng)演示Android手機(jī)投屏?xí)r势篡,就需要借助第三方軟件進(jìn)行投屏念祭,比如說360手機(jī)管家的演示功能還有一個(gè)神器Vysor(通過Google瀏覽器投屏并控制手機(jī))粱坤,但是隨之也會(huì)帶來問題,通過反編譯Vysor的Apk可以看到它是使用adb命令截屏然后通過Async網(wǎng)絡(luò)庫傳輸屏幕投影給后臺(tái)株旷,既然有網(wǎng)絡(luò)操作,如果是公司比較重要的東西齿尽,萬一第三方在后面偷偷保留了演示錄屏(我相信這些應(yīng)用應(yīng)該都不會(huì)循头,有職業(yè)操守),然后可能就會(huì)有自己去做投屏的需求。
3 預(yù)覽圖
今天寫的原理都是經(jīng)過本人實(shí)現(xiàn)過的,目前PC端已經(jīng)正常工作盒使,并且可以投屏多臺(tái)Android苞慢。Web端通過node.js websocket webrtc HTML實(shí)現(xiàn)的目前還在開發(fā)中挽放,鑒于之前沒怎么用過前端吗蚌,所以寫的比較慢。
目前測(cè)試實(shí)時(shí)投影在真實(shí)機(jī)上還可以。
PC端的動(dòng)態(tài)截圖如下陨收。
4 原理圖
5 投屏
投影屏幕,可以去傳輸圖像也可以去傳輸視頻宏悦,具體使用哪一種就去看你的需求。而投影圖像又分為通過ADB命令去截取圖像以及通過Android的ImageReader獲取圖像然后通過網(wǎng)絡(luò)傳輸兩種方式诗越,所以投屏的實(shí)現(xiàn)是有很多種的块促,你想使用哪一種都是可以的。
圖像流
現(xiàn)在的產(chǎn)品看到他們都是借助手機(jī)連線到電腦端的,通過adb直接去截取圖片屎鳍,這樣的話就會(huì)很快,如果你只是在公司內(nèi)部用貌踏,使用公司的局域網(wǎng)進(jìn)行通信我覺得也已經(jīng)夠用了,因此也可以實(shí)現(xiàn)通過網(wǎng)絡(luò)Socket直接去傳輸圖像的字節(jié)碼眷昆。但是現(xiàn)在手機(jī)分辨率可高了攘滩,因此如果你不對(duì)圖像進(jìn)行處理直接通過Socket傳輸?shù)脑捘敲磿?huì)讓PC端投屏變得很卡赖瞒,因此AndroidClient可以先對(duì)圖像進(jìn)行壓縮裁剪之后再去傳輸。
Android端這塊我是開啟了一個(gè)Service,然后通過ImageReader獲取屏幕的圖像伺通,之后對(duì)圖片進(jìn)行裁剪壓縮之后再利用Socket傳輸圖像數(shù)據(jù)信息涮帘。其中的基本代碼流程如下:
virtualDisplay = mediaProjection.createVirtualDisplay("MainScreen",width,height,dpi
,DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,imageReader.getSurface()
,null,screenHandler);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
Log.i(TAG, "call onImageAvailable");
try {
//如果有圖片那么就獲取
img = imageReader.acquireLatestImage();
if (img != null) {
//圖像處理
//send 數(shù)據(jù)
}
}
}
視頻流
起初我采用的就是圖片傳輸,后來想想其實(shí)還是有其他方案的妇多,其實(shí)可以通過獲取Android手機(jī)的屏幕視頻流通過H264進(jìn)行編碼進(jìn)行傳輸給后臺(tái)Server,這樣可以讓畫面顯示的更加流暢七问。Android Client里面有一個(gè)MediaCodec的類以及VirtualDisplay類可以去讀取Android的屏幕流饶氏,然后轉(zhuǎn)化為H264視頻流疹启。
Android端依然是開啟一個(gè)Service去獲取屏幕流籍琳,但是編碼H264時(shí)會(huì)有一個(gè)坑,就是需要你去手動(dòng)加入SPS和PPS呜达,之后才是視頻幀。此處的處理代碼如下
//1,get SPS and PPS
MediaFormat outputFormat = codec.getOutputFormat();
ByteBuffer sps = outputFormat.getByteBuffer("csd-0"); // SPS
ByteBuffer pps outputFormat.getByteBuffer("csd-1"); // PPS
//2, change ByteBuffer to byte[]
...
//3, send byte[] to server by socket
...
6 反向控制
PC端去控制手機(jī)有如下兩大塊技術(shù):
- Android通過USB數(shù)據(jù)線或者Wifi連接打開ADB,通過本地執(zhí)行ADB command
- Android手機(jī)root掉,通過Android客戶端執(zhí)行ADB command
Adb連接方式有如下兩種:
- Usb數(shù)據(jù)線
- Wifi: adb tcpip 5555, adb connect android_ip_address
PC應(yīng)用程序:
Server端的代碼主題邏輯不復(fù)雜:通過Socket接收Android 客戶端傳過來的圖像數(shù)據(jù)信息解壓縮顯示到Ui上面扭倾,當(dāng)用戶點(diǎn)擊UI時(shí)獲取鼠標(biāo)點(diǎn)擊的坐標(biāo),通過比例換算轉(zhuǎn)化成實(shí)際Android真機(jī)的坐標(biāo),之后通過ADB執(zhí)行對(duì)應(yīng)的Command命令撬槽,然后Android圖像的變化再通過Socket實(shí)時(shí)傳輸給Server端記住坐標(biāo)系變化不要忘記了,一開始我忘記了轉(zhuǎn)化坐標(biāo)結(jié)果顯示就不對(duì)。
當(dāng)然PC端也可以讀取Android Client端的H264編碼視頻流薪者,然后PC端使用FFMPEG這個(gè)庫去解碼取试,關(guān)于FFMPEG庫的相關(guān)使用瞬浓,我推薦大家去看看雷霄驊的技術(shù)博客磅叛,此人在音視頻方面給予大家很大的幫助杖爽。
Web應(yīng)用程序:
首先通過在node.js上通過socket獲取Android Client端的H264視頻流,然后通過WebSocket實(shí)時(shí)將字節(jié)數(shù)組傳輸給WebRtc精置,通過WebRtc的video標(biāo)簽去顯示脂倦,題外話:WebRtc也是個(gè)好東西,你可以基于它去做很多有意思的東西比如網(wǎng)絡(luò)視屏以及現(xiàn)在挺熱的Android直播火欧,程序員去多折騰折騰還是很有意思的企锌。之后通過js獲取鼠標(biāo)點(diǎn)擊的坐標(biāo)事件,之后的操作和PC很相似了萍鲸,都是得到命令然后執(zhí)行捌肴,然后AndroidClient再投屏圖像状知,如此循環(huán)盲再。
這大概就是屏幕投影的原理了棠笑。并不復(fù)雜洪规。關(guān)鍵你要有一顆折騰的心。最近準(zhǔn)備把Web端的這塊實(shí)現(xiàn)完了就來寫一篇雙開的原理實(shí)現(xiàn)。歡迎其他程序員一起入坑一起交流,不管你是學(xué)習(xí)Android的還是后端的還是前端開發(fā)的,都?xì)g迎大家一起交流原理思想翻具,一起學(xué)習(xí)工禾,一起進(jìn)步。
還有本人寫博客并不多癣丧,所以語法表述之類的還尚待提高厢钧,而且今天寫的時(shí)候燒還沒退頭一直很懵霞扬,還請(qǐng)見諒,歡迎大家提出其他的實(shí)現(xiàn)想法以及意見。
也喜歡你可以加入QQ群大家一起交流交流:94839608
這是我一開始寫的最基本的Android屏幕投影以及反向控制代碼,里面很多代碼都是硬編碼進(jìn)去的,可能需要你們手動(dòng)改一些IP或者通過Socket去傳輸屏幕寬高之類的,畢竟只是基本測(cè)試使用的。這是鏈接
http://download.csdn.net/detail/zhangkai1992/9809903
最近換了工作方向,我還是很喜歡Android的,不過不是我最喜歡的,不過我還是有空會(huì)去研究研究Android的。