Genymobile / scrcpy

Display and control your Android device
Apache License 2.0
110.77k stars 10.62k forks source link

Android14 mirrordisplay #4848

Open chenxuanyu opened 6 months ago

chenxuanyu commented 6 months ago

Environment

Describe the bug

When creating a virtual screen in the Android system or using native methods to create a surface, Scrcpy opens with a black screen. I checked the source code of Android 14 and it seems that creating mirrordisplay is required. Scrcpy did not cause a black screen due to this operation. Please help confirm. Thank you

rom1v commented 6 months ago

I'm not sure to understand.

Scrcpy did not cause a black screen due to this operation.

Could you please post some commit/patch to show what you changed?

chenxuanyu commented 6 months ago

in Scrcpy server code, does mirror mian display in android 14,so it show black screen. should use SurfaceComposerClient call mirrorDisplay function. and setLayerStack for the mirror screen

rom1v commented 6 months ago

in Scrcpy server code, does mirror mian display in android 14,so it show black screen.

Scrcpy correctly works on Android 14. It shows a black screen for windows with "secure flag" set (since Android 12, see #2129).

should use SurfaceComposerClient call mirrorDisplay function. and setLayerStack for the mirror screen

Please post a commit/patch to show what you suggest.

chenxuanyu commented 5 months ago

this is my test code: create a surface . run on main display. but not show in scrcpy

sp<SurfaceControl> surfaceControl = client->createSurface(String8("TestSurface"),
                                                              3000, 3000, PIXEL_FORMAT_RGB_565,
                                                              0);
    sp<Surface> surface = surfaceControl->getSurface();
    SurfaceComposerClient::Transaction{}
        .setLayer(surfaceControl, std::numeric_limits<int32_t>::max()).show(surfaceControl).apply();
    SurfaceComposerClient::Transaction t;
    t.setFixedTransformHint(surfaceControl, android::ui::Transform::ROT_0);
    t.setLayerStack(surfaceControl, ui::LayerStack::fromValue(0));
    t.show(surfaceControl);
    t.apply();
    ANativeWindow_Buffer outBuffer;
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    memset((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
    surface->unlockAndPost();
chenxuanyu commented 5 months ago

my suggest code is : 1、set scrcpy virtualdisplay layerStack 2、also set the layerStack to mirrordisplay sp client = SurfaceComposerClient::getDefault(); sp surface; surface = client->mirrorDisplay(maindisplayid); SurfaceComposerClient::Transaction t; t.setLayerStack(surface, ui::LayerStack::fromValue(layerStack)); t.apply();

rom1v commented 5 months ago

The screen capture code is here (in java, not in C++): https://github.com/Genymobile/scrcpy/blob/master/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java

What do you suggest to change here?

chenxuanyu commented 5 months ago
--- a/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/ScreenCapture.java
@@ -43,11 +43,15 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
virtualDisplay.release();
virtualDisplay = null;
}
     try {
         display = createDisplay();
       setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack);
       Ln.d("cxyDisplay: using SurfaceControl API layerStack:...."+layerStack);
       if(Build.VERSION.SDK_INT >=34){
           setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, device.getDisplayLayerStack());
       }else{
           setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack);
       }
       Ln.d("cxyDisplay: using mirror layerStack:"+layerStack+",current displayLayerStack:"+device.getDisplayLayerStack()+",Android:"+Build.VERSION.SDK_INT);
   } catch (Exception surfaceControlException) {
       Rect videoRect = screenInfo.getVideoSize().toRect();
       try {
@@ -106,6 +110,10 @@ public class ScreenCapture extends SurfaceCapture implements Device.RotationList
SurfaceControl.setDisplaySurface(display, surface);
SurfaceControl.setDisplayProjection(display, orientation, deviceRect, displayRect);
SurfaceControl.setDisplayLayerStack(display, layerStack);

       //mirror
       if(Build.VERSION.SDK_INT >=34) {
           SurfaceControl.mirrorMainDisplay(layerStack);
       }
   } finally {
       SurfaceControl.closeTransaction();
   }

mirrorMainDisplay use jni call SurfaceComposerClient set getDisplayLayerStack can get by android api