I am using Android ImageReader class to receive Bitmaps from MediaProjection.createVirtualDisplay method.
My code so far looks like this:
mProjection.createVirtualDisplay("test", width, height, density, flags, mImageReader.getSurface(), new VirtualDisplayCallback(), mHandler);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = mImageReader.acquireLatestImage();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
final byte[] data = new byte[buffer.capacity()];
buffer.get(data);
final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (bitmap==null)
Log.e(TAG, "bitmap is null");
} catch (Exception e) {
if (image!=null)
image.close();
}
}
}, mHandler);
The problem is that BitmapFactory cannot decode data[] back to Bitmap, i.e. BitmapFactory always returns null. The only messages I see from logcat come from android_media_ImageReader.cpp and go like this:
D/ImageReader_JNI(1432): ImageReader_imageSetup: Receiving JPEG in HAL_PIXEL_FORMAT_RGBA_8888 buffer.
W/ImageReader_JNI(1432): Image_getJpegSize: No JPEG header detected, defaulting to size=width=3891200
Image object returned by acquireLatestImage is not null but not a valid JPEG either, I tried to check with the following test which fails:
if((buf [0] & 0xFF) == 0xFF && (buf[1] & 0xFF) == 0xD8 && (buf[2] & 0xFF) == 0xFF && (buf[3] & 0xFF) == 0xE0)
Log.e(TAG, "is JPG");
else
Log.e(TAG, "not a valid JPG");
The only think I am suspecting at the moment is that Android 5.0 emulator I am testing against cannot hanlde the API calls.
Any ideas?
I encountered exactly your problem. My ImageReader created as so:
The ImageReader above should only return compressed images, and these need to be decompressed. I acquireLatestImage(), then pass it through the following:
The key for me was to rewind the ByteBuffer. Your code should work as so:
I don't like having to copy the ByteBuffer through an intermediate byte[], but the internal array is protected.
Tested working on 5.0.1 on an HTC
I tried to use many example code. But none of those codes are working. I mixed those codes myself. And I created working sample code.
In case someone else stumbles on this, working code is as follows:
As you see I am saving the bitmap captured from ImageReader to a fileoutput stream and this produces a valid jpeg file.
The messages I was getting back from android_media_ImageReader.cpp were not indicating any sort of misbehaviour.
Hope it helps someone in the future!
I tested the code of the first answer, but unfortunately it does not work on real device. I make some investigation and the following code solved my problem:
The code in answer by @charlesjean works but I would rather not generate each pixel by my self. A better way to get the Image from ImageReader is just to create right sized bitmap and use the method copyPixelsFromBuffer(). Create ImageReader as follows:
Then you can get the image from mImageReader using the code below.
I have described the process of capturing screen using MediaProjection API along with the mistakes most people made when getting image from ImageReader in a blog post which you can read if interested.