11

I am working on recording my screen with MediaProjection as follows

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
displayWidth = size.x;
displayHeight = size.y;

imageReader = ImageReader.newInstance(displayWidth, displayHeight, ImageFormat.JPEG, 5);

int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;

DisplayMetrics metrics = getResources().getDisplayMetrics();
int density = metrics.densityDpi;

mediaProjection.createVirtualDisplay("test", displayWidth, displayHeight, density, flags, 
      imageReader.getSurface(), null, projectionHandler);

Image image = imageReader.acquireLatestImage();
byte[] data = getDataFromImage(image);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

Problem is that captured images contains black frame like image below.

enter image description here

EDIT

The above issue can be solved with bitmap operations.

However, I am now looking for a solution that can be applied to MediaProjection or to SurfaceView of ImageReader to implement device recording.

Radu Ionescu
  • 3,462
  • 5
  • 24
  • 43
AMD
  • 1,662
  • 18
  • 39
  • Take a picture of the screen (with a second device) and compare the two. Are you losing pixels off the edge of the screen? Is the entire display represented? Is the app full screen -- does the original have a visible nav bar / notification bar? – fadden Jan 19 '16 at 19:20
  • @ fadden picture contains fullscreen view including nav bar, notif bar and represents entire display including black frame outside picture – AMD Jan 20 '16 at 04:55
  • @AMD did you give my code a try? – Radu Ionescu Jan 20 '16 at 08:26
  • What do you mean exactly by _during media projection operation_ and what _surface_ from the posted code? – Radu Ionescu Jan 21 '16 at 06:30
  • surface argument in mediaProjection.createVirtualDisplay ( imageReader.getSurface) or by any other modification with mediaProjection.createVirtualDisplay () – AMD Jan 21 '16 at 10:31
  • What are you doing with the pictures - displaying them???, saving them? You need recurrent operation? – Radu Ionescu Jan 21 '16 at 11:15
  • i need to implement device recording also and recording is also contains black frame – AMD Jan 21 '16 at 11:47
  • See my updated answer if it is what you are looking for – Radu Ionescu Jan 21 '16 at 12:33
  • 1
    https://github.com/googlesamples/android-ScreenCapture .. I dont have your full code so , Can't suggest any root cause of the issue .. but try the example in given link.. – MKJParekh Jan 21 '16 at 14:25
  • @AMD did you figure out how to remove this black stripes when recording video? – Juvi Jun 17 '17 at 15:46
  • @juvi issue is unreolved – AMD Jun 19 '17 at 08:57

3 Answers3

7

I had a similar issue. The following code exhibits this problem.

final DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

final int width = metrics.widthPixels;
final int height = metrics.heightPixels;
final int densityDpi = metrics.densityDpi;
final int MAX_IMAGES = 10;

mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, MAX_IMAGES);

mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCaptureTest",
        width, height, densityDpi,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
        mImageReader.getSurface(), null, null);

Replacing this:

getWindowManager().getDefaultDisplay().getMetrics(metrics);

With this:

getWindowManager().getDefaultDisplay().getRealMetrics(metrics);

Fixes it. The problem is that the decorations around the image corrupt the actual resolution of the screen. getMetrics() returns a height (or width in landscape) that is not accurte, and has the home, back, etc, buttons subtracted. The actual display area available for developers is (1440 x 2326... or something like that). But of course, the captured image is going to be the full 1440 X 2560 screen resolution.

MobA11y
  • 18,425
  • 3
  • 49
  • 76
4

If you do not have control over the image yourself, you can modify it by doing something like, assuming your Bitmap is called image.

Bitmap imageWithBG = Bitmap.createBitmap(image.getWidth(), image.getHeight(),image.getConfig());  // Create another image the same size
imageWithBG.eraseColor(Color.BLACK);  // set its background to white, or whatever color you want
Canvas canvas = new Canvas(imageWithBG);  // create a canvas to draw on the new image
canvas.drawBitmap(image, 0f, 0f, null); // draw old image on the background
image.recycle(); 
Uday Nayak
  • 429
  • 4
  • 20
  • i apriciate your answer but i need it during media projection like perfact capture feature, see updated question – AMD Jan 21 '16 at 05:59
1

Based on your comments I think this is what you are looking for

    Bitmap bitmap; //field
    Bitmap  croppedBitmap; // field
    Image image;// field
    Handler mHandler; //field


    new Thread() {
        @Override
        public void run() {
            Looper.prepare();
            mHandler = new Handler();
            Looper.loop();
        }
    }.start();

    imageAvailableListener = new ImageReader.OnImageAvailableListener {
    @Override
    public void onImageAvailable(ImageReader reader) {

        try {
            image = reader.acquireLatestImage();
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            Rect rect = image.getCropRect();
            croppedBitmap =  Bitmap.createBitmap(bitmap,rect.left,rect.top,rect.width(),rect.height());

            \\Do whatever here...


            image.close();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {

               if (bitmap!=null) {
                   bitmap.recycle();
               }

              if (croppedBitmap!=null) {
                   bitmap.recycle();
               }

              if (image!=null) {
                   image.close();
               }
           }
        }
    }
    imageReader.setOnImageAvailableListener(imageAvailableListener, mHandler);
Radu Ionescu
  • 3,462
  • 5
  • 24
  • 43
  • thanks i have tried your code it removes top and bottom padding but left-right padding are steal as it is and also it shows white border outside image – AMD Jan 20 '16 at 10:05
  • for recording mediarecorder.getSurface is used instead imageReader.getSurface – AMD Jan 25 '16 at 06:55
  • Any surface can be used. The camera hardware simply requires a `SurfaceView` to send data to. – Radu Ionescu Jan 25 '16 at 08:18
  • 1
    If you found the answer you can post an answer here for other people to use when they come across your post – Radu Ionescu Jan 27 '16 at 07:59