Android 4.2wifidisplay採集

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的鏈接創建嗎?

wpsCD0B.tmp

其是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使用。

3.RemoteDisplayClient : public BnRemoteDisplayClient

其與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();

}

4.供RemoteDisplay.java使用native方法

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進程當中屏幕直播模塊的狀態。如暫時直播,從新直播,關閉直播。

frameworks\av\media\libmediaplayerservice\RemoteDisplay.cpp

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的數據保存爲本地文件,主要是修改了此的初始化流程。將以前須要真正有客戶鏈接才啓動整個採集,編碼,傳輸的流程,修改成直接調用

wpsCD2C.tmp

wpsCD4C.tmp

wpsCD5C.tmp

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數據保存爲本地文件的時候,具體是須要了此類當中的代碼

wpsCD7D.tmp

2. 由start進行初始化操做,在play當中啓動。

A. 要創建起SOCKET鏈接成功,且雙方約定好傳輸多媒體格式。

wpsCD8D.tmp

建立雙向約定協議的 sender,且在PlaybackSession約定了一個AMessage與Sender進行通訊。

wpsCDAD.tmp

wpsCDBE.tmpwpsCDCF.tmpwpsCDDF.tmp

wpsCDFF.tmp

wpsCE10.tmp

wpsCE30.tmp

創建成功以後,向上層進程調用鏈接成功的通知。

【display當中的數據怎麼樣讀取與採集】

數據來源之屏幕

wpsCE41.tmp

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();

2. 虛擬顯示設備與屏幕源結合

【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

【流程打印】

相關鏈接

Android截屏淺析

http://blog.sina.com.cn/s/blog_69a04cf4010173fz.html

IGraphicBufferProducer

Android 4.4(KitKat)中的設計模式-Graphics子系統

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

Stagefright 之 Buffer傳輸流程

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 概要分析系列 (一)

http://blog.csdn.net/andyhuabing/article/details/7258113

相關文章
相關標籤/搜索