Android ImageReader.acquireLatestImage 返回无效的 JPG

标签 android bitmap android-5.0-lollipop

我正在使用 Android ImageReader 类从 MediaProjection.createVirtualDisplay 方法接收位图。

到目前为止,我的代码如下所示:

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

问题是 BitmapFactory 无法将 data[] 解码回 Bitmap,即 BitmapFactory 总是返回 null。我从 logcat 看到的唯一消息来自 android_media_ImageReader.cpp 并且像这样:

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

acquireLatestImage 返回的图像对象不为空但也不是有效的 JPEG,我尝试检查以下测试但失败了:

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

目前我唯一怀疑的是我正在测试的 Android 5.0 模拟器无法处理 API 调用。

有什么想法吗?

最佳答案

@charlesjean 回答的代码有效,但我不想自己生成每个像素。从 ImageReader 获取图像的更好方法是创建大小合适的位图并使用方法 copyPixelsFromBuffer()。按如下方式创建 ImageReader:

mImageReader = ImageReader.newInstance(mWidth, mHeight, ImageFormat.RGB_565, 2);

然后您可以使用下面的代码从 mImageReader 获取图像。

final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
int offset = 0;
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * mWidth;
// create bitmap
bitmap = Bitmap.createBitmap(mWidth+rowPadding/pixelStride, mHeight, Bitmap.Config.RGB_565);
bitmap.copyPixelsFromBuffer(buffer);
image.close();

我在 blog post 中描述了使用 MediaProjection API 捕获屏幕的过程以及大多数人在从 ImageReader 获取图像时所犯的错误。如果有兴趣,您可以阅读。

关于Android ImageReader.acquireLatestImage 返回无效的 JPG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26673127/

相关文章:

java - 将 MediaProjection 虚拟显示器的输出捕获到 ImageReader 的系统错误

android - ProgressBar Circle 在 android L (API 21) 上没有显示任何进展

android - 外围设备模式下的 Nexus 9 不接受来自客户端的连接或不响应客户端请求?

java - 什么是 AsyncTask(或 AsyncResult)以及它通常如何用于 Android?

c# - 在单击位置绘制一个新的圆位图,同时保留以前绘制的圆

android - 缩放位图以适合 Canvas

android - l 预览 : Call requires API level 21 (current min is 20)

android - 如何在Android表格布局中设置表格行居中水平

java - 隐藏导航栏

c++ - 将灰度转换为Rgb