Android capture screen for ImageReader surface

I am currently looking into the code of one gitub ScreenCapture project that can capture a screen and show an image as a surface, here is the project https://github.com/Charlesjean/android-ScreenCapture . I tried to replace the SurfaceView with the surface of the ImageReader with the code below:

 mImgReader = ImageReader.newInstance(mWidth, mHeight, ImageFormat.JPEG, 5);
    mSurface = mImgReader.getSurface();// mSurfaceView.getHolder().getSurface();
    mImgReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
            Log.i(TAG, "in OnImageAvailable");

        }
    }, mHandler);

      

and create VirtualDisplay like this:

mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
              mWidth, mHeight, mScreenDensity,
              DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY |
                      DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
              mSurface, new VirtualDisplay.Callback() {
                  @Override
                  public void onResumed() {
                      Log.i(TAG, "onResumed");
                      super.onResumed();
                  }

                  @Override
                  public void onPaused() {
                      Log.i(TAG, "onPaused");
                      super.onPaused();
                  }
              }, mHandler);

      

but the method is onImageAvailable

never called, does anyone have any experience with this? I couldn't figure out why this doesn't work.

+3


source to share


2 answers


Thanks Simon, I solved the problem by changing the aspect ratio to PixelFormat.RGBA_8888, but there are some other points you need to take care of when you do what I did, I am posting it here in case it helps someone in the future.

The data buffer is Image.Plane

not exactly the same as the data buffer needed for Bitmap

:
1. The image format we used to create ImageReader

is PixelFormat.RGBA_8888, so the image buffer. Plane will place R (ed) channel first, then G (reen), etc. To convert this buffer to a bitmap, we need to create a bitmap like this, bitmap = Bitmap.createBitmap(metrics,width, height, Bitmap.Config.ARGB_8888);

and the alarm buffer needs to transfer the Alpha channel first. 2. The buffer we got from Image.Plane

has a few paddings for each line, personally I think this is used by the hardware to speed up the buffer or alignment. Therefore, in order to copy this buffer, we need to discard this padding.



To understand two points, see the kick code:

 public void onImageAvailable(ImageReader reader) {
            Log.i(TAG, "in OnImageAvailable");
            FileOutputStream fos = null;
            Bitmap bitmap = null;
            Image img = null;
            try {
                img = reader.acquireLatestImage();
                if (img != null) {
                    Image.Plane[] planes = img.getPlanes();
                    if (planes[0].getBuffer() == null) {
                        return;
                    }
                    int width = img.getWidth();
                    int height = img.getHeight();
                    int pixelStride = planes[0].getPixelStride();
                    int rowStride = planes[0].getRowStride();
                    int rowPadding = rowStride - pixelStride * width;
                    byte[] newData = new byte[width * height * 4];

                    int offset = 0;
                    bitmap = Bitmap.createBitmap(metrics,width, height, Bitmap.Config.ARGB_8888);
                    ByteBuffer buffer = planes[0].getBuffer();
                    for (int i = 0; i < height; ++i) {
                        for (int j = 0; j < width; ++j) {
                            int pixel = 0;
                            pixel |= (buffer.get(offset) & 0xff) << 16;     // R
                            pixel |= (buffer.get(offset + 1) & 0xff) << 8;  // G
                            pixel |= (buffer.get(offset + 2) & 0xff);       // B
                            pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
                            bitmap.setPixel(j, i, pixel);
                            offset += pixelStride;
                        }
                        offset += rowPadding;
                    }
                    String name = "/myscreen" + count + ".png";
                    count++;
                    File file = new File(Environment.getExternalStorageDirectory(), name);
                    fos = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                    Log.i(TAG, "image saved in" + Environment.getExternalStorageDirectory() + name);
                    img.close();
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != fos) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (null != bitmap) {
                    bitmap.recycle();
                }
                if (null != img) {
                    img.close();
                }

            }
        }

      

+5


source


private void createCameraPreviewSession() {
    mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
    mCameraDevice.createCaptureSession(Arrays.asList(surface,mImageReader.getSurface()),
    new CameraCaptureSession.StateCallback() {}
}

      



-1


source







All Articles