Reputation: 13
I have been working to capture images of the phone screen using ImageReader. The JPEG's I am receiving are not valid. With this setting:
ImageReader mImageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 10);
I get this in onImageAvailable:
W/AndroidMediaUtils: Image_getBlobSize: No JPEG/HEIC header detected, defaulting to size=width=2662272
2022-01-26 11:23:36.495 22708-22857/com.artistol.phonekast D/skia: --- Failed to create image decoder with message 'unimplemented'
If I try to extract a bitmap, the bitmap is null:
ByteBuffer myBuffer = image.getPlanes()[0].getBuffer();
myBuffer.rewind();
int mySize = myBuffer.remaining();
frame = new byte[mySize];
myBuffer.get(frame, 0, mySize);
final Bitmap bitmap = BitmapFactory.decodeByteArray(frame, 0, frame.length);
if (bitmap==null)
Log.d(TAG, "bitmap is null");
If I set things such that the height != width, I will see the following exception:
2022-01-26 11:30:29.251 23141-23194/com.name.subname A/AndroidMediaUtils: RGBA override BLOB format buffer should have height == width
2022-01-26 11:30:29.376 23141-23194/com.name.subname A/my_process: runtime.cc:655] Runtime aborting...
runtime.cc:655] Dumping all threads without mutator lock held
runtime.cc:655] All threads:
runtime.cc:655] DALVIK THREADS (27):
runtime.cc:655] "com.name.subname.MyService" prio=5 tid=23 Runnable
runtime.cc:655] | group="" sCount=0 dsCount=0 flags=0 obj=0x12e4cce8 self=0xb40000773250af00
runtime.cc:655] | sysTid=23194 nice=0 cgrp=default sched=0/0 handle=0x75b062bcc0
runtime.cc:655] | state=R schedstat=( 5329217 1502500 2 ) utm=0 stm=0 core=7 HZ=100
runtime.cc:655] | stack=0x75b0528000-0x75b052a000 stackSize=1043KB
runtime.cc:655] | held mutexes= "abort lock" "mutator lock"(shared held)
runtime.cc:655] native: #00 pc 000000000049ee3c /apex/com.android.art/lib64/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+140)
runtime.cc:655] native: #01 pc 00000000005abff8 /apex/com.android.art/lib64/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool, BacktraceMap*, bool) const+376)
runtime.cc:655] native: #02 pc 00000000005c9130 /apex/com.android.art/lib64/libart.so (art::DumpCheckpoint::Run(art::Thread*)+924)
runtime.cc:655] native: #03 pc 00000000005c3070 /apex/com.android.art/lib64/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+528)
runtime.cc:655] native: #04 pc 00000000005c223c /apex/com.android.art/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, bool)+1920)
runtime.cc:655] native: #05 pc 000000000055cec4 /apex/com.android.art/lib64/libart.so (art::Runtime::Abort(char const*)+1864)
runtime.cc:655] native: #06 pc 0000000000013978 /system/lib64/libbase.so (android::base::SetAborter(std::__1::function<void (char const*)>&&)::$_3::__invoke(char const*)+76)
runtime.cc:655] native: #07 pc 0000000000006e18 /system/lib64/liblog.so (__android_log_assert+336)
runtime.cc:655] native: #08 pc 0000000000001644 /system/lib64/libmedia_jni_utils.so (android::getLockedImageInfo(android::CpuConsumer::LockedBuffer*, int, int, unsigned char**, unsigned int*, int*, int*)+1284)
runtime.cc:655] native: #09 pc 000000000003c66c /system/lib64/libmedia_jni.so (Image_createSurfacePlanes(_JNIEnv*, _jobject*, int, int)+616)
runtime.cc:655] at android.media.ImageReader$SurfaceImage.nativeCreatePlanes(Native method)
runtime.cc:655] - locked <0x004f434f> (a android.media.ImageReader$SurfaceImage)
runtime.cc:655] at android.media.ImageReader$SurfaceImage.getPlanes(ImageReader.java:912)
runtime.cc:655] at com.name.subname.MyService.processImage(MyService.java:341)
runtime.cc:655] at com.name.subname.MyService.access$600(MyService.java:60)
runtime.cc:655] at com.name.subname.MyService$2.onImageAvailable(MyService.java:293)
I have spent considerable time looking at this. I have experimented with changing my ImageReader setting to produce formats other than JPEG. Each time I get an exception such as the following when I use ImageFormat.FLEX_RGBA_8888 instead of ImageFormat.JPEG:
java.lang.UnsupportedOperationException: Invalid format specified 42
at android.media.ImageUtils.getNumPlanesForFormat(ImageUtils.java:73)
at android.media.ImageReader.<init>(ImageReader.java:274)
at android.media.ImageReader.newInstance(ImageReader.java:135)
I see that ImageFormat.FLEX_RGBA_8888 is defined as 0x29 (42) in ImageFormat.java. I reviewed ImageUtils.java code I found here:
Indeed FLEX_RGBA_8888 is not one of the codes that getNumPlanesForFormat recognizes, so I can see why this is being rejected. I am an Android novice and could be missing the obvious, but why would ImageFormat provide values that are rejected by ImageReader? Put another way, if I enter some of the codes I see as valid in the ImageUtils case statement, such as PixelFormat.RGBA_8888, my code won't even compile. I'm told:
Must be one of: ImageFormat.UNKNOWN, ImageFormat.RGB_565, ImageFormat.YV12, ImageFormat.Y8, ImageFormat.NV16, ImageFormat.NV21, ImageFormat.YUY2, ImageFormat.JPEG, ImageFormat.DEPTH_JPEG, ImageFormat.YUV_420_888, ImageFormat.YUV_422_888, ImageFormat.YUV_444_888, ImageFormat.FLEX_RGB_888, ImageFormat.FLEX_RGBA_8888, ImageFormat.RAW_SENSOR, ImageFormat.RAW_PRIVATE, ImageFormat.RAW10, ImageFormat.RAW12, ImageFormat.DEPTH16, ImageFormat.DEPTH_POINT_CLOUD, ImageFormat.PRIVATE, ImageFormat.HEIC
Here is how I am setting things up:
ImageReader mImageReader = ImageReader.newInstance(width, height, ImageFormat.FLEX_RGBA_8888, 10);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
processImage(reader);
}
}, mImageReaderCallbackHandler);
MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mMediaProjection = mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, mIntent);
mMediaProjection.registerCallback(mMediaProjectionCallback, mMediaProjectionCallbackHandler);
mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
width, height, density,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mImageReader.getSurface(), mVirtualDisplayCallback, mVirtualDisplayCallbackHandler);
I am running this as a remote service and have been testing on a Samsung Note 8 and and Pixel 4a, both physical devices.
Edit 1:
In ImageReader's onImageAvailable, I have the following:
private void processImage(ImageReader reader){
byte[] frame;
Image image = reader.acquireLatestImage();
if(image!=null) {
ByteBuffer myBuffer = image.getPlanes()[0].getBuffer();
myBuffer.rewind();
int mySize = myBuffer.remaining();
frame = new byte[mySize];
myBuffer.get(frame, 0, mySize);
final Bitmap bitmap = BitmapFactory.decodeByteArray(frame, 0, frame.length);
if (bitmap==null)
Log.d(TAG, "bitmap is null");
image.close();
}
}
Upvotes: 0
Views: 1117