HUAWEI P40 Pro的录制超级慢动作
一般的电影都是采用24帧/秒的制式标准,当电影放映机和摄影机转换频率同步时就是正常速度的画面
如果在拍摄时以每秒48帧进行录制,播放时仍以每秒24帧播放,那么同样的画面播放速率也就放慢了一倍,即时长增加一倍,此时就会出现慢动作。这样的拍摄手法通常称为「慢镜头」或「升格摄影」
最著名的慢镜头当属《黑客帝国》中的「子弹时间」了
随着手机拍摄能力的持续创新,慢动作也成为了各大手机厂商旗舰机的标配功能,在抖音、B站等平台中我们可以看到一些用手机拍摄的比较炫酷的慢镜头vlog和短视频(比如矮脚猫跳高这个场景是非常适合用慢动作来拍摄的)
除了系统相机能提供慢动作的能力外,第三方应用开发能否支持慢动作呢?答案是肯定的,但是大部分机型其实是不支持的......
就国内华米OV四家影像能力开放来说,通过camera2 api支持自家能力,华为对第三方开发者来说是算比较友好的
(荣耀现在独立,具体情况研究较少,总体不太了解,有清楚的小伙伴可以来一起交流交流)
本文介绍的慢动作功能采用Camera2+MediaRecorder+SurfaceView实现,预览流程和常规的camera2预览流程是一致的,只是创建会话和请求request有些许不同,详细步骤可以参考Android Camera2详解,下面仅说说流程的关键点,详细代码可以参考文末的「参考2」
启动预览前需要先检查一下当前设备是否支持慢动作
// 遍历capabilities是否存在CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
// 慢动作录制视频的video size必须和preview size保持一致
// 所以需要从两个list中找到交集
map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
highSpeedVideoSizes = map.getHighSpeedVideoSizes();
previewSizes = getOutputSizes(SurfaceHolder.class);
for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_LOW; quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) {
if (CamcorderProfile.hasProfile(quality)) {
if (size.getWidth() == profile.videoFrameWidth && size.getHeight() == profile.videoFrameHeight) {
return profile;
}
}
}
// 比如华为P40 Pro上1920x1080支持的fps为:
// [30, 120], [30, 240], [120, 120], [240, 240]
map.getHighSpeedVideoFpsRangesFor(size);
在设备支持慢动作的前提下就可以配置预览流程了
// 1. open camera
cameraManager.openCamera(...);
// 2. prepare surfaces
surfaceList.add(mSurfaceHolder.getSurface);
// prepare media recorder
// mMediaRecorder的参数配置来自前面的higt speed profile
mMediaRecorder.prepare();
surfaceList.add(mMediaRecorder.getSurface)
// 3. create high speed session
cameraDevice.createConstrainedHighSpeedCaptureSession(surfaceList,...);
// 4. trigger request
mPreviewBuilderBurst = session.createHighSpeedRequestList(mPreviewBuilder.build());
session.setRepeatingBurst(mPreviewBuilderBurst, null, null);
其中配置MediaRecorder时不配置Audio(录制慢动作和延时摄影时都不用配置音频)
// only config video stream
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setOrientationHint(90);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(profile.fileFormat);
mMediaRecorder.setVideoEncoder(profile.videoCodec);
mMediaRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight); mMediaRecorder.setVideoEncodingBitRate(profile.videoBitRate);
mMediaRecorder.setVideoFrameRate(profile.videoFrameRate);
预览起来后就可以通过MediaRecorder开启录制了
// start record
mMediaRecorder.start();
// stop record
mMediaRecorder.stop();
以手上机器设置帧率【30,120】为例,录制的一个test视频如下
FAQ
Q1: 为什么慢动作启动预览时需要保持video size和preview size一致
A1: 因为在创建request list时会校验每个surface的size是否支持设定的fps
fpsRange一定是不为null的,如果为null,后续流程就NPE了
Q2: 类似华为P40 Pro提供的这种32X对应到960帧/S是怎么算的
A2: session每次请求的request list数量为设置的fps最大值除以30,UI显示的倍数乘以30就是录制的最大的fps
参考
1.【录制超级慢动作视频 (HUAWEI P40 Pro)】
https://consumer.huawei.com/cn/emui10-1/tips/entertainment-list/article17/
2.【Android-Slow-Motion-Camera2】
https://github.com/thesleort/Android-Slow-Motion-Camera2
3.【华为相机能力】
https://developer.huawei.com/consumer/cn/CameraKit/
4.【Android源码9.0】
http://androidxref.com/9.0.0_r3/xref/frameworks
~~END~~