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

2023-11-27

我正在开发一个需要将屏幕捕获为位图以进行传输的应用程序。我正在尝试使用新的 Android 5.0android.media.projection API进行屏幕捕获。

此 API 的工作流程最终会调用

mediaProjection.createVirtualDisplay("Test Screen", WIDTH, HEIGHT, DPI,
   DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, surface, null, null);

在我最初尝试进行此捕获时,我从 SurfaceView 获取了表面对象。这可以正常工作;最终结果是在屏幕上绘制的显示的微小副本(导致德罗斯特效应)

我以为这个功能已经快完成了,但是然后我发现SurfaceView(从代码的角度来看)不可读;你不能从他们那里得到位图。

在寻找其他解决方案时我遇到了这个问题它与我的目标非常相似,在该线程中它是建议使用 ImageReader 而不是 SurfaceView 来获取传递给 createVirtualDisplay API 调用的 Surface。

但是,当我更改代码以使用 ImageReader 代替 SurfaceView 时,我会收到运行时 logcat 错误(无例外),并且 ImageReader 的回调函数永远不会被调用。 createVirtualDisplay 调用还返回一个看似有效的 VirtualDisplay 对象。

这是日志猫:

9230-9270/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: createGraphicBuffer failed
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count
9230-9246/com.android.techrocket9.nanoid E/BufferQueueProducer﹕ [unnamed-9230-0] dequeueBuffer: can't dequeue multiple buffers without setting the buffer count

第二行在停止出现之前会重复大约 100 次。

在调试器上单步调试,我发现第一个错误发生在 createVirtualDisplay 调用期间,而所有其他错误都发生在执行返回到系统代码之后的某个时刻。

The 唯一有意义的结果此错误与 Kitkat 中的一个问题有关,其中我尝试使用的 API 不存在。尽管如此,我尝试了此处建议修复(推杆android:hardwareAccelerated="false"在清单中)。这并没有改变应用程序的行为。

如何“设置缓冲区计数”或以其他方式解决此错误并将屏幕显示为位图?

附:我的开发平台是 Nexus 6。

根据要求,完整的代码块:

MediaProjection mediaProjection = mgr.getMediaProjection(resultCode, data);
ImageReader ir = ImageReader.newInstance(WIDTH, HEIGHT, ImageFormat.JPEG, 5);
VirtualDisplay v = mediaProjection.createVirtualDisplay("Test Screen", WIDTH, HEIGHT, getApplicationContext().getResources().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, ir.getSurface(), null, null);

编辑:关于伪影问题,这是我用来从图像中获取位图并显示它的代码:

 public void onImageAvailable(ImageReader reader) {
        Image image = null;
        ByteArrayOutputStream bos = null;

        try {
            image = reader.acquireLatestImage();
            if (null == image){
                return;
            }
            bos = new ByteArrayOutputStream();
            final Image.Plane[] planes = image.getPlanes();
            final ByteBuffer buffer = (ByteBuffer) planes[0].getBuffer().rewind();
            final Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
            bitmap.copyPixelsFromBuffer(buffer);
            //bitmap.compress(Bitmap.CompressFormat.WEBP, 50, bos);

            runOnUiThread(new Runnable() {
                public void run() {
                    iv.setImageBitmap(bitmap);
                }
            });

我想我现在可以回答这个问题了,我遇到了同样的问题,并且在我改变之后ImageFormat.JPEG to PixelFormat.RGBA_8888一切顺利。似乎不支持 ImageFormat.JPEG。

您需要使用以下代码来获取正确的位图:

                    int width = img.getWidth();
                    int height = img.getHeight();
                    int pixelStride = planes[0].getPixelStride();
                    int rowStride = planes[0].getRowStride();
                    int rowPadding = rowStride - pixelStride * width;
                    byte[] newData = new byte[width * height * 4];

                    int offset = 0;
                    bitmap = Bitmap.createBitmap(metrics,width, height, Bitmap.Config.ARGB_8888);
                    ByteBuffer buffer = planes[0].getBuffer();
                    for (int i = 0; i < height; ++i) {
                        for (int j = 0; j < width; ++j) {
                            int pixel = 0;
                            pixel |= (buffer.get(offset) & 0xff) << 16;     // R
                            pixel |= (buffer.get(offset + 1) & 0xff) << 8;  // G
                            pixel |= (buffer.get(offset + 2) & 0xff);       // B
                            pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
                            bitmap.setPixel(j, i, pixel);
                            offset += pixelStride;
                        }
                        offset += rowPadding;
                    }

这样一来,bitmap的内容就是你想要的了。

PS:我真的想说,android的doc很糟糕。我们需要调查太多细节才能正确使用 sdk api。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 MediaProjection 虚拟显示器的输出捕获到 ImageReader 时出现系统错误 的相关文章

  • 如何消除警告:使用“$”而不是“.”对于 Eclipse 中的内部类

    我是 Android 开发新手 当我将 eclipse 和 Android SDK 更新到最新版本后 我收到警告 Use instead of for inner classes or use only lowercase letters
  • 独占锁定ConcurrentHashMap

    我知道不可能锁定 ConcurrentHashMap 进行独占访问 但是 我找不到原因 是因为构成CHM的 Segment 没有被api公开吗 据推测 如果是的话 客户端代码可以执行 交接 锁定 Cheers 我知道不可能锁定 Concur
  • android:widgetLayout 和 android:layout 之间的区别?

    我得到一些奇怪的配置 其中 widgetLayout 配置列表项的内部空间 而布局配置整个项目列表和屏幕背景 有人能真正解释一下什么是 widgetLayout 吗 android layout 整个首选项的布局 包括标题 摘要和小部件 a
  • 即使获得平台签名也无法读取系统文件

    我已经构建了一个自定义 Android ROM 我已经使用平台签名签署了我的应用程序并添加了android sharedUserId android uid system 在清单文件中 我的应用程序被授予所有 签名 和 系统 级别权限 但不
  • android 从图库中选择图像

    我想从图库创建一个图片选择器 我使用代码 intent new Intent Intent ACTION PICK android provider MediaStore Images Media EXTERNAL CONTENT URI
  • Android - 从服务器获取响应时验证 JSON 以避免 JSONException

    在我的一些与服务器通信并使用 http 获取响应的应用程序中 我使用 json 来格式化数据服务器端 当它到达设备时 我使用类似于我在 stackoverflow 上找到的代码 private class LoadData extends
  • .class 与 .java

    class 文件和 java 文件有什么区别 我正在尝试让我的小程序工作 但目前我只能在 Eclipse 中运行它 还不能嵌入 HTML 谢谢 编辑 那么如何使用 JVM 进行编译呢 class 文件是编译后的 java 文件 java 都
  • 使用外部硬盘写入和存储 mysql 数据库

    我已经设置了 mysql 数据库在我的 Mac 上使用 java 和 eclipse 运行 它运行得很好 但现在我将生成大约 43 亿行数据 这将占用大约 64GB 的数据 我存储了大量的密钥和加密值 我有一个 1TB 外部我想用作存储位置
  • 使用 IntelliJ / Android Studio 调试基于 gradle 的单元测试

    我正在使用robolectric gradle 插件 https github com robolectric robolectric gradle plugin为 Android 编写单元测试 到目前为止 除了能够使用 Android S
  • 如何在高速缓存中存储图像

    我对此完全空白 我想从 URL 下载图像 并且必须将其存储在内部 以便下次我不需要连接到网络 而是从缓存中检索它 但我不知道该怎么做 谁能帮我提供一个代码片段 import java io BufferedInputStream impor
  • 是什么原因导致“对象不是声明类的实例”? [复制]

    这个问题在这里已经有答案了 可能的重复 使用反射调用方法时 为什么会出现 对象不是声明类的实例 https stackoverflow com questions 7202988 why do i get object is not an
  • 如何计算文件中单词的长度?爪哇

    我正在尝试编写一个代码来计算文件中特定长度的单词数 例如 How are you 会打印 Proportion of 3 letter words 100 3 words 我想计算长度为 1 2 3 4 5 6 7 8 9 10 11 12
  • RMI 服务器:rmiregistry 或 LocateRegistry.createRegistry

    对于服务器端的RMI 我们需要启动吗rmiregistry程序 或者只是调用LocateRegistry createRegistry 如果两者都可以的话 各有什么优点和缺点 他们是同一件事 rmiregistry是一个单独的程序 您可以从
  • java中的比较器链

    正在阅读Oracle 关于接口的 Java 教程 https docs oracle com javase tutorial java IandI createinterface html其中给出了一个例子Card 打牌 我试图理解接口中的
  • Scala repl 抛出错误

    当我打字时scala在终端上启动 repl 它会抛出此错误 scala gt init error error while loading AnnotatedElement class file usr lib jvm java 8 ora
  • Android同步onSensorChanged?

    这是我的问题的后续 Android线程可运行性能 https stackoverflow com questions 36395440 android thread runnable performance 我在理解应用程序的同步方法时遇到
  • Java的hashCode可以为不同的字符串产生相同的值吗?

    使用java的哈希码函数是否可以为不同的字符串提供相同的哈希码 或者如果可能的话 其可能性的 是多少 Java 哈希码是 32 位 它散列的可能字符串的数量是无限的 所以是的 会发生冲突 百分比是没有意义的 项目 字符串 的数量是无限的 而
  • 如何更改焦点/按下时图像按钮的色调

    我有一个ImageButton在我的应用程序中 当按钮打开时我需要更改图像的色调pressed focused 我有ImageButton设置为获取其src来自 XML 文件 如下所示
  • 从 Android 中的过渡动画中排除 BottomNavigation

    我一直在四处寻找 但找不到有助于解决这个特定问题的答案 我的应用程序有一个自定义滑入 滑出效果 如下所示 Intent intent new Intent getApplicationContext MyActivity class sta
  • 将隐藏(生物识别)数据附加到 pdf 上的数字签名

    我想知道是否可以使用 iText 我用于签名 或 Java 中的其他工具在 pdf 上添加生物识别数据 我会更好地解释一下 在手写板上签名时 我会收集签名信息 例如笔压 签名速度等 我想将这些信息 java中的变量 与pdf上的签名一起存储

随机推荐

  • 我可以在控件内托管 Windows 窗体吗

    我有一个客户 它是一个具有有线表示逻辑的单实例模式下的 Visual Basic 项目 主窗体包含一个具有多个选项卡页的 TabControl 如果我单击 TabPage 另一个窗体会显示在窗体前面 并调整大小以与 TabPage 具有相同
  • 如何获取Oracle中每个组的最大值? [复制]

    这个问题在这里已经有答案了 我已经找到了解决此问题的一些解决方案 但是它们似乎不适用于 Oracle 我懂了 我想要一个视图只显示每个团队中最年长的人的信息 所以 我的输出应该是这样的 PERSON TEAM AGE Sam 1 23 Mi
  • 获取发送到 click.group() 子命令的参数

    如果我有一个click group 对于多个子命令 有没有办法可以将命令行参数传递给组本身内的这些子命令 我知道你可以通过context 而且我知道我可以使用callback将在命令之前执行的函数 但我不知道是否有比使用更好的方法来执行此操
  • 有没有办法在 Windows 上的链接时重新定义 malloc?

    我想在链接时替换默认的 malloc 以使用自定义 malloc 但是当我尝试在程序中重新定义 malloc 时 出现以下错误 MSVCRT lib MSVCR80 dll error LNK2005 malloc already defi
  • Azure Functions,无法加载文件或程序集

    当使用NuGet协议Azure Functions 中的 NuGet 包 出现以下错误 System Private CoreLib Could not load file or assembly 4 18 2020 8 51 43 AM
  • 根据单元格值数据按路径引用 Excel 工作簿

    我有一个 Excel 工作表 可以从其他关闭的 Excel 工作簿中提取数据 目前 当我列出关闭的工作簿的整个路径时 它工作正常 但我想使用存储在单独单元格中的变量作为路径名的一部分 例如 我正在尝试引用名为的工作簿 工作簿12 10 12
  • 在 joomla 组件中写入多个表?

    我正在尝试创建一个使用多个表的组件 前端 我发现一两个帖子部分回答了这个问题 但没有一个真正回答了这个问题 对于知道如何做的人来说 这一点似乎总是简单明了 但从未真正解释过 或者我错过了正确的帖子 在我的组件中 用户在一个视图中输入需要存储
  • 需要处理 git-archive 中的 git-submodules

    我需要将 git 子模块打包到我创建的 tarball 中git archive 我在1 6 5中看到了git archive不支持 git 子模块 我在网上看到了几个处理这种情况的脚本 但我不确定该选择哪一个 最好 最官方的方法是什么 你
  • 在 C# Windows 服务上重定向 stdout+stderr

    我使用 C 编写了一个 Windows 服务ServiceBase帮手 在执行期间 会调用外部本机 DLL 中的一些过程 令人烦恼的是 这些过程以不受控制的方式写入 stdout 和 或 stderr 因为没有给出该 DLL 的源代码 是否
  • Android Studio:错误代码 1:Gradle:任务“:app:processDebugResources”执行失败

    我想编译一个项目 我得到了Error Gradle Execution failed for task app processDebugResources 这是例外 错误 Gradle 任务 app processDebugResource
  • 如何在javascript中检测浏览器渲染引擎?

    我读过一本名为 Professional Javascript For Web Developers 2nd Edition 的书 其中指出此代码可以检测浏览器渲染引擎
  • 如何控制recyclerView.smoothScrollToPosition(position)的滚动速度?

    我有一个回收器视图 我想要平滑地向下滚动 然后以编程方式向上滚动到它 以向用户显示其中的完整内容 我可以通过以下方式做到这一点 final int height recyclerView getChildAt 0 getHeight rec
  • docker libgomp.so.1 内的 Lightgbm:无法打开共享对象文件

    我在我的 Mac 上安装了 LightGBM 并之前针对不同的项目进行了测试 现在我在 Mac 上安装了 python 3 6 的 docker 中 一旦我添加import lightgbm as lgbm在我的 Flask 应用程序中 我
  • 对象名称“dbo.UserRoles”无效

    我收到此错误 SqlException 0x80131904 Invalid object name dbo UserRoles 但我无法捕获错误所在 我可以从其他表中检索其他数据 但不能从这个表中检索数据 条件是 web config 中
  • Android创建BitmapDescriptor异常

    我正在编写一个可以与谷歌地图和标记配合使用的应用程序 我的任务是在谷歌地图上创建并显示一些标记 标记中有自定义图像和文本 数据正在从服务器加载 每次用户移动谷歌地图相机时我都需要显示新的数据量 所以我使用 android maps util
  • 在同一台机器上运行的 Firefox 扩展和 C# 代码之间应该使用什么 IPC 方法?

    我有一个关于如何在 新 Firefox 扩展和现有 C 代码之间构建通信的问题 Firefox 扩展将使用配置数据并生成其他数据 因此需要从某处获取配置数据并将其输出保存在某处 数据由现有 C 代码生成 使用 因此我需要决定扩展应如何与 C
  • 更改绑定中的默认千位和小数分隔符

    假设我有一个号码1234567 89 该数字显示在 WPF TextBlock 中 我正在尝试申请StringFormat归因于Text属性 以便数字显示如下 1 234 567 89 正如您所看到的 千位分隔符和小数分隔符与不变区域性规范
  • sbt 插件没有从子模块中获取?

    我正在尝试将单个模块项目转换为两个模块 根聚合体 感觉就像是一件很正常的事情 因此 为了简化 我删除了添加的第二个项目 但我 做类似的事情 cd myproject mkdir core mv core 然后在 myproject 中添加一
  • 如何将 target="_blank" 添加到指定 div 内的链接?

    假设我有以下代码 div ul li a href http www google com google a li li div class some class dsalkfnm sladkfm a href http www yahoo
  • 将 MediaProjection 虚拟显示器的输出捕获到 ImageReader 时出现系统错误

    我正在开发一个需要将屏幕捕获为位图以进行传输的应用程序 我正在尝试使用新的 Android 5 0android media projection API进行屏幕捕获 此 API 的工作流程最终会调用 mediaProjection cre