seanfir
seanfir

Reputation: 13

Android ImageReader - Invalid format specified 42

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:

https://cs.android.com/android/platform/superproject/+/master:frameworks/base/media/java/android/media/ImageUtils.java;l=55;bpv=1;bpt=0

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

Answers (0)

Related Questions