【Android】VirtualDisplay创建流程及原理
Android VirtualDisplay创建流程及原理
- Android DisplayManager提供了createVirtualDisplay接口,用于创建虚拟屏。虚拟屏可用于录屏(网上很多资料说这个功能),分屏幕(比如一块很长的屏幕,通过虚拟屏分出不同的区域)等等。
创建VirtualDisplay
- DisplayManager中的函数原型如下。后两个Hide的API,只有平台的应用才可以使用。
// frameworks/base/core/java/android/hardware/display/DisplayManager.java public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags) { } public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, @Nullable String uniqueId) { } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { }
- 补充一点,MediaProjection中也提供了 createVirtualDisplay这个接口,实际上也是通过调用DisplayManager实现的功能。
// frameworks/base/media/java/android/media/projection/MediaProjection.java public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { DisplayManager dm = mContext.getSystemService(DisplayManager.class); // 调用DisplayManager的接口 return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler); }
- 创建VirtualDisplay时,需要传入Surface。**VirtualDisplay上要绘制的内容,实际是通过传入的Surface显示出来的。**比如在主屏(根据物理屏,分配逻辑Display)上创建了一个SurfaceView,通过把这个SurfaceView传给VirtualDisplay。那么VirtualDisplay的 内容,实际上是在主屏的SurfaceView上显示的。下面是一段Android原生的例子。
// frameworks/base/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java private Display createVirtualDisplay() { final String displayName = "NavVirtualDisplay"; final DisplayInfo displayInfo = new DisplayInfo(); mContext.getDisplay().getDisplayInfo(displayInfo); final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); // 创建ImageReader,通过它得到一张Surface mReader = ImageReader.newInstance(displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2); assertNotNull("ImageReader must not be null", mReader); // 创建虚拟屏,传入Surface。 mVirtualDisplay = displayManager.createVirtualDisplay(displayName, displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.logicalDensityDpi, mReader.getSurface(), 0 /*flags*/); assertNotNull("virtual display must not be null", mVirtualDisplay); waitForDisplayReady(mVirtualDisplay.getDisplay().getDisplayId()); return mVirtualDisplay.getDisplay(); }
- 上面的例子中创建虚拟屏,返回Display(实际上是VirtualDislay)对象。有了Display对象,我们就可以将View绑定到这个虚拟的Display上了(绑定网上方法比较多可自行搜索)。关于Surface的创建,有很多种方法,比如通过SurfaceContron+Buffer这种方式也可以。
- VituralDisplay创建时,需要提供flag。其值定义如下,可通过 “或”将flag组合。
public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 /** * Called when the virtual display video projection has been * paused by the system or when the surface has been detached * by the application by calling setSurface(null). * The surface will not receive any more buffers while paused. */ public void onPaused() { } /** * Called when the virtual display video projection has been * resumed after having been paused. */ public void onResumed() { } /** * Called when the virtual display video projection has been * stopped by the system. It will no longer receive frames * and it will never be resumed. It is still the responsibility * of the application to release() the virtual display. */ public void onStopped() { } } return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null); } public VirtualDisplay createVirtualDisplay(@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, densityDpi); builder.setFlags(flags); if (surface != null) { builder.setSurface(surface); } return createVirtualDisplay(null /* projection */, builder.build(), callback, handler); } // TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService) /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface, int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler, @Nullable String uniqueId) { final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width, height, densityDpi); builder.setFlags(flags); if (uniqueId != null) { builder.setUniqueId(uniqueId); } if (surface != null) { builder.setSurface(surface); } return createVirtualDisplay(projection, builder.build(), callback, handler); } /** @hide */ public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection, @NonNull VirtualDisplayConfig virtualDisplayConfig, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) { // 走的这里,会调用到DisplayManagerGlobal中。 return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback, handler); } VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler); // 从MediaProjection过来的调用,这个地方非空。 IMediaProjection projectionToken = projection != null ? projection.getProjection() : null; int displayId; try { // 告知DMS创建虚拟屏,并返回DisplayID displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper, projectionToken, context.getPackageName()); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } if (displayId
- 创建VirtualDisplay时,需要传入Surface。**VirtualDisplay上要绘制的内容,实际是通过传入的Surface显示出来的。**比如在主屏(根据物理屏,分配逻辑Display)上创建了一个SurfaceView,通过把这个SurfaceView传给VirtualDisplay。那么VirtualDisplay的 内容,实际上是在主屏的SurfaceView上显示的。下面是一段Android原生的例子。
- 补充一点,MediaProjection中也提供了 createVirtualDisplay这个接口,实际上也是通过调用DisplayManager实现的功能。
- DisplayManager中的函数原型如下。后两个Hide的API,只有平台的应用才可以使用。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。
还没有评论,来说两句吧...