Camera 慢动作实现流程

31c9100305668572896036066102d573.gif

和你一起终身学习,这里是程序员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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值