Android 4.2wifidisplay採集 html
1. 顯示設置display,其是最終顯示的地方,其的數據格式,其的緩存結構 java
2. Display其的數據來源,又怎麼樣操做這些Display當中的數據如截個圖,其與SurfaceFlinger有關係,在wifidisplay其的數據來源surfaceMediaSource android
3. Android平板當中其是有多個顯示設備,如平板的顯示屏,HDMI, wifidisplay. 其之間的並存的關係,每一個顯示設備又有不一樣的特色,如用戶在輸入密碼的時候,可能但願只在顯示屏上顯示,不在其餘屏幕上顯示,這就是安全性。 c++
4. 多個顯示設備則須要有一個顯示設備類,用來描述顯示設備,要一個顯示設備管理類來統一管理顯示設備的建立,刪除,數據的讀取。 設計模式
5. 多個顯示設備是並存顯示,android平板當中是有多個activity,android經過surfaceFlinger來混合,以後依次輸出到各個顯示設備當中。出於安全考慮,其應該是:先獲得顯示設備的特色,將特性輸出給surfaceflinger, surfaceflinger要求windowManagerService按要求提供activity集合,如:有安全要求,則不要將有安全特性的activity發給surfaceflinger混合。 緩存
6. 用戶層經過相應的java層接口來操做display,建立與刪除,截個圖。 安全
Android frameworks,其是有DisplayManagerService,提供用戶來操做display, 內部則是於java層向JNI,層,而後調用c++層native service,SurfaceFlinger ,此處是native的binder通訊,是JVM進程與surfaceFlinger進程之間經過binder通訊。 服務器
a) 在android當中截圖有三種方式,A,經過直接讀取framebuffer,B.經過display來截個圖,首先經過 網絡
b) ScreenshotClient screenshot; session
c) // 根據ID獲得顯示設備的操做接口,其的內部:
d) surfaceComposerClient,SurfaceFlinger,DisplayDevice,其進程之間的關係,應用進程與surfaceFlinger進程。
e) sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
f) if (display != NULL && screenshot.update(display) == NO_ERROR) {
g) base = screenshot.getPixels();//獲得display緩存的地址方式
h) w = screenshot.getWidth();
i) h = screenshot.getHeight();
j) f = screenshot.getFormat();//ARGB是888仍是565的位格式
k) size = screenshot.getSize();//緩存的大小
l) // screenshot.update其會引發surfaceFlinger來進行混屏操做。
C.仍是display,但其直接讀取surfaceflinger混合以後的數據,不會引發surfaceflinger再次混合,wifidisplay當中的surfaceMediaPlay就是讀取此當中的數據。
7.java層:
8.frameworks\base\media\java\android\media\RemoteDisplay.java
上層的核心類RemoteDisplay, Remote + Display,Remote體如今遠程,如在wifidisplay當中顯示在另外一臺機器當中。Display其是一個顯示設備。其native層的so庫與native服務是什麼。
首先查看其的JNI層代碼
frameworks\base\core\jni\android_media_RemoteDisplay.cpp,其當中有幾個類:
1. class NativeRemoteDisplayClient : public BnRemoteDisplayClient
1. 其是native層進程之間通訊的服務提供層,其被哪一個進程全部調用,應該是MediaPlayerService進程(media service)。Display怎麼樣與media service有關係呢。
流程:1.建立一個客戶端IRemoteDisplayClient,而後傳遞media service,media Service就使用這個對象與服務端通訊,主要用於將MediaService進程通知wifidisplay進程客戶端的鏈接成功,鏈接失敗,鏈接異常。
2. 此類主要是remoteDisplay創建鏈接,關閉鏈接,鏈接異常的回調。其將數據信息由native層調用JAVA層的回調接口。鏈接主要是哪一個與哪一個的鏈接,本地顯示與另外一臺機器顯示之間的鏈接嗎。鏈接的基礎是RTSP的鏈接創建嗎?
其是mediaplayerservice進程當中,當一個客戶端鏈接到wifidisplaySource充當的RTSP服務器當中,mediaplayerservice經過IRemoteDisplayClient的binder通訊機制經過上層應用進程。
3. NativeRemoteDisplay類的做用,其是原生代碼當中,在保存文件當中,並無使用些類,而是使用一個相似做用的類:NativeRemoteDisplayEx,其二者的做用均是相同的,在native層保存與mediaplayerService進程的關鍵變量,暫將變量的地址保存在java層。
2.class NativeRemoteDisplay {
3.private:
4. sp<IRemoteDisplay> mDisplay;
5. sp<NativeRemoteDisplayClient> mClient;
6.}
其包含兩個主要接口,其沒有什麼業務,只一個數據結構。
sp<IRemoteDisplay> mDisplay其是進程之間的客戶端,是哪幾個進程之間通訊,SurfaceFlinger進程,其是操做Display的客戶端接口。
sp<NativeRemoteDisplayClient> mClient其是進程之間的服務端,與media service進程之間通訊。
其爲何須要這樣一個包裝的數據結構呢?主要是爲了下面的native層處理當中建立一個C++對象,而後將此對象的地址發送到上層疊java service當中保存。
4.NativeRemoteDisplayEx與NativeRemoteDisplay的做用相同
2.NativeRemoteDisplayEx{
3. sp<IRemoteDisplay> mDisplay;
4. sp<RemoteDisplayClient> mClient;
5.}
其與NativeRemoteDisplay同樣的,其的mClient對象類型是:RemoteDisplayClient,在保存文件當中,其是使用這個對象,其的做用只是一個對象的wrapper,供上java service使用。
其與NativeRemoteDisplayClient均是用於進程之間的通訊,bind的服務提供端。其當中的鏈接成功方法:
// 當客戶端鏈接到服務器,上層應用進程經過binder接口調用surfaceFlinger進程建立一個虛擬顯示設備,根據每個鏈接顯示的要求的不一樣建立不一樣的顯示設備。
void RemoteDisplayClient::onDisplayConnected(
const sp<ISurfaceTexture> &surfaceTexture,
uint32_t width,uint32_t height,uint32_t flags) {
// 虛擬顯示設備的數據來源,其來源於surfacemediaSource
mSurfaceTexture = surfaceTexture;
// 根據是否有安全性要求,經過surfaceflinger進程建立一個顯示設備。
mDisplayBinder = mComposerClient->createDisplay(String8("foo"), false /* secure */);
// 設置顯示設備的參數
SurfaceComposerClient::openGlobalTransaction();
mComposerClient->setDisplaySurface(mDisplayBinder, mSurfaceTexture);
//Rect layerStackRect(1280, 720); // XXX fix this.
Rect layerStackRect(width, height); // XXX fix this.
//Rect displayRect(1280, 720);
Rect displayRect(width, height);
mComposerClient->setDisplayProjection(
mDisplayBinder, 0 /* 0 degree rotation */,
layerStackRect,
displayRect);
SurfaceComposerClient::closeGlobalTransaction();
}
nativeStartRecord:
static jint nativeStartRecord(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
ScopedUtfChars iface(env, ifaceStr);
ALOGI("### nativeStartRecord ###");
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service =
interface_cast<IMediaPlayerService>(binder);
CHECK(service.get() != NULL);
// 音頻策略起用remote submix方案
enableAudioSubmix(true /* enable */);
// 建立一個網絡鏈接狀態接口的回調,其是mediaserviceplay進程調用上層應用進程。
sp<RemoteDisplayClient> client = new RemoteDisplayClient(env, remoteDisplayObj);
// 經過調用mediaserviceplay進程建立一個remoteDisplay對象,其集成了屏幕採集,語音採集,音視頻單獨格式編碼壓縮,再按時間同步合成TS數據流,創建網絡鏈接通訊的基礎,利用網絡鏈接發送到客戶端,或保存到本地文件當中,因此其本質是一個流媒體播放器,也就解釋了remotedisplay其的代碼是frameworks\av\media\libmediaplayerservice路徑當中。這個是多媒體播放器的目錄:在流媒體錄製與播放,本地多媒體的錄製與播放器。
注意remoteDisplay其並非真正的在surfaceflinger進程當中建立了一個虛擬顯示設備,RemoteDisplayClient::onDisplayConnected當中完成的建立一個虛擬顯示設備,而remoteDisplay其只是建立一個多媒體播放器。
結論:一臺android設備當中的相關進程關係
1. 上層java進程,如Setting進程,錄屏幕進程
2. 多媒體進程,mediaplayerservice進程,其建立一個流媒體屏幕錄製直播對象
3. 顯示進程,surfaceflinger進程,其建立一個虛擬顯示設備
// 經過mediaplayerservice進程建立一個流媒體屏幕錄製直播模塊對象
sp<IRemoteDisplay>display=service->listenForRemoteDisplay(client,String8(iface.c_str()));
// 將兩個進程之間的bind接口保存起來。
NativeRemoteDisplayEx* wrapper = new NativeRemoteDisplayEx(display, client);
// 返回給java保存
return reinterpret_cast<jint>(wrapper);
}
nativePauseRecord
nativeResumeRecord,nativeStopRecord.
其均是控制mediaplayerservice進程當中屏幕直播模塊的狀態。如暫時直播,從新直播,關閉直播。
RemoteDisplay其是核心當中的核心,其處於libmediaplayerservice.so庫,其處於的進程是
Mediaplayerservice進程。其的做用:流媒體屏幕直播模塊,在此框架當中其應該有的部件:
1. 網絡通訊框架,負責建立服務器,負責接受客戶端的socket鏈接,管理全部的客戶端socket數據接收與發送,這是一個線程
2. 單獨一個直播源的數據發送與命令控制
3. 採集數據模塊,有視頻採集模塊,語音採集模塊。這是一個線程
4. 數據壓縮模塊:將各類多媒體數據壓縮如視頻壓縮成h264,語音壓縮成AAC,這是一個線程
5. 多媒體數據合成模塊:將多媒體數據按時間同步的方法合成爲ts數據流,這是一個線程
6. 將多媒體數據按網絡數據合成發送:在網絡當中發送,以RTP協議格式經過socket發送到客戶端。
注意:全部這些部件均在同一個進程當中,線程之間通訊使用ALooper,AHandle,AMessager所組成的異步通訊框架,其相似於android java層的looper, handler,Message
1. RemoteDisplay
屏幕流媒體直播服務器的入口,
a.建立了網絡通訊框架ANetworkSession,總體的業務框架WifiDisplaySource等對象。
b.繼承了BnRemoteDisplay對象,負責上層進程與屏幕流媒體直播服務器進程的狀態控制。
2.ANetworkSession
網絡通訊框架,負責建立服務器,負責接受客戶端的socket鏈接,管理全部的客戶端socket數據接收與發送,這是一個線程當中,不斷的接收客戶端的鏈接,不斷的管理全部客戶端的業務數據的發送與接收。全部客戶端鏈接socket模型是select方式,沒有一個鏈接一個線程,也沒有使用epoll,因此其一個線程就搞定了。
其的類有:
A. ANetworkSession:負責建立服務器監控鏈接,管理全部session
B. NetworkThread:其繼承一個thread就是一個線程,在線程回調方法threadLoop當中,調用ANetworkSession.threadLoop方法來接收客戶端鏈接與客戶端數據的讀取與發送。
C. Session:負責與一個客戶端的數據讀取與發送。
3.WifiDisplaySource
各類業務的管理類,直播器的狀態具體控制。將狀態反饋到上層進程當中。
A. 調用onSetupRequestEx模擬一個客戶端的鏈接,建立一個PlaybackSession,且傳遞其一個AMessage(kWhatPlaybackSessionNotify, id())給PlaybackSession,用於PlaybackSession異步地將消息傳遞給wifiDisplaySource,調用PlaybackSession::initEx()方法,在改造將wifidisplay的數據保存爲本地文件,主要是修改了此的初始化流程。將以前須要真正有客戶鏈接才啓動整個採集,編碼,傳輸的流程,修改成直接調用
B. 調用PlaybackSession::initEx()方法,肯定視頻採集者:SurfaceMediaSource其是原始數據,RepeaterSource:以固定採集頻率從SurfaceMediaSource當中讀取數據,音頻的流程也相似。
C. 在音頻,視頻數據採集者的基礎之上,統一出一個公共類以統一的接口爲上層服務,
MediaPuller具體將音視頻數據格式從MediaBuffer統一封裝成ABuffer。
D. 對於從MediaPuller當中讀取過來的數據須要進行壓縮編碼(codec),Converter具體負責對於音視頻數據編碼,而後將結果以Message:kWhatConverterNotify發送給PlaybackSession,音頻的流程也相似,Converter轉換以後的數據,已是裸數據,如裸H264,AAC,咱們就是直接在此處將數據經過LocalSocket發送到上層進程當中。
E. 將採集MediaPuller與編碼Converter封裝到統一的Track結構當中,方便上層處理,視頻數據一個Track,音頻數據一個Track.上層在將Track合成Ts數據流的時候很方便。此過程:Converter編碼數據以後,發送消息給WifiDisplaySource,WifiDisplaySource根據數據類型調用相應的Track,判斷是否須要HDCP加密,根據音視頻數據時間同步要求,最終數據調用Sender經過socket發送數據到另外一臺機器的客戶端上面。
F. 對於TS數據在網絡上面傳遞,雙向須要約定網絡傳輸協議,在Sender當中具體實現,其是使用RTSP/RTP協議,咱們在將TS數據保存爲本地文件的時候,具體是須要了此類當中的代碼
2. 由start進行初始化操做,在play當中啓動。
A. 要創建起SOCKET鏈接成功,且雙方約定好傳輸多媒體格式。
建立雙向約定協議的 sender,且在PlaybackSession約定了一個AMessage與Sender進行通訊。
創建成功以後,向上層進程調用鏈接成功的通知。
SurfaceMediaSource其至關於fremebuffer,其的讀取與寫入須要surfaceflinger實時地將混合的圖片數據寫入到虛擬顯示設備當中,但如今尚未建立虛擬顯示設備,簡單地建立一個SurfaceMediaSource是沒有做用的,其須要surfaceflinger實時將混合的界面數據寫入到SurfaceMediaSource當中。
A.建立一個虛擬顯示設備
mDisplayBinder = mComposerClient->createDisplay(String8("foo"), false /* secure */);
B.虛擬顯示設備與surface相關,surface的兩個buffer與虛擬顯示設備關聯,當surfaceflinger實時地將混合的界面數據寫入虛擬顯示設備當中,其本質就是寫了surface的buffer當中,因此用戶只要讀取surface當中的數據就是讀取屏幕當中的數據,也解決了爲何讀取一個虛擬顯示設備的display不會影響平板性能,而讀取主顯示設備會影響平板性能。由於虛擬顯示設備其讀取surfaceflinger混合以後的數據,而主顯示設備會觸發surfaceflinger進行混合從而影響到了性能。
mComposerClient->setDisplaySurface(mDisplayBinder, mSurfaceTexture);
C.用戶讀取surface當中的數據
// BufferQueue是繼承BnSurfaceTexture
sp<BufferQueue> mBufferQueue;
sp<SurfaceMediaSource> source = new SurfaceMediaSource(1280, 720);
mBufferQueue = source->getBufferQueue();
【Surface系統】
直接從native層看surface層怎麼樣操做,向surfaceflinger分配空間,獲得surface的graphicbuffer的起始地址,向其中寫入數據,通知surfaceflinger進行刷新顯示。
frameworks\native\services\surfaceflinger\tests\resize.cpp做爲一個最佳的分析入口,其沒有JAVA層的activity.
進程之間的關係,上層應用進程,surfaceflinger進程,二者經過binder進行通訊。服務端有兩個binder,獲得binder服務端的接口方法:經過serviceManager對象傳入服務名稱,獲得客戶端binder接口。
A.BnSurfaceComposerClient
B.BnSurfaceComposer
SurfaceComposerClient:
其封裝了操做surfaceFlinger的方法,其不是Bn端,其組合Bn端,其最終調用Bn端來進行與surfaceFlinger通訊。Bn端是Client.
Client : public BnSurfaceComposerClient
SurfaceControl
:
Surface
SurfaceFlinger
ISurfaceComposer
1. Surface的內部管理
A. GraphicBuffer封裝了與硬件相關的操做,爲上層應用程序提供了統一的圖形內存分配接口。每個Activity的Surface須要分配一個GraphicBuffer,這些GraphicBuffer怎麼樣統一的管理,怎麼樣統一的數據讀取與寫入。
2. Surface數據的讀取
3. BufferQueue與GraphicBuffer之間的關係
WifiDisplaySource : public AHandler
有一個集成管理數據來源的管理類:採集,編碼,其也是放置在一個線程當中。
同一個線程當中,使用線程的發送與接收數據
同一個進程當中的不一樣線程,數據的發送與接收
// 生成一個AMessage的時候綁定一個線程A的id,發送給B線程,B修改此message,如放置數據,B發送此消息,經過消息框架A線程就可以接收到數據。同一個進程的不一樣線程的內存空間的共享的就能夠直接使用。
sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
notify->setInt32("playbackSessionID", playbackSessionID);
// 建立一個線程,且將此線程集成到異步通訊框架當中,可以接收異步數據
looper()->registerHandler(playbackSession);
RemoteDisplay其的做用是什麼。其的流程是什麼呢。
ANetworkSession:其是一個socket service的線程,負責循環等待客戶端鏈接,管理全部客戶端鏈接的數據讀寫。若是隻是保存文件則不須要此類的功能
WifiDisplaySource:其管理全部數據來源。
1. wifiDisplaySource調用playbackSession::initEx,建立一個PlaybackSession線程來建立一個音視頻數據來源,視頻數據來源於SurfaceMediaSource,音頻來源於AudioSource。
2. 添加視頻源SurfaceMediaSource,其是怎麼樣與顯示設備所創建關聯的,其讀取的是surfaceFlinger以後,其怎麼樣與surfaceFlinger創建關聯的。仍是以前的數據,其數據的格式與大小。
3. 須要一個類以必定的幀率在surfaceMediaSource當中讀取數據,其應該是一個線程且異步讀取數據,其使用AHandler,但其沒有繼承AHandle而是組合使用,由於其繼承了MediaSource,其就是RepeaterSource。其使用了裝飾者設計模式。
4. 須要一個類以音視頻時間同步的方式從視頻,音頻的數據提供者當中讀取數據。
5. 數據的發送:先音頻,音頻按相應格式組合,如視頻按H264,音頻按AAC,這個是Track的工做,
6. 其將音視頻數據混合且添加音視頻時間同步的信息,拼成TS數據TSPacketizer,
7. 將數據按相應的協議發送,其是Sender負責按RTSP,RTP協議發送,其利用ANetworkSession基礎設備最終發送數據。
8. SurfaceMediaSource其的數據來源最終來源於Gralloc Buffers
【流程打印】
相關鏈接
http://blog.sina.com.cn/s/blog_69a04cf4010173fz.html
http://blog.csdn.net/jinzhuojun/article/details/17427491
Android中的GraphicBuffer同步機制-Fence
http://blog.csdn.net/jinzhuojun/article/details/39698317
Android 4.4(KitKat)中的設計模式-Graphics子系統
http://blog.csdn.net/jinzhuojun/article/details/17427491
http://blog.csdn.net/ayuppie/article/details/8668462
ScreenMirror buffer ->codec編碼傳輸流程(1/3)
http://www.codes51.com/article/detail_341988.html
SurfaceFlinger GraphicBuffer內存共享緩衝區機制
http://blog.csdn.net/andyhuabing/article/details/7489776
雙方設備準備就緒後,MediaPull會經過kWhatPull消息處理不斷調用MediaSource的read函數。在SurfaceMediaSource實現的read函數中,來自SurfaceFlinger的混屏後的數據經由BufferQueue傳遞到MediaPull中
http://blog.csdn.net/innost/article/details/8474683
Android -- SurfaceFlinger 概要分析系列 (一)