欢迎你们关注个人微信公众号——“简静慢”,除了技术文章,我还会在里面分享一些平常的思考,欢迎一块儿交流。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 啪啪打脸了:
有读者问过我为何你写东西写得那么慢?其实答案很是简单,由于我写的东西都是我不会且感兴趣的,所以我都是边学边写,而且由于我的有一种小小的偏执,就是一个东西若是没弄懂就必须弄懂,于是就写得很慢很慢。可是请你们放心,你们可以看到的内容都是我再三确认没问题才会发表的,质量绝对是有保证的。但愿有一天,我可以在某个领域,自豪地说出那四个字:
以我为准。
最后,你们若是以为这篇文章写得还不错或者对你有帮助的话,麻烦点赞,转载,分享到你的朋友圈或者相关的技术群。谢谢你们了。