和你一起终身学习,这里是程序员Android
经典好文推荐,通过阅读本文,您将收获以下知识点:
一、高帧率录像简介
二、代码流程分析
三、高通平台如何获取platform和camera sensor的capabilities?
一、高帧率录像简介
高帧率录像即慢动作拍摄,通常人眼能够接受的最好的视频帧速率是24帧/每秒。如果用120帧/秒拍摄一个动作,再用24帧每秒来播放的话,视频就放慢了5倍。
高通平台的 Slow motion feature :
高速录制(HSR) : 以高fps(运行速率)捕获、编码并保存为高 fps(目标速率),运行速率等于目标速率。
高帧率录制(HFR) : 以高fps(运行速率)捕获、编码并保存为30 fps(目标速率),运行速率大于目标速率。
二、代码流程分析
1、app启动录像
路径:\packages\apps\SnapdragonCamera\src\com\android\camera\CaptureModule.java
private boolean startRecordingVideo(final int cameraId) {
...
if (ApiHelper.isAndroidPOrHigher()) {
if (mHighSpeedCapture && ((int) mHighSpeedFPSRange.getUpper() > NORMAL_SESSION_MAX_FPS)) {
CaptureRequest initialRequest = mVideoRequestBuilder.build();
buildConstrainedCameraSession(mCameraDevice[cameraId], surfaces,
mSessionListener, mCameraHandler, initialRequest);
} else {
configureCameraSessionWithParameters(cameraId, surfaces,
mSessionListener, mCameraHandler, mVideoRequestBuilder.build());
}
} else {
//hfr开启且最大帧率大于NORMAL_SESSION_MAX_FPS(60fps)
//创建的是createConstrainedHighSpeedCaptureSession
//否则是createCaptureSession
if (mHighSpeedCapture && ((int) mHighSpeedFPSRange.getUpper() > NORMAL_SESSION_MAX_FPS)) { //创建高速流
mCameraDevice[cameraId].createConstrainedHighSpeedCaptureSession(surfaces, new
CameraConstrainedHighSpeedCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
mCurrentSession = cameraCaptureSession;
Log.v(TAG, "createConstrainedHighSpeedCaptureSession onConfigured");
mCaptureSession[cameraId] = cameraCaptureSession;
CameraConstrainedHighSpeedCaptureSession session =
(CameraConstrainedHighSpeedCaptureSession) mCurrentSession; try { setUpVideoCaptureRequestBuilder(mVideoRequestBuilder, cameraId); List list = CameraUtil .createHighSpeedRequestList(mVideoRequestBuilder.build()); // 通过setRepeatingBurst每次同时提交多个request申请,对应的native方法是submitRequestList session.setRepeatingBurst(list, mCaptureCallback, mCameraHandler); } catch (CameraAccessException e) { Log.e(TAG, "Failed to start high speed video recording " + e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) { Log.e(TAG, "Failed to start high speed video recording " + e.getMessage()); e.printStackTrace(); } catch (IllegalStateException e) { Log.e(TAG, "Failed to start high speed video recording " + e.getMessage()); e.printStackTrace(); } if (!mFrameProcessor.isFrameListnerEnabled() && !startMediaRecorder()) { startRecordingFailed(); return; }
}, null);
} else {
surfaces.add(mVideoSnapshotImageReader.getSurface());
String zzHDR = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_HDR_VALUE);
boolean zzHdrStatue = zzHDR.equals("1");
// if enable ZZHDR mode, don`t call the setOpModeForVideoStream method.
if (!zzHdrStatue) {
setOpModeForVideoStream(cameraId);
}
String value = mSettingsManager.getValue(SettingsManager.KEY_FOVC_VALUE);
if (value != null && Boolean.parseBoolean(value)) {
mStreamConfigOptMode = mStreamConfigOptMode | STREAM_CONFIG_MODE_FOVC;
}
if (zzHdrStatue) {
mStreamConfigOptMode = STREAM_CONFIG_MODE_ZZHDR;
}
if (DEBUG) {
Log.v(TAG, "createCustomCaptureSession mStreamConfigOptMode :"
+ mStreamConfigOptMode);
}
if (mStreamConfigOptMode == 0) { //普通流,但是该过程设置了setOpModeForVideoStream,会导致config->operation_mode变化。
mCameraDevice[cameraId].createCaptureSession(surfaces, mCCSSateCallback, null);
} else {
List<OutputConfiguration> outConfigurations = new ArrayList<>(surfaces.size());
for (Surface sface : surfaces) {
outConfigurations.add(new OutputConfiguration(sface));
}
mCameraDevice[cameraId].createCustomCaptureSession(null, outConfigurations,
mStreamConfigOptMode, mCCSSateCallback, null);
}
}
}
}
...
2、HFR 配置流
路径:\frameworks\base\core\java\android\hardware\camera2\CameraDevice.java
//创建高速捕获会话接口
public abstract void createConstrainedHighSpeedCaptureSession(@NonNull List<Surface> outputs,
@NonNull CameraCaptureSession.StateCallback callback,
@Nullable Handler handler)
throws CameraAccessException;
具体实现在:\frameworks\base\core\java\android\hardware\camera2\impl\CameraDeviceImpl.java
@Override
public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
throws CameraAccessException {
if (outputs == null || outputs.size() == 0 || outputs.size() > 2) {
throw new IllegalArgumentException(
"Output surface list must not be null and the size must be no more than 2");
}
List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
createCaptureSessionInternal(null, outConfigurations, callback,
checkAndWrapHandler(handler),
/*operatingMode*/ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE,
/*sessionParams*/ null);
}
其中 createCaptureSessionInternal 函数实现如下:
private void createCaptureSessionInternal(InputConfiguration inputConfig,
List<OutputConfiguration> outputConfigurations,
CameraCaptureSession.StateCallback callback, Executor executor,
int operatingMode, CaptureRequest sessionParams) throws CameraAccessException {
synchronized(mInterfaceLock) {
if (DEBUG) {
Log.d(TAG, "createCaptureSessionInternal");
}
checkIfCameraClosedOrInError();
boolean isConstrainedHighSpeed =
(operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);
if (isConstrainedHighSpeed && inputConfig != null) {
throw new IllegalArgumentException("Constrained high speed session doesn't support"
+ " input configuration yet.");
}
// Notify current session that it's going away, before starting camera operations
// After this call completes, the session is not allowed to call into CameraDeviceImpl
if (mCurrentSession != null) {
mCurrentSession.replaceSessionClose();
}
// TODO: dont block for this
boolean configureSuccess = true;
CameraAccessException pendingException = null;
Surface input = null;
try {
// configure streams and then block until IDLE
// 里面会获取设备属性
configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
operatingMode, sessionParams);
if (configureSuccess == true && inputConfig != null) {
input = mRemoteDevice.getInputSurface();
}
} catch (CameraAccessException e) {
configureSuccess = false;
pendingException = e;
input = null;
if (DEBUG) {
Log.v(TAG, "createCaptureSession - failed with exception ", e);
}
}
// Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
CameraCaptureSessionCore newSession = null;
if (isConstrainedHighSpeed) {
ArrayList<Surface> surfaces = new ArrayList<>(outputConfigurations.size());
for (OutputConfiguration outConfig : outputConfigurations) {
surfaces.add(outConfig.getSurface());
}
StreamConfigurationMap config =
getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// 检查格式是否正确、fps是否是有效范围、是不是预览/录像编码流等
SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);
newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
callback, executor, this, mDeviceExecutor, configureSuccess,
mCharacteristics);
} else {
newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
callback, executor, this, mDeviceExecutor, configureSuccess);
}
// TODO: wait until current session closes, then create the new session
mCurrentSession = newSession;
if (pendingException != null) {
throw pendingException;
}
mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
}
}
继续分析configureStreamsChecked():
public boolean configureStreamsChecked(InputConfiguration inputConfig,
List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams)
throws CameraAccessException {
// Treat a null input the same an empty list
if (outputs == null) {
outputs = new ArrayList<OutputConfiguration>();
}
if (outputs.size() == 0 && inputConfig != null) {
throw new IllegalArgumentException("cannot configure an input stream without " +
"any output streams");
}
checkInputConfiguration(inputConfig);
boolean