草庐IT

android - Android 上从 CPU 到 GPU 方法的最低架空相机

coder 2023-11-25 原文

我的应用程序需要先在 CPU 上对实时摄像机帧进行一些处理,然后再在 GPU 上进行渲染。还有一些其他的东西在 GPU 上渲染,这取决于 CPU 处理的结果;因此,保持一切同步非常重要,这样我们才不会在 GPU 上渲染帧本身,直到该帧的 CPU 处理结果也可用。

问题是在 Android 上,什么是开销最低的方法?

在我的例子中,CPU 处理只需要一个灰度图像,所以 Y 平面打包的 YUV 格式是理想的(并且往往也很适合相机设备的 native 格式)。 NV12、NV21 或全平面 YUV 都将提供对灰度的理想低开销访问,因此在 CPU 端将是首选。

在最初的相机 API 中,setPreviewCallbackWithBuffer() 是将数据传送到 CPU 进行处理的唯一明智方式。这具有独立的 Y 平面,因此非常适合 CPU 处理。让 OpenGL 可以使用此帧以低开销方式进行渲染是更具挑战性的方面。最后,我编写了一个 NEON 颜色转换例程来输出 RGB565,并仅使用 glTexSubImage2d 使其在 GPU 上可用。这首先是在 Nexus 1 时间框架中实现的,即使是 320x240 的 glTexSubImage2d 调用也需要 50 毫秒的 CPU 时间(我想是糟糕的驱动程序试图进行纹理混合 - 这在后来的系统更新中得到了显着改善)。

回到那天,我研究了诸如 eglImage 扩展之类的东西,但它们似乎不可用或没有为用户应用程序提供足够的文档。我稍微查看了内部 android GraphicsBuffer 类,但理想情况下我想留在受支持的公共(public) API 的世界中。

android.hardware.camera2 API promise 能够将 ImageReader 和 SurfaceTexture 附加到捕获 session 。不幸的是,我在这里看不到任何确保正确顺序管道的方法——在 CPU 处理完之前推迟调用 updateTexImage() 很容易,但是如果在该处理过程中另一个帧到达,则 updateTexImage() 将直接跳到最新的框架。似乎对于多个输出,每个队列中都会有独立的帧副本,这是我理想中想要避免的。

理想情况下,这是我想要的:

  1. 相机驱动程序用最新的帧填充一些内存
  2. CPU获得内存中数据指针,无需复制即可读取Y数据
  3. 当帧就绪时,CPU 处理数据并在我的代码中设置一个标志
  4. 开始渲染帧时,检查新帧是否准备就绪
  5. 调用一些 API 来绑定(bind)与 GL 纹理相同的内存
  6. 当新的帧准备就绪时,将保存前一帧的缓冲区释放回池中

我看不到在 Android 上使用公共(public) API 完全实现零拷贝样式的方法,但最接近的方法是什么?

我试过的一件疯狂的事情似乎有效,但没有记录:ANativeWindow NDK API 可以接受数据 NV12 格式,即使适当的格式常量不是公共(public) header 中的格式常量之一。这允许通过 memcpy() 用 NV12 数据填充 SurfaceTexture,以避免 CPU 端颜色转换和 glTexImage2d 中驱动程序端发生的任何混合。这仍然是数据的额外副本,尽管感觉它应该是不必要的,而且由于它没有记录在案,可能不适用于所有设备。一个受支持的顺序零拷贝相机 -> ImageReader -> SurfaceTexture 或等价物将是完美的。

最佳答案

处理视频的最有效方法是完全避免使用 CPU,但听起来这不适合您。公共(public) API 通常适合在硬件中执行所有操作,因为这是框架本身所需要的,尽管 RenderScript 有一些路径。 (我假设您已经看到使用 fragment 着色器的 Grafika filter demo。)

访问 CPU 上的数据过去意味着缓慢的相机 API 或使用 GraphicBuffer 和相对晦涩的 EGL 函数(例如 this question)。 ImageReader 的目的是提供对来自相机的 YUV 数据的零拷贝访问。

您无法真正序列化 Camera -> ImageReader -> SurfaceTexture,因为 ImageReader 没有“转发缓冲区”API。这很不幸,因为这会使这变得微不足道。您可以尝试复制 SurfaceTexture 的功能,使用 EGL 函数将缓冲区打包为外部纹理,但您又进入了非公共(public) GraphicBuffer 领域,我担心缓冲区的所有权/生命周期问题。

我不确定并行路径如何帮助您(Camera2 -> ImageReader,Camera2 -> SurfaceTexture),因为发送到 SurfaceTexture 的内容不会有您的修改。 FWIW,它不涉及额外的副本——在 Lollipop 或附近,BufferQueue 已更新以允许单个缓冲区在多个队列中移动。

完全有可能有一些我还没有见过的奇特的新 API,但据我所知,您的 ANativeWindow 方法可能是赢家。我怀疑使用其中一种相机格式(YV12 或 NV21)会比使用 NV12 更好,但我不确定。

FWIW,如果您的处理时间太长,您将丢帧,但除非您的处理不均匀(某些帧比其他帧花费的时间长得多),无论如何您都必须丢帧。再次进入非公共(public) API 领域,您可以将 SurfaceTexture 切换到“同步”模式,但如果您的缓冲区已满,您仍然会丢帧。

关于android - Android 上从 CPU 到 GPU 方法的最低架空相机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37510487/

有关android - Android 上从 CPU 到 GPU 方法的最低架空相机的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  6. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  7. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  8. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  9. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  10. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

随机推荐