Android Camera2前置摄像头的编码器输出Surface:在编码成H.264的 NAL单元中,物理倾斜角度似乎被放大了两倍——为什么?

移动开发 2026-07-08

我正在开发一个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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章