Rockchip设备Camera2+MediaRecorder竖屏WYSIWYG录像裁剪方案问询
解决方案:Camera2 + MediaRecorder 实现竖屏所见即所得录制(Rockchip设备适配)
问题分析
核心矛盾是Rockchip设备的Camera HAL不支持硬件级裁剪,导致MediaRecorder只能录制完整传感器帧,无法直接和竖屏预览对齐。现有setOrientationHint、预览变换仅做视觉调整,未真正改变录制帧内容。
针对问题的解答
1. Camera2+MediaRecorder实时裁剪的正确方式
由于Rockchip HAL不支持Camera2直接裁剪,无法通过MediaRecorder直接实现实时裁剪——MediaRecorder的Surface直接绑定相机输出,只能接收完整传感器帧。必须在相机输出到MediaRecorder之间添加帧处理环节,对帧裁剪后再传给编码器。
2. Surface层(OpenGL/SurfaceTexture)裁剪的可行性
完全可行,这是实时处理的最优方案,无需后期重编码。具体流程:
- 相机输出帧到
SurfaceTexture(绑定OpenGL上下文) - 在OpenGL中对帧做中心裁剪(从16:9帧截取中间9:16区域)
- 将裁剪后的帧同时渲染到预览
TextureView和MediaRecorder的Surface,保证所见即所得
该方案依托硬件加速,在RK3568/RK3399上可轻松实现1080p@30fps的实时性能。
3. Rockchip专属API/HAL级裁剪支持
Rockchip Camera HAL默认仅输出完整传感器帧,但可尝试两种硬件级裁剪途径:
- RK Camera扩展参数:部分设备提供非标准Camera2参数(如
com.rockchip.camera.param.CROP_REGION),可在CaptureRequest中设置裁剪区域,需联系Rockchip获取适配文档。 - RK MPP媒体处理框架:若用MPP替代MediaRecorder,可在编码前通过MPP硬件裁剪模块处理帧,性能比OpenGL更优,但需适配Native层代码,Java层需通过JNI调用。
4. 后期处理的高效方案(避免重编码)
若必须采用后期处理,需避免全帧重编码,最优方式是用FFmpeg流拷贝模式结合裁剪滤镜,仅修改容器元数据和裁剪帧,不重新编码视频流:
ffmpeg -i input.mp4 -filter:v "crop=ih*9/16:ih:(iw-ih*9/16)/2:0" -c:v copy -c:a copy output.mp4
该方式几乎实时,无重编码性能损耗。注意录制时需设置较小的关键帧间隔(如1秒),避免裁剪后播放卡顿。
示例代码:OpenGL实时裁剪实现(Java层)
核心流程代码
- 初始化SurfaceTexture与MediaRecorder Surface:
// 初始化SurfaceTexture接收相机帧 SurfaceTexture surfaceTexture = new SurfaceTexture(textureId); surfaceTexture.setOnFrameAvailableListener(this); // 配置MediaRecorder MediaRecorder mediaRecorder = new MediaRecorder(); mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mediaRecorder.setVideoSize(1080, 1920); // 目标竖屏分辨率 mediaRecorder.setOrientationHint(0); // 裁剪后已是竖屏,无需旋转 Surface recorderSurface = mediaRecorder.getSurface();
- OpenGL帧裁剪渲染逻辑(
onFrameAvailable回调):
@Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { surfaceTexture.updateTexImage(); float[] transformMatrix = new float[16]; surfaceTexture.getTransformMatrix(transformMatrix); // 相机输出为1920x1080横屏,目标为1080x1920竖屏 float inputAspect = 1920f / 1080f; float targetAspect = 9f / 16f; float scaleX = targetAspect / inputAspect; // 横向裁剪比例 // 渲染到预览TextureView previewEglSurface.makeCurrent(); glViewport(0, 0, 1080, 1920); glClear(GL_COLOR_BUFFER_BIT); drawCroppedFrame(transformMatrix, scaleX, 1f); // 执行裁剪渲染 previewEglSurface.swapBuffers(); // 渲染到MediaRecorder Surface recorderEglSurface.makeCurrent(); glViewport(0, 0, 1080, 1920); glClear(GL_COLOR_BUFFER_BIT); drawCroppedFrame(transformMatrix, scaleX, 1f); recorderEglSurface.swapBuffers(); }
关键注意事项
- 初始化EGL上下文时需添加
EGL_RECORDABLE_ANDROID属性,确保渲染Surface可被MediaRecorder正常编码。 - 相机
CaptureRequest需设置与预览/录制一致的输出分辨率(如1920x1080),避免额外缩放损耗。
Rockchip设备专属优化建议
- 优先尝试RK Camera扩展参数:若设备支持,直接在
CaptureRequest中设置裁剪区域,性能最优且无需额外处理。 - 适配RK MPP框架:追求极致性能时,通过JNI调用MPP硬件裁剪接口,编码前完成帧裁剪,比OpenGL更节省资源。
- 规避软件裁剪:嵌入式设备上软件帧处理会大幅降低性能,尽量采用硬件加速方案。
内容的提问来源于stack exchange,提问作者Nityam Tiwari
相关产品推荐
相关产品推荐

