3

Is it possible to use SurfaceComposerClient to get screenshots, the way MediaCodec does with createInputSurface().

I cant use MediaCodec for that because I need raw video and not encoded data.

since 4.3 it seems that ScreenshotClient cant do multiple screenshots.

Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
jacob
  • 1,397
  • 1
  • 26
  • 53

2 Answers2

1

Yes, assuming you're running as shell or root, and you don't mind using non-public native APIs (i.e. you don't care if your app breaks every time a new version of the OS rolls out).

The canonical example is screenrecord, introduced in Android 4.4. It creates a virtual display and directs the output to a Surface. For normal operation a MediaCodec input surface receives the output. For the "bugreport" mode introduced in screenrecord v1.1, the output goes to a GLConsumer (roughly equivalent to a SurfaceTexture), which is rendered to a Surface with overlaid text.

fadden
  • 51,356
  • 5
  • 116
  • 166
  • in screenrecord 1.1 Overlay, What do I need to do to get the image raw bytes from the outputSurface (IGraphicBufferProducer) ? – jacob Jan 15 '14 at 00:20
  • In `setup_l()`, Overlay creates an EGL window surface for the IGraphicBufferProducer. That feeds into the video encoder. If you instead create a pbuffer surface, you can then use `glReadPixels()` to extract the data after the texture blit in `processFrame_l()`. – fadden Jan 15 '14 at 00:50
  • I have finally got it to work, but it slows the device terribly, unlike MediaCodec that doesn't slow at all ( and it also does encoding what should of been slower than just grab raw data, no ? ). Any way I can speed it up ? – jacob Jan 15 '14 at 15:53
  • Something I learned recently is that, if EGL isn't configured with an alpha plane, `glReadPixels(GL_RGBA)` can take an absurdly long time on certain devices (177ms vs. 6ms). In `eglSetupContext()` (or wherever you're configuring EGL for your pbuffer), below `EGL_BLUE_SIZE, 8,` add `EGL_ALPHA_SIZE, 8,` and see if that helps. – fadden Jan 15 '14 at 16:24
  • EGL_ALPHA_SIZE, 8, didnt help would you mind taking a look at my code, maybe I am doing glReadPixels() in the wong place. https://dl.dropboxusercontent.com/u/36894441/EglWindow.cpp https://dl.dropboxusercontent.com/u/36894441/Overlay.cpp – jacob Jan 15 '14 at 16:42
  • In `createWindow()`, use `mWidth` and `mHeight` in the `pbufferAttribs` so it doesn't have to scale (I suspect you're scaling the display resolution to 1280x800, then scaling it back to display res when extracting... unless you're on a device with a 1280x800 display). Before we go too far down this road, you should bracket the `glReadPixels()` call with `systemTime(CLOCK_MONOTONIC)` calls to see just how long each invocation is taking... maybe the performance problem is elsewhere. (Maybe install https://github.com/google/grafika and run the "glReadPixels speed test"?) – fadden Jan 15 '14 at 17:51
  • I am using a display of 1280x800 - nexus 7 ( hard coded just for tests ) , I added a time test around glReadPixels and got avg of 220 ms per call. perhaps I should be using a Pixel Buffer Object ? – jacob Jan 15 '14 at 18:09
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45308/discussion-between-jacob-and-fadden) – jacob Jan 15 '14 at 18:10
  • Got my Nexus 7 (2012) updated. Grafika reports ~200ms for a 1280x720 frame, consistent with your results. Ugh. – fadden Jan 15 '14 at 18:21
  • I am trying EGL_KHR_image_base with no success, can you take a look at this: http://stackoverflow.com/questions/21151259/replacing-glreadpixels-with-egl-khr-image-base-for-faster-pixel-copy – jacob Jan 17 '14 at 12:14
1

There's a bug in Android 4.3 (see issues 59649 or 60638 on the Android Open Source Project Issue Tracker) which means ScreenshotClient can't be used to take more than one screenshot.