0

我一直在努力使用 ImageReader 捕捉手机屏幕的图像。我收到的 JPEG 无效。使用此设置:

ImageReader mImageReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 10);

我在 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'

如果我尝试提取位图,则位图为空:

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");

如果我设置高度!=宽度,我将看到以下异常:

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)

我花了相当多的时间来研究这个。我已经尝试更改我的 ImageReader 设置以生成 JPEG 以外的格式。当我使用 ImageFormat.FLEX_RGBA_8888 而不是 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) 

我看到 ImageFormat.FLEX_RGBA_8888 在 ImageFormat.java 中被定义为 0x29 (42)。我查看了在这里找到的 ImageUtils.java 代码:

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

事实上 FLEX_RGBA_8888 不是 getNumPlanesForFormat 识别的代码之一,所以我可以看到为什么这被拒绝了。我是一名 Android 新手,可能会遗漏明显的内容,但为什么 ImageFormat 会提供被 ImageReader 拒绝的值?换句话说,如果我在 ImageUtils case 语句中输入一些我认为有效的代码,例如 PixelFormat.RGBA_8888,我的代码甚至不会编译。有人告诉我:

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

以下是我的设置方式:

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);

我将其作为远程服务运行,并且一直在三星 Note 8 和 Pixel 4a 上进行测试,这两种设备都是物理设备。

编辑1:

在 ImageReader 的 onImageAvailable 中,我有以下内容:

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();
        }

    }
4

0 回答 0