安卓:相机预览帧始终横向编码。如何旋转?

3
目标:将Android相机流式传输到Wowza服务器,无论设备的方向如何(即视频始终正面朝上)。
我已经查看了这里关于相机方向的所有问题,到目前为止它们似乎都只是改变了呈现在屏幕上的预览或在MP4文件中设置了一个标志(不适用于我的用例:流媒体)。
我正在将相机帧流式传输到Wowza服务器,在Wowza服务器上接收到的视频始终是横向的。如果手机始终保持相同的方向,则没有问题,但我不能保证我的用户会这样做。据我所知,当您直接从相机获取帧并将其提供给编码器时,您正在获得设备相机的自然方向(在我的情况下可能安装为横向),这完全不受预览的影响。这是有问题的,因为如果在流程中旋转设备,则图像也会随之旋转。
我尝试使用openGL矩阵将预览转换为自定义GLSurfaceView.Renderer中的内容,但它只是转换屏幕上的视图,而不是发送到编码器的帧。
我已阅读Grafika的示例,但不确定在将帧提供给编码器之前需要在哪个阶段旋转它们。我正在使用SurfaceTexture作为相机预览,然后将其渲染到GLSurfaceView上(并使用自己的自定义GLSurfaceView.Renderer)。
如何将帧旋转到编码器中?
理想情况下,我会在openGL中完成这项工作。我曾考虑过在填充mediacodec.dequeueInputBuffer缓冲区之前旋转帧,但这将使用CPU,由于实时应用程序的原因,我有所顾虑。也许我在预览方面忽略了一些东西。我已看到其他广播应用程序在设备旋转时拆除UI上的预览层并重新构建它。
参考资料:

https://github.com/Kickflip/kickflip-android-sdk/

https://github.com/google/grafika

1个回答

1
Grafika中的相机活动每帧都会渲染两次:一次用于显示,一次用于编码。您想做同样的事情,但是加入旋转(并对MediaCodec / MediaRecorder配置进行适当调整,即720x1280与1280x720)。例如,考虑ContinuousCapture中drawFrame()方法。它选择SurfaceView的EGLSurface,绘制,然后切换到视频编码器的EGLSurface并调用相同的绘制方法。它甚至添加了一个drawExtra()调用,只是为了展示它的功能。在这两种情况下,您只需将GLES渲染到EGLSurface上,EGLSurface从底层Surface获取其尺寸,该Surface来自SurfaceView或MediaCodec。如果您修改FullFrameRect#drawFrame()以接受矩阵参数,并传入旋转矩阵代替当前使用的单位矩阵,则应获得所需结果。

非常感谢您的迅速回复!我的surface是来自MediaCodec(mediaCodec createInputSurface()),所以如果编码器在运行时发生方向变化,您是说我必须停止它,并重新配置适当尺寸,同时传递旋转矩阵(Matrix.rotateM())?我还需要再次调用createInputSurface,对吗?我没有任何OpenGL经验,但我想我可以弄清楚。我将首先尝试在ContinuousCapture&FullFrameRect中使用您建议的更改,并让您知道是否有任何问题。 - bennnnnnjamin
中途更改分辨率是可能的,但我没有使用过它们(请参见例如https://dev59.com/dozda4cB1Zd3GeqPrtij)。停止和重新启动MediaCodec将起作用。另一种选择是在旋转后加上黑边或白边,但这看起来不太好。 “从相机获取纹理”的活动会缩放和旋转相机源;有关实现细节,请参见Sprite2d#recomputeMatrix() - fadden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接