- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试使用 TextureView
制作绘图/绘画应用程序在安卓上。我想支持高达 4096x4096 像素的绘图表面,这对于我的最小目标设备(我用于测试)来说是合理的,它是 Google Nexus 7 2013,它有一个很好的四核 CPU 和 2GB 内存。
我的要求之一是我的 View 必须位于允许放大、缩小和平移的 View 内,这是我编写的所有自定义代码(想想 iOS 中的 UIScrollView)。
我试过在 OnDraw 中使用常规 View (不是 TextureView
),性能绝对糟糕 - 每秒不到 1 帧。即使我拨打 Invalidate(rect)
也会发生这种情况只有 rect 发生了变化。我尝试关闭 View 的硬件加速,但没有渲染,我认为是因为 4096x4096 对于软件来说太大了。
然后我尝试使用 TextureView
性能要好一点 - 大约每秒 5-10 帧(仍然很糟糕但更好)。用户绘制位图,然后使用后台线程将其绘制到纹理中。我正在使用 Xamarin,但希望代码对 Java 人员有意义。
private void RunUpdateThread()
{
try
{
TimeSpan sleep = TimeSpan.FromSeconds(1.0f / 60.0f);
while (true)
{
lock (dirtyRect)
{
if (dirtyRect.Width() > 0 && dirtyRect.Height() > 0)
{
Canvas c = LockCanvas(dirtyRect);
if (c != null)
{
c.DrawBitmap(bitmap, dirtyRect, dirtyRect, bufferPaint);
dirtyRect.Set(0, 0, 0, 0);
UnlockCanvasAndPost(c);
}
}
}
Thread.Sleep(sleep);
}
}
catch
{
}
}
TextureView
的内容闪烁并损坏,这是令人失望的。我原以为它只是在下面使用 OpenGL 帧缓冲区/渲染纹理,或者至少可以选择保留内容。
最佳答案
首先,如果您想了解幕后发生的事情,您需要阅读 Android Graphics Architecture document .它很长,但如果你真诚地想了解“为什么”,它就是开始的地方。
关于TextureView
TextureView 是这样工作的:它有一个 Surface,它是一个具有生产者-消费者关系的缓冲区队列。如果您使用软件 (Canvas) 渲染,则会锁定 Surface,从而为您提供缓冲区;你在上面画画;然后你解锁 Surface,它将缓冲区发送给消费者。在这种情况下,消费者处于同一进程中,称为 SurfaceTexture 或(在内部,更恰本地)GLConsumer。它将缓冲区转换为 OpenGL ES 纹理,然后渲染到 View 。
如果关闭硬件加速,GLES 将被禁用,TextureView 将无法执行任何操作。这就是为什么当您关闭硬件加速时您一无所获。 The documentation非常具体:“TextureView 只能在硬件加速窗口中使用。在软件中渲染时,TextureView 不会绘制任何内容。”
如果指定dirty rect,软件渲染器会在渲染完成后将之前的内容memcpy到帧中。我不相信它会设置剪辑矩形,因此如果您调用 drawColor(),您将填满整个屏幕,然后覆盖这些像素。如果您当前没有设置剪辑矩形,您可能会从中看到一些性能优势。 (虽然我没有检查代码。)
脏矩形是一个输入输出参数。当您拨打 lockCanvas()
时,您传递了您想要的矩形,并且允许系统在调用返回之前对其进行修改。 (实际上,这样做的唯一原因是如果没有前一帧或调整 Surface 的大小,在这种情况下它会扩展它以覆盖整个屏幕。我认为使用更直接的方法会更好地处理“我拒绝您的矩形”信号。)您需要更新您返回的矩形内的每个像素。你不能改变矩形,你似乎试图在你的样本中做 - 无论在 lockCanvas()
之后的脏矩形中是什么|成功是你需要借鉴的。
我怀疑肮脏的 rect 处理不当是您闪烁的根源。可悲的是,这是一个很容易犯的错误,因为 lockCanvas()
的行为dirtyRect
arg 仅记录在 the Surface class 中本身。
表面和缓冲
所有表面都是双缓冲或三缓冲。没有办法解决这个问题——你不能同时读和写也不会流泪。如果您想要一个可以在需要时修改和推送的单个缓冲区,则需要锁定、复制和解锁该缓冲区,这会在组合管道中造成停顿。为了获得最佳吞吐量和延迟,翻转缓冲区更好。
如果您想要锁定-复制-解锁行为,您可以自己编写(或找到一个执行此操作的库),并且它的效率将与系统为您完成时一样有效(假设您擅长blit 循环)。绘制到屏幕外的 Canvas 并 blit 位图,或绘制到 OpenGL ES FBO 并 blit 缓冲区。您可以在 Grafika 的“record GL app” Activity 中找到后者的示例,该 Activity 具有在屏幕外渲染一次,然后 blit 两次(一次用于显示,一次用于录制视频)的模式。
更多速度等
在 Android 上绘制像素有两种基本方法:使用 Canvas 或使用 OpenGL。 Canvas 渲染到 Surface 或 Bitmap 总是在软件中完成,而 OpenGL 渲染是用 GPU 完成的。唯一的异常(exception)是,当渲染到 custom View 时,您可以选择使用硬件加速,但这在渲染到 SurfaceView 或 TextureView 的 Surface 时不适用。
绘图或绘画应用程序可以记住绘图命令,或者只是将像素扔到缓冲区并将其用作其内存。前者允许更深层次的“撤消”,后者更简单,并且随着要渲染的内容数量的增加,性能也越来越好。听起来您想做后者,因此从屏幕外进行 blitting 是有道理的。
大多数移动设备对 GLES 纹理的硬件限制为 4096x4096 或更小,因此您将无法将单个纹理用于更大的纹理。您可以查询大小限制值 (GL_MAX_TEXTURE_SIZE),但最好使用尽可能大的内部缓冲区,并且只渲染适合屏幕的部分。我不知道 Skia (Canvas) 的限制是什么,但我相信您可以创建更大的位图。
根据您的需要,SurfaceView 可能比 TextureView 更可取,因为它避免了中间的 GLES 纹理步骤。您在 Surface 上绘制的任何内容都会直接进入系统合成器 (SurfaceFlinger)。这种方式的缺点是,由于 Surface 的消费者不在进程内,View 系统没有机会处理输出,所以 Surface 是一个独立的层。 (对于绘图程序来说,这可能是有益的——正在绘制的图像在一层上,您的 UI 在顶部的单独层上。)
FWIW,我没看过代码,但 Dan Sandler 的 Markers应用程序可能值得一看(源代码 here)。
更新:腐败是identified as a bug和 fixed in 'L' .
关于Android TextureView/绘图/绘画性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31057293/
我在 TextureView 中显示 CameraView 并使用 TextureView.getBitmap() 从 TextureView 获取位图>。 每次我调用 TextureView.get
我有一个附加了 mediaPlayer 的 TextureView,所以我可以使用它的表面来显示视频,到目前为止它运行良好。现在我尝试创建淡入淡出动画来显示视频,但我不知道该怎么做。 我尝试使用 se
我想使用 TextureView 在其中显示相机预览。最后我想使用 TextureView 为相机预览设置不透明度。但我有问题: 10-22 12:21:14.773: W/TextureView(5
是否有可能拥有一个具有透明度的 TextureView,以便其下方的 View (z 顺序)可见? TextureView 的 IOW 部分是透明的,TextureView 位于其上的 View 会透
我正在尝试实现 this page 上显示的示例.我已经尝试了三种运行 android 4 及更高版本的不同设备,在所有情况下我都会遇到黑屏并显示此警告: 01-27 20:01:22.683: W/
我尝试使用 SurfaceView 和 TextureView 播放相同的视频,并注意到使用 TextureView 渲染的图像更混叠(不如 SurfaceView 更“流畅”。 这是什么原因?有什么
我有一个具有固定宽度和高度的 TextureView,我想在其中显示一个相机预览。我需要裁剪相机预览,使其在我的 TextureView 中看起来不会被拉伸(stretch)。如何进行种植?如果我需要
我正在查看 Android 的 Camera2 API。在 https://github.com/googlesamples/android-Camera2Basic/blob/master/Appl
我正在查看 Android 的 Camera2 API。在 https://github.com/googlesamples/android-Camera2Basic/blob/master/Appl
我正在使用 android vlc (LibVLC) 和 TextureView 以便在我的 android 应用程序中播放实时 rtsp 流。一切工作正常,但是我需要为某些对象检测任务尽可能获取当前
我有一个 TextureView。我可以从我的 TextureView 中的评估文件夹播放视频。现在我想检查视频是否完成。我写了 setOnCompletionListener 但没有工作。这是我的来
我目前正在开发一个使用 Camera2 的应用程序。我在缩放和平移的 TextureView 上显示预览(我只需要显示图像的一部分)。我的问题是我需要分析整个图像。 我的 CameraDevice.S
我正在使用来自 Android Developers Samples 的相机代码在预览时获取图像的一部分并对其进行一些处理。 我想获取预览中从 [0,0] 到 [99,99] 的正方形图像,对其进行处
我正在制作一个自定义的安卓相机应用。到目前为止,我遇到的唯一问题是让 textureView 在横向模式下进行调整(将相机旋转 90 度)。 View 出来扭曲,而不是在正确的方向。肖像模式工作正常。
SurfaceTexture 预览被拉伸(stretch)了!我正在开发一个 camera2 应用程序。每个设备都工作不好。视频和照片的预览被拉伸(stretch)。 public class Cam
我有两个具有 TextureView 的 fragment 来显示相机预览或播放视频。 在使用应用程序一段时间后,玩弄屏幕,我在 logcat 中收到此错误 OpenGLRenderer﹕ GL_IN
我正在尝试将 TextureView 上的绘制过程复制到其他 TextureView 中。主要目标是能够创建一个相同视频的“墙”,该视频正在从附加到 TextureView 的 MediaPlayer
我正在尝试在 TextureView 上使用 ExoPlaye 播放视频。为了缩放和裁剪视频以适合 View ,我使用矩阵。我的自定义 View 扩展了“TextureView”这是我的代码: @Ov
我有一个 WpxHp 预览,我想拍摄 HxW 照片,因此我希望用户看到一个预览窗口,它与我要拍摄的照片具有相同的纵横比,而不是预览窗口。如何使用 TextureView 裁剪预览? -- 编辑 我的想
当我的 Android 应用程序启动时,我尝试播放启动 Activity 的视频,但我遇到了永远不会调用 onSurfaceTextureAvailable 接口(interface)方法的问题。 代
我是一名优秀的程序员,十分优秀!