Android虚拟显示器的延迟帧
我试图解决的基本问题是将发送到虚拟显示器的内容延迟一秒钟左右。所以基本上,我尝试在初始录制后将所有帧移动1秒。请注意,通过此虚拟显示,一个曲面用作输入,另一个曲面用作输出。我最初的预感是探索一些想法,因为修改Android框架或使用非公共API是可以的。Java或本机C/C++可以 a) 我尝试在SurfaceFlinger中将发布到虚拟显示或输出表面的帧延迟一两秒。这不起作用,因为它会导致所有曲面延迟相同的时间(帧的同步处理) b) MediaCodec使用曲面作为输入进行编码,然后生成解码数据。是否有必要使用MediaCodec,使其不进行实际编码,只生成未编码的原始帧?似乎不太可能。此外,MediaCodec是如何做到这一点的?一帧一帧地处理事情。如果我能推断出这种方法,我可能能够从输入表面逐帧提取,并创建一个按我所需时间延迟的环形缓冲区 c) 软件解码器,比如FFmpeg,在Android中是如何做到这一点的?我假设他们接受了一个曲面,但他们如何一帧一帧地推断和处理呢 请注意,我当然可以编码和解码以检索帧并发布它们,但我希望避免实际解码。请注意,修改Android框架或使用非公共API是可以的 我还发现:Android虚拟显示器的延迟帧,android,android-ndk,android-mediacodec,surface,Android,Android Ndk,Android Mediacodec,Surface,我试图解决的基本问题是将发送到虚拟显示器的内容延迟一秒钟左右。所以基本上,我尝试在初始录制后将所有帧移动1秒。请注意,通过此虚拟显示,一个曲面用作输入,另一个曲面用作输出。我最初的预感是探索一些想法,因为修改Android框架或使用非公共API是可以的。Java或本机C/C++可以 a) 我尝试在SurfaceFlinger中将发布到虚拟显示或输出表面的帧延迟一两秒。这不起作用,因为它会导致所有曲面延迟相同的时间(帧的同步处理) b) MediaCodec使用曲面作为输入进行编码,然后生成解码数
选项d)似乎可以使用SurfaceTexture,但我希望避免编码/解码过程。据我所知,您有一个虚拟显示器,它正在将其输出发送到Surface。如果仅使用SurfaceView进行输出,则虚拟显示器输出的帧会立即显示在物理显示器上。目标是在虚拟显示器生成帧和表面消费者接收帧之间引入一秒钟的延迟,以便(再次以表面视图为例)物理显示器延迟一秒钟显示所有内容 基本概念很简单:将虚拟显示输出发送到SurfaceTexture,并将帧保存到循环缓冲区中;同时,另一个线程正在从循环缓冲区的尾部读取帧并显示它们。问题是@AdrianCrețu在评论中指出的:每秒60帧的全分辨率屏幕数据会占用设备内存的很大一部分。更不用说复制如此多的数据将相当昂贵,有些设备可能无法跟上 (无论您是在应用程序中还是在SurfaceFlinger中进行此操作,都无关紧要……多达60个屏幕大小的帧的数据必须保存在某个位置整整一秒钟。) 您可以通过多种方式减少数据量:
- 降低分辨率。将2560x1600缩放到1280x800将删除3/4的像素。在大多数显示器上,质量损失应该很难注意到,但这取决于您正在观看的内容
- 减少颜色深度。从argb888切换到RGB565会将大小减半。但这将是显而易见的
- 降低帧速率。您正在为虚拟显示生成帧,因此可以选择更新速度较慢。动画仍然以30fps的速度平滑,将内存需求减半
- 应用图像压缩,例如PNG或JPEG。相当有效,但如果没有硬件支持,速度太慢
- 编码帧间差异。如果帧与帧之间的变化不大,则增量变化可能非常小。像VNC这样的桌面镜像技术可以做到这一点。在软件方面有点慢
如果您还没有,请通读。据我所知,您有一个将其输出发送到曲面的虚拟显示器。如果仅使用SurfaceView进行输出,则虚拟显示器输出的帧会立即显示在物理显示器上。目标是在虚拟显示器生成帧和表面消费者接收帧之间引入一秒钟的延迟,以便(再次以表面视图为例)物理显示器延迟一秒钟显示所有内容 基本概念很简单:将虚拟显示输出发送到SurfaceTexture,并将帧保存到循环缓冲区中;同时,另一个线程正在从循环缓冲区的尾部读取帧并显示它们。问题是@AdrianCrețu在评论中指出的:每秒60帧的全分辨率屏幕数据会占用设备内存的很大一部分。更不用说复制如此多的数据将相当昂贵,有些设备可能无法跟上 (无论您是在应用程序中还是在SurfaceFlinger中进行此操作,都无关紧要……多达60个屏幕大小的帧的数据必须保存在f的某个位置。)