歡迎你們關注個人微信公衆號——「簡靜慢」,除了技術文章,我還會在裏面分享一些平常的思考,歡迎一塊兒交流。bash
前段時間 Android R 發佈了 Beta 版本,同時帶來原生用戶心心念唸的功能——錄屏,雖然這個功能在別的 Android 定製 ROM,像 MIUI,在好幾年前已經就有了。是錄屏這個功能是很難實現嗎?爲何谷歌遲遲不願在 Android 上這個功能呢?微信
再者,目前十分火爆的手機直播,大概能夠分爲兩種形式:一種是讓觀衆看到手機攝像頭拍到的內容;另外一種是讓觀衆看到手機屏幕的內容。然後者,其實能夠理解爲另一種形式的「錄屏」。app
那麼,「錄屏」在咱們平常生活中這麼常見的功能,你是否思考過,錄屏背後的原理是什麼?錄屏軟件又是怎麼獲取到屏幕的畫面內容的呢?composer
閱讀完本文,你能夠了解到:ide
- 在 App 渲染合成中的狀態與事務(State and Transaction)
- 錄屏背後的功臣——Virtual Display 的核心接口以及 SurfaceFlinger 是如何發現,處理 VirtualDisplay
- 錄屏的原理以及完整的數據流傳輸
若是你對這些內容感興趣,那就接着看下去吧。若是對這些冗長的分析感到頭疼,想要直接看到結論,能夠直接放到最後面的總結。那咱們開始吧。函數
在目前的 Android 中,支持多種屏幕(Display,後文提到的 Display 都是指以下的各類屏幕)類型:fetch
前兩種都是有具體的物理屏幕設備的,而與之相反的 Virtual Display 則沒有,是由 SurfaceFlinger 模擬出來的,一大做用就是給前面反覆提到的「錄屏」提供基礎設施。ui
前面提到錄屏背後用到的都是 VirtualDisplay,這裏分別點一下 C++ 和 Java 中與 VirtualDisplay 相關的核心接口:this
在 Android 中有一個 screenrecord
的命令,這個命令是用純 C++ 寫的,源碼路徑在:frameworks/av/cmds/screenrecord/
,經過這份谷歌官方的源碼咱們能夠一窺 native 層實現錄屏的原理(其實 Android 很早以前就支持錄屏了哈哈)。其中的核心代碼:atom
static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
const sp<IGraphicBufferProducer>& bufferProducer,
sp<IBinder>* pDisplayHandle) {
sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
String8("ScreenRecorder"), false /*secure*/);
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(dpy, bufferProducer);
......
t.apply();
複製代碼
這裏面涉及到三個最爲核心的接口:
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
return ComposerService::getComposerService()->createDisplay(displayName,
secure);
}
複製代碼
實現很是簡單,經過 Binder 調用 SurfaceFlinger 端的 createDisplay()
來建立 VirtualDisplay。而至於 SurfaceFlinger 是如何建立 VirtualDisplay 的,後面會詳細分析。
SurfaceComposerClient::Transaction::setDisplaySurface()
status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer) {
......
DisplayState& s(getDisplayState(token));
s.surface = bufferProducer;
s.what |= DisplayState::eSurfaceChanged;
return NO_ERROR;
}
複製代碼
將上面建立的 VirtualDisplay 和本地的 IGraphicBufferProducer
(Client 端經過 createBufferQueue()
能夠得到 BufferQueue 的 IGraphicBufferProducer
和 IGraphicBufferConsumer
)關聯起來。注意這裏的 DisplayState::eSurfaceChanged
,會是後面一系列流程重要的標誌位。
SurfaceComposerClient::Transaction::apply()
這個函數也很是重要,App 側的改變都須要這個函數通知給 SurfaceFlinger 側。
在後文會對三個接口作深刻的分析。
在 Android Framework 中有一個類 OverlayDisplayAdapter
,這個類是方便 Framework 開發者建立模擬輔助顯示設備,一樣也有 C++ 提到的三個核心接口。事實上,Java 端的這些接口其實都是對作了一些封裝,最終經過 JNI 調用到 native 層,最終的實現都是在 SurfaceFlinger,這裏就不過多描述,詳細能夠參考 @夕月風 大佬在簡書上的博客:《Android P 圖形顯示系統(四) Android VirtualDisplay解析》
在 frameworks/native/libs/gui/include/gui/LayerState.h
裏定義:
struct DisplayState {
enum {
eOrientationDefault = 0,
eOrientation90 = 1,
eOrientation180 = 2,
eOrientation270 = 3,
eOrientationUnchanged = 4,
eOrientationSwapMask = 0x01
};
enum {
eSurfaceChanged = 0x01,
eLayerStackChanged = 0x02,
eDisplayProjectionChanged = 0x04,
eDisplaySizeChanged = 0x08
};
DisplayState();
void merge(const DisplayState& other);
uint32_t what;
sp<IBinder> token;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack;
uint32_t orientation;
Rect viewport;
Rect frame;
uint32_t width, height;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
};
複製代碼
這個結構體是在 Client 端(即 App 側)定義的,裏面描述了 Client 端關於 Display 全部狀態的集合,包括了 Display 的方向,Display 裏 Surface 改變,LayerStack 改變等(對應了上面的 enum 變量),what
是狀態的集合,全部的狀態能夠經過 「與」 操做合併到一塊兒(仔細看上面上面的 enum 變量的值,每個狀態都佔用了十六進制的一位)。
frameworks/native/services/surfaceflinger/DisplayDevice.h
struct DisplayDeviceState {
bool isVirtual() const { return !displayId.has_value(); }
int32_t sequenceId = sNextSequenceId++;
std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
Rect viewport;
Rect frame;
uint8_t orientation = 0;
uint32_t width = 0;
uint32_t height = 0;
std::string displayName;
bool isSecure = false;
private:
static std::atomic<int32_t> sNextSequenceId;
};
複製代碼
DisplayDeviceState
是在 Server 端(即 SurfaceFlinger 側)定義的, 不光名字跟前面的 DisplayDevice
很像,內部成員也十分地相似。那麼這兩個類有什麼關係呢?
我的是這麼理解的,這兩個類實際上是 App 側和 SurfaceFlinger 側對於 Display 狀態 的不一樣表示,前面提到的 SurfaceComposerClient::Transaction::apply()
的做用一個就是將 DisplayState
傳遞給 DisplayDeviceState
,後文原理分析中會有詳細說明。
還有一個點很是重要,DisplayDeviceState
是如何區分對應的 Display 是否爲 VirtualDisplay
的呢?答案就在 displayId
的類型中 —— std::optional
。std::optional
是 C++ 17 新引入的新特性,做用是方便表示或者處理一個變量「可能爲空」的狀態,若是在之前,咱們會選擇使用相似 NULL
,null
或者 -1
這種特殊值來標記,可是如今,std::optional
給出了一種更加方便的方案,這裏不作過多的語法描述。
在 DisplayDeviceState
中的 isVirtual()
就是用來判斷該 DisplayDeviceState
對應的 Display 是否爲 VirtualDisplay,而判斷的依據就是 displayId.has_value()
, 而對於 Virtual Display 來講,是不會對其 displayId
進行賦值的,而主顯和外顯則會賦值,於是 !displayId.has_value()
爲 true,從而能夠判斷出 Display 是否爲 VirtualDisplay。
上面提到的 DisplayState
和 DisplayDeiveState
都是須要跟具體 Display 設備(無論是不是 VirtualDisplay)綁定。而 DisplayToken
就是這些 state 類型跟具體 Display 設置鏈接的橋樑。 DisplayToken
其實只是一個 IBinder
類型的變量,而且其值自己是沒有意義的,只是用來作索引罷了。
每個 VSYNC 之間, Display 或者是各個 Layer 可能都會發生不少變化,這些變化被 SurfaceFlinger 打包在一塊兒統一處理,統稱爲 Transaction——事務,在目前的 Android Q 中,上面涉及到各類 state,在 SurfaceFlinger 端被打包成以下的事務,用枚舉變量描述:
enum {
eTransactionNeeded = 0x01,
eTraversalNeeded = 0x02,
eDisplayTransactionNeeded = 0x04,
eDisplayLayerStackChanged = 0x08,
eTransactionFlushNeeded = 0x10,
eTransactionMask = 0x1f,
};
複製代碼
這些事務在 SurfaceFlinger::handleTransaction()
中被處理,而這個函數在每次 VSYNC-sf 觸發 SurfaceFlinger 合成的時候都會調用一次。這就很像古代皇帝天天上早朝通常,handleTransaction()
就像皇上身邊的那個太監喊了一聲,
"有事啓奏,無事退朝"
若是上個 VSYNC 內 Client 端有 State 的變化,那麼就會被 SurfaceFlinger 經過 handleTransaction()
知曉而且被處理,如同有大臣在底下說,
"臣有事啓奏"
而後皇帝一天忙碌的工做就開始了。
而這些事務會被統一記錄在 mTransactionFlags
這個變量中,經過 setTransactionFlags()
,peekTransactionFlags()
和 getTransactionFlags
來更新/獲取當前的 mTransactionFlags
的值:
uint32_t SurfaceFlinger::peekTransactionFlags() {
return mTransactionFlags;
}
// 注意:
// 這裏的 fetch_and() 和下面的 fetch_or(),這兩個的函數值都是修改前的 mTransactionFlags,這一點很是重要
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
return mTransactionFlags.fetch_and(~flags) & flags;
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
Scheduler::TransactionStart transactionStart) {
uint32_t old = mTransactionFlags.fetch_or(flags);
mVsyncModulator.setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
}
return old;
}
複製代碼
peekTransactionFlags()
跟 getTransactionFlags()
從函數名看都是獲取 mTransactionFlags
的值,可是其實有很大的區別。 peekTransactionFlags()
只是簡單地將當前的 mTransactionFlags
直接返回。 而 getTransactionFlags()
則否則,它表面的做用是判斷並返回當前的 mTransactionFlags
是否包含指定的 TransactionFlag(經過原來的 mTransactionFlags
跟傳進來的 flag 作**"與"**操做)。 可是 getTransactionFlags()
會將原來 mTransactionFlags
的值,修改成只包含傳進來的 TransactionFlags 的位,其他位都會置爲 0。 說句題外話,從上面的說明其實能夠看到, peekTransactionFlags()
和 getTransactionFlags()
這兩個函數的命名很是具備迷惑性,很容易帶來認知上的誤區。若是讓我來命名的話,那麼 peekTransactionFlags()
應該命名爲 getTransactionFlags()
,而 getTransactionFlags()
更加應該命名爲 checkTransactionFlags()
。
看到這你可能會很奇怪,狀態前面不是已經說了嗎?爲何又蹦出了一個 State
?其實這裏的 State
是一個新的類,而以前在 講解 fps 計算原理 提到了的 mCurrentState
和 mDrawingState
,類型就是 State
。
State
是 SurfaceFlinger
這個類裏面的一個內部類:
class State {
public:
explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
......
const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid;
LayerVector layersSortedByZ;
DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
bool colorMatrixChanged = true;
mat4 colorMatrix;
void traverseInZOrder(const LayerVector::Visitor& visitor) const;
void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
複製代碼
這個 State
類其實很是有說頭,只不過他們咱們本文的核心相關的就是裏面的 displays
成員,他是一個 <DefaultKeyedVector>
類型(Android 自定義的一個類型,與 std::map
相似),key-value 就是咱們前面都有提到的 DisplayToken
和 DisplayDeviceState
。
mCurrentState
和 mDrawingState
側重點不同:
mCurrentState
側重於 「變」,mCurrentState
表明的是當前系統最新的狀態, 任什麼時候刻發生的各類改變都會被記錄在 mCurrentState
中mDrawingState
側重於 「定」,mDrawingState
表明的是本次合成時的狀態, SurfaceFlinger 在開始合成以前須要肯定本次合成的狀態,所以每次開始合成以前,SurfaceFlinger 都會經過 SurfaceFlinger::commitTransaction()
將記錄了當前最新的狀態的 mCurrentState
與 mDrawingState
作同步前面鋪墊了這麼長,終於來到了本文的中心內容了:
無論是 Java 代碼的 SurfaceControl.createVirtualDisplay()
仍是 C++ 代碼的 SurfaceComposerClient::createDisplay()
,建立 VirtualDisplay 最終都會走到 SurfaceFlinger 的 createDisplay()
:
sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
bool secure)
{
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
// Display ID is assigned when virtual display is allocated by HWC.
DisplayDeviceState state;
state.isSecure = secure;
state.displayName = displayName;
mCurrentState.displays.add(token, state);
mInterceptor->saveDisplayCreation(state);
return token;
}
複製代碼
這個函數最重要的就是生成一個該 VirtualDisplay 的 DisplayDeviceState
和一個 DisplayToken
,而且將這個 DisplayDeviceState
增長到 mCurrentState
。
須要注意的是,此時 Virtual Display 其實尚未被真正地建立,這裏只是經過修改 mCurrentState
記錄一下狀態的改變,真正的建立流程在後面。
回過頭看一下前面核心接口部分提到的 SurfaceComposerClient::Transaction::apply()
:
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
......
sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
mDesiredPresentTime,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
listenerCallbacks);
複製代碼
這個函數最終會將 DisplayState
裏面的 DisplayToken
和 DisplayState
等內容發經過 SurfaceFlinger::setTransactionState()
傳遞給 SurfaceFlinger 端,而後通過以下調用之後:
SurfaceFlinger::setTransactionState()
\_ SurfaceFlinger::applyTransactionState()
\_ SurfaceFlinger::setDisplayStateLocked()
複製代碼
在 SurfaceFlinger::setDisplayStateLocked
中:
uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
if (index < 0) return 0;
uint32_t flags = 0;
DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);
const uint32_t what = s.what;
if (what & DisplayState::eSurfaceChanged) {
if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
state.surface = s.surface;
flags |= eDisplayTransactionNeeded;
}
}
複製代碼
將 DisplayState
中的 Surface (即 App 端建立的 BufferProducer) 傳遞給 DisplayDeviceState
,同時將 eSurfaceChanged
(回想一下前面的內容,surface
和 what
都是在 SurfaceComposerClient::Transaction::setDisplaySurface()
設置的) 轉換爲 eDisplayTransactionNeeded
。這一下,不只完成了 DisplayState
的內容傳遞到 DisplayDeviceState
,還完成了 state 轉爲 Transaction 這一偉大壯舉,SurfaceFlinger 終於瞭解到了 App 側狀態的變更。
而後回到 SurfaceFlinger::applyTransactionState()
將前面的 eDisplayTransactionNeeded
這個事務經過 SurfaceFlinger::setTransactionFlags()
保存起來,等待被處理。
前面的 eDisplayTransactionNeeded
這個事務將會在下一個 SurfaceFlinger 的合成流程中,通過以下的函數調用:
SurfaceFlinger::handleMessageTransaction()
\_ SurfaceFlinger::handleTransacion()
\_ SurfaceFlinger::handleTransactionLocked()
複製代碼
最終在 processDisplayChangesLocked()
中被處理。
首先你們思考一個問題:
❔ SurfaceFlinger 怎麼知道在上個 VSYNC 中新增或者移除了 Display 呢?
答案就是前面提到的 mDrawingState
和 mCurrentState
。mCurrentState
表明的是最新的狀態,mDrawingState
表明的是上一次合成的狀態(相對本次合成來講,在未 commitTransaction()
以前),所以假設:
mCurrentState
中的 DisplayDeviceState
中有可是在 mDrawingState
中沒有,那麼就說明在上一個 VSYNC 中新增了 DisplaymDrawingState
中的 DisplayDeviceState
中有可是在 mCurrentState
中沒有,那麼就說明在上一個 VSYNC 中有 Display 被移除了瞭解了這個之後咱們就能夠很簡單地判斷 Display 的變更了,本文的分析側重於新增 Display:
void SurfaceFlinger::processDisplayChangesLocked() {
......
// find displays that were added
// (ie: in current state but not in drawing state)
for (size_t i = 0; i < cc; i++) {
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
sp<compositionengine::DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
std::optional<DisplayId> displayId;
if (state.isVirtual()) {
if (state.surface != nullptr) {
......
// 給 VirtualDisplay 建立其 DisplaySurface —— VirtualDisplaySurface
sp<VirtualDisplaySurface> vds =
new VirtualDisplaySurface(getHwComposer(),
displayId, state.surface,
bqProducer, bqConsumer,
state.displayName);
dispSurface = vds;
producer = vds;
}
} else {
displayId = state.displayId;
LOG_ALWAYS_FATAL_IF(!displayId);
// 給 主顯/外顯 建立其 DisplaySurface —— FrameBufferSurface
dispSurface =
new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
const wp<IBinder>& displayToken = curr.keyAt(i);
if (dispSurface != nullptr) {
// 真正建立 DisplayDevice 的地方,而且加入到 mDisplays
mDisplays.emplace(displayToken,
setupNewDisplayDeviceInternal(displayToken,
displayId, state,
dispSurface, producer));
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
dispatchDisplayHotplugEvent(displayId->value, true);
}
}
}
}
複製代碼
新增 Display 內容這部份內容比較多,分爲兩部分說明(說明:剩下的內容會着重於代碼流程以及數據流轉,涉及的衆多類以及其子類會新開一篇文章詳細說明。同時下面的內容也會涉及到 CompositionEngine 這一部分的內容,也會先粗略帶過,會單開新的文章單獨說明):
前面提到,Android 支持多種 Display 類型,而每個 Display 都會有一個關聯的 Buffer,這個 Buffer 使用 DisplaySurface
這個類進行描述。不一樣類型的 Display 採用的 DisplaySurface
也不盡相同:主顯和外顯採用的是 FrameBufferSurface
,而虛顯採用的是 VirtualDisplaySurface
:
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
const std::optional<DisplayId>& displayId,
const sp<IGraphicBufferProducer>& sink,
const sp<IGraphicBufferProducer>& bqProducer,
const sp<IGraphicBufferConsumer>& bqConsumer,
const std::string& name)
......
{
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bqProducer;
複製代碼
App 側傳過來的 BufferProducer 被保存爲 VirtualDisplaySurface
裏面的 mSource[SOURCE_SINK]
,這一點很重要,後文會用到。
而後利用前面建立的 VirtualDisplaySurface
,調用 setupNewDisplayDeviceInternal()
:
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
......
auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
auto nativeWindow = nativeWindowSurface->getNativeWindow();
creationArgs.nativeWindow = nativeWindow;
......
sp<DisplayDevice> display = getFactory().createDisplayDevice(std::move(creationArgs));
.......
return display;
}
複製代碼
首先 setupNewDisplayDeviceInternal()
這個函數的 displaySurface
和 producer
這兩個參數都是前面建立的 VirtualDisplaySurface
。
接着利用前面建立的 VirtualDisplaySurface
,使用 createNativeWindowSurface()
建立一個 native window。這裏簡單說明一下 native window 這個概念:
咱們知道,OpenGL ES 是一個跨平臺的圖形 API,可是即使是跨平臺,最終也是須要在具體的平臺上落地的,落地就須要在特定的平臺系統上「本地化」——把跨平臺的 OpenGL ES 跟具體平臺中的窗口系統創建起關聯,這樣才能保證正常工做,而爲 OenGL ES 提供本地窗口(即 native window)的就是 EGL,具體到 Android 裏,native window 其實就是指
Surface
這個類,在frameworks/native/libs/gui/Surface.cpp
中定義。
而後看一下 native window 是怎麼建立的:
std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
const sp<IGraphicBufferProducer>& producer) {
class NativeWindowSurface final : public surfaceflinger::NativeWindowSurface {
public:
explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
: mSurface(new Surface(producer, /* controlledByApp */ false)) {}
~NativeWindowSurface() override = default;
sp<ANativeWindow> getNativeWindow() const override { return mSurface; }
void preallocateBuffers() override { mSurface->allocateBuffers(); }
private:
sp<Surface> mSurface;
};
return std::make_unique<NativeWindowSurface>(producer);
}
複製代碼
再看一下 Surface
的構造函數:
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
......
複製代碼
從這個構造函數能夠很清楚地看到,建立出來的 native window,即 Surface
,是將前面建立的 VirtualDisplaySurface
給 mGraphicBufferProducer
賦值的。請記住這一點,後面的數據流傳輸會用到。
而後就使用 createDisplayDevice()
建立一個 DisplayDeivce
而且添加到 mDisplays
中,VirtualDisplay 纔算真正建立完畢。
而後一切準備就緒之後,咱們終於來到最終的數據流傳輸。
每次合成的時候,SurfaceFlinger 對每一個 DisplayDevice
依次調用 doDisplayComposition()
。在 VirtualDisplay 的 doDisplayComposition()
中,會調用 dequeueBuffer()
給接下來的合成(目前看 VirtualDisplay 都是 GPU 合成)申請 Buffer,這個 dequeueBuffer()
的調用流程十分值得說道說道:
回想一下前文咱們提到,setupNewDeviceInternal()
中的 createNativeWindow()
,將 VirtualDisplaySurface
爲其成員 mGraphicBufferProducer
賦值,而在 SurfaceFlinger::dequeueBuffer()
中:
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
reqFormat, reqUsage, &mBufferAge,
enableFrameTimestamps ? &frameTimestamps
: nullptr);
複製代碼
會去調用 mGraphicBufferProducer->dequeueBuffer()
, 於是會轉而 VirtualDisplaySurface::dequeueBuffer()
:
status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
PixelFormat format, uint64_t usage,
uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
if (!mDisplayId) {
return mSource[SOURCE_SINK]->dequeueBuffer(pslot,fence, w, h, format, usage,
outBufferAge, outTimestamps);
}
......
複製代碼
回想一下前面的內容,對於 VirtualDisplay 來講,displayId 爲空,於是會直接調用 mSource[SOURCE_SINK]
的 dequeueBuffer()
,而咱們前面提到,mSource[SOURCE_SINK]
,就是 App 端傳來的 BufferProducer。
所以,最終整個 dequeueBuffer()
的調用流程以下:
RenderSurface::dequeueBuffer()
\_ Surface::hook_dequeueBuffer()
\_ Surface::dequeueBuffer()
\_ VirtualDisplaySurface::dequeueBuffer()
\_ 在這裏調用了 Client 端的 BufferProducer 的 dequeueBuffer()
複製代碼
通過一系列的 dequeueBuffer()
調用,SurfaceFlinger 最終拿到了 App 側的 BufferQueue 申請到的 Buffer,給錄屏 App 進行一次獨立的合成,並將合成的內容渲染到從 App 側拿到的 Buffer。是的,你沒有看錯,在這個場景裏,SurfaceFlinger 是內容的生產者,錄屏 App 纔是內容的消費者。最後,SurfaceFlinger 合成再經過 queueBuffer()
將渲染完的 Buffer 還給錄屏 App:
void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
const Region& inDirtyRegion) {
......
if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
// swap buffers (presentation)
display->getRenderSurface()->queueBuffer(std::move(readyFence));
複製代碼
完整的調用流程跟 dequeueBuffer()
是徹底一致,再也不贅述。
最後,App 經過 onFrameAvailable()
獲得新 Buffer 的通知,經過 acquireBuffer(()
,在這裏拿到合成完的 Buffer(即當前屏幕的內容),就能夠對該 Buffer 而後就能夠開始進行各類處理(例如編解碼等)了。至此,整個數據傳輸的完整流程就說明完畢了。
一句話總結錄屏的原理就是:
錄屏軟件經過建立一個 VirtualDisplay,而後每次 SurfaceFlinger 在作合成的時候,會對 VirtualDisplay 作一次獨立的合成,並將合成完的結果渲染到錄屏軟件傳遞過來的 Buffer。而錄屏軟件在拿到裝有當前畫面的 Buffer 之後,就能夠對 Buffer 進行進一步的處理如去作編解碼等,從而達到錄屏的目的。
而:
而這兩點,均可以用下面的這張圖來總結:
以前在分析 DisplayState
的內容是怎麼傳遞給 DisplayDeviceState
的時候卡了好久,緣由是我執拗地認爲 SurfaceFlinger::setTransactionState()
只有 Display 在初始化的時候纔會調用,而且自信地加上了以下的 debug log:
結果我就被滿屏的 simowce: I don;t believe this'll print twice or more 啪啪打臉了:
有讀者問過我爲何你寫東西寫得那麼慢?其實答案很是簡單,由於我寫的東西都是我不會且感興趣的,所以我都是邊學邊寫,而且由於我的有一種小小的偏執,就是一個東西若是沒弄懂就必須弄懂,於是就寫得很慢很慢。可是請你們放心,你們可以看到的內容都是我再三確認沒問題纔會發表的,質量絕對是有保證的。但願有一天,我可以在某個領域,自豪地說出那四個字:
以我爲準。
最後,你們若是以爲這篇文章寫得還不錯或者對你有幫助的話,麻煩點贊,轉載,分享到你的朋友圈或者相關的技術羣。謝謝你們了。