Android:编码的相机预览帧总是横向的。如何旋转?
Android: Encoded Camera Preview Frames always in landscape. How to rotate?
目标:将 Android 摄像头以正确的方向传输到 Wowza 服务器,无论设备的方向如何(即视频总是正面朝上)
我已经查看了此处关于相机方向的所有问题,到目前为止,它们似乎都只是更改呈现到屏幕的预览或在 MP4 文件中设置一个标志(不适合我的用例:流媒体)。
我正在将摄像机帧流式传输到 Wowza 服务器,在 Wowza 服务器上,接收到的视频始终是横向的。如果 phone 始终保持在同一方向,这很好,但我不能保证我的用户会这样做。根据我收集到的信息,当您直接从相机抓取帧并将它们提供给编码器时,您将获得设备相机的自然方向(在我的情况下可能是横向安装的)并且这完全不受预览的影响.这是有问题的,因为如果设备在流式传输期间旋转,图像也会随之旋转。
我尝试使用 openGL 矩阵在自定义 GLSurfaceView.Renderer 中转换预览,它所做的只是转换屏幕上的视图,而不是发送到编码器的帧。
我已经阅读了 Grafika 的示例,但不确定在将帧馈送到编码器之前我需要在哪个过程中旋转帧。我使用 SurfaceTexture 作为相机预览,然后渲染到 GLSurfaceView(并使用我自己的自定义 GLSurfaceView.Renderer)。
如何将帧旋转到编码器?
理想情况下,我会在 openGL 中执行此操作。我曾考虑过在填充 mediacodec.dequeueInputBuffer 缓冲区之前旋转帧,但这将使用 CPU 完成,而且由于实时应用程序,我很谨慎。也许我忽略了一些关于预览的内容。我已经看到其他广播应用程序在 UI 上拆除预览层并在设备旋转时重建它。
参考文献:
Grafika 中的相机活动每帧渲染两次:一次用于显示,一次用于编码。您想做同样的事情,但要进行轮换(并对 MediaCodec / MediaRecorder 配置进行适当调整,即 720x1280 与 1280x720)。
例如,考虑 drawFrame()
method in ContinuousCapture。它选择 SurfaceView 的 EGLSurface,绘制,然后切换到视频编码器的 EGLSurface 并调用相同的绘制方法。它甚至会调用 drawExtra()
来表明它可以。
在这两种情况下,您只是将 GLES 渲染到 EGLSurface 上,而 EGLSurface 从底层 Surface 获取其尺寸,它来自 SurfaceView 或 MediaCodec。如果您修改 FullFrameRect#drawFrame()
以采用矩阵参数,并传入一个旋转矩阵来代替它当前使用的单位矩阵,您应该会得到您想要的结果。
目标:将 Android 摄像头以正确的方向传输到 Wowza 服务器,无论设备的方向如何(即视频总是正面朝上)
我已经查看了此处关于相机方向的所有问题,到目前为止,它们似乎都只是更改呈现到屏幕的预览或在 MP4 文件中设置一个标志(不适合我的用例:流媒体)。
我正在将摄像机帧流式传输到 Wowza 服务器,在 Wowza 服务器上,接收到的视频始终是横向的。如果 phone 始终保持在同一方向,这很好,但我不能保证我的用户会这样做。根据我收集到的信息,当您直接从相机抓取帧并将它们提供给编码器时,您将获得设备相机的自然方向(在我的情况下可能是横向安装的)并且这完全不受预览的影响.这是有问题的,因为如果设备在流式传输期间旋转,图像也会随之旋转。
我尝试使用 openGL 矩阵在自定义 GLSurfaceView.Renderer 中转换预览,它所做的只是转换屏幕上的视图,而不是发送到编码器的帧。
我已经阅读了 Grafika 的示例,但不确定在将帧馈送到编码器之前我需要在哪个过程中旋转帧。我使用 SurfaceTexture 作为相机预览,然后渲染到 GLSurfaceView(并使用我自己的自定义 GLSurfaceView.Renderer)。
如何将帧旋转到编码器?
理想情况下,我会在 openGL 中执行此操作。我曾考虑过在填充 mediacodec.dequeueInputBuffer 缓冲区之前旋转帧,但这将使用 CPU 完成,而且由于实时应用程序,我很谨慎。也许我忽略了一些关于预览的内容。我已经看到其他广播应用程序在 UI 上拆除预览层并在设备旋转时重建它。
参考文献:
Grafika 中的相机活动每帧渲染两次:一次用于显示,一次用于编码。您想做同样的事情,但要进行轮换(并对 MediaCodec / MediaRecorder 配置进行适当调整,即 720x1280 与 1280x720)。
例如,考虑 drawFrame()
method in ContinuousCapture。它选择 SurfaceView 的 EGLSurface,绘制,然后切换到视频编码器的 EGLSurface 并调用相同的绘制方法。它甚至会调用 drawExtra()
来表明它可以。
在这两种情况下,您只是将 GLES 渲染到 EGLSurface 上,而 EGLSurface 从底层 Surface 获取其尺寸,它来自 SurfaceView 或 MediaCodec。如果您修改 FullFrameRect#drawFrame()
以采用矩阵参数,并传入一个旋转矩阵来代替它当前使用的单位矩阵,您应该会得到您想要的结果。