Android Camera2前置摄像头的编码器输出Surface:在编码成H.264的 NAL单元中,物理倾斜角度似乎被放大了两倍——为什么?
我正在开发一个Android应用(Flutter/Kotlin),显示设备通过前置摄像头使用Camera2拍摄,并将H.264 NALs直接送入MediaCodec解码器以实现实时显示。编码后的帧也会保存为MP4。
问题: 它在前置摄像头上运行时表现不正确。当前置摄像头设备倾斜(例如3°)时,实时预览的图像应当朝相反方向倾斜,使画面保持直立,这一点与后置镜头相同。相反,图像却沿着与相机同方向倾斜,且倾斜角度是原来的一倍(6°)。这个6° 的倾斜是正确的,但方向被错用。这个倍增在保存的MP4文件中也能确认存在,意味着它发生在编码像素数据层面,在解码器之前,而非显示流水线中。
我们确定的事实:
- 图像在几何上始终正确(宽高比正确,无畸变)
- 只有倾斜的幅度错了——每个角度都被放大了一倍
- 这与
KEY_ROTATION无关——它只处理90° 的步进 sensorOrientation=270表示前置摄像头,sensorOrientation=90表示后置- 倍增存在于MP4文件中——它被编码进像素数据
- 将
TEMPLATE_RECORD改为TEMPLATE_PREVIEW也没有区别 setFixedTransformHint(ROTATION_0)改变横屏表现但并未修正倍增- 一个GLES预处理器在Camera2与编码器表面之间插入一个X 翻转也没有改变
Encoder setup:
val format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720).apply {
setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
setInteger(MediaFormat.KEY_BIT_RATE, 4_000_000)
setInteger(MediaFormat.KEY_FRAME_RATE, 30)
setInteger(MediaFormat.KEY_LATENCY, 1)
setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0)
setInteger(MediaFormat.KEY_BITRATE_MODE, MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR)
}
val codec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
encoderSurface = codec.createInputSurface()
Camera2 capture session:
val requestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
requestBuilder.addTarget(encoderSurface)
requestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(fps, fps))
captureSession?.setRepeatingRequest(requestBuilder.build(), null, backgroundHandler)
Decoder setup:
val format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720).apply {
setInteger(MediaFormat.KEY_ROTATION, 270) // front camera portrait
}
codec.configure(format, holder.surface, null, 0)
Logcat confirming the setup:
W/#####ENC: setupEncoderSession: cameraId=1 physical=null 1280x720@30 isFront=true sensorOrientation=270
W/#####ENC: startEncoderCapture: cameraId=1 isFront=true passedSensorOrientation=270 cam2SensorOrientation=270 fps=30
W/#####ROT: startLiveDecoder: KEY_ROTATION=270 isFront=true sensorOrientation=270 localCamStreamCorrection=270
W/#####DEC: INFO_OUTPUT_FORMAT_CHANGED: 1280x720 rotation=270 isLocal=true isFront=true
问题: 为什么Camera2会向编码器表面写入包含前置摄像头双倍物理倾斜的帧,其他相机应用是如何避免这种情况的?是否存在某个具体的捕获请求参数、会话配置,或表面属性,控制Camera2将写入前置摄像头的编码器表面的帧如何变换?
设备测试: Samsung Galaxy Tab A9+、Tab S11、Galaxy S24 —— 全部Android 16。三星Galaxy S9在 Android 10上。同一硬件上的三星原生相机应用、Open Camera以及其他多款类似应用在前置摄像头上工作正常。相机倾斜时,图像仍然固定在空间中,这意味着图像会发生反向自转。
解决方案
预览现在显示为正常的非镜像视图。我决定不再与Camera2对着干,直接接受实时预览的镜像视图。毕竟可能更好。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。