录像实践(C/C++)
===========

在开发相机应用时，需要先[申请相关权限](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/camera-preparation)。

当前示例提供完整的录像流程及其接口调用顺序的介绍。对于单个流程（如[设备输入](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/native-camera-device-input)、[会话管理](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/native-camera-session-management)、[录像](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/native-camera-recording)）的介绍请参考具体章节。

#### 开发流程

在获取到相机支持的输出流能力后，开始创建录像流，开发流程如下。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/f9/v3/MJqALOBSQOKYGVcsB48eIw/zh-cn_image_0000002634009292.png?HW-CC-KV=V1&HW-CC-Date=20260709T132524Z&HW-CC-Expire=86400&HW-CC-Sign=0ADD1B115EAD1C31CCB9D5D2994B9884A846239253E91DF2993B91DA763D49FE)

#### 完整示例

1.  在CMake脚本中链接相关动态库。
    
    target\_link\_libraries(entry PUBLIC
        libace\_napi.z.so
        libohcamera.so
        libhilog\_ndk.z.so
    )
    
2.  创建头文件ndk\_camera.h。
    
    #include "ohcamera/camera.h"
    #include "ohcamera/camera\_input.h"
    #include "ohcamera/capture\_session.h"
    #include "ohcamera/photo\_output.h"
    #include "ohcamera/preview\_output.h"
    #include "ohcamera/video\_output.h"
    #include "ohcamera/camera\_manager.h"
    
    class NDKCamera {
    public:
        ~NDKCamera();
        NDKCamera(char\* previewId, char\* videoId);
    };
    
3.  cpp侧导入NDK接口，并根据传入的SurfaceId进行录像。
    
    #include "hilog/log.h"
    #include <cmath>
    
    bool IsAspectRatioEqual(float videoAspectRatio, float previewAspectRatio)
    {
        float epsilon = 1e-6f;
        return fabsf(videoAspectRatio - previewAspectRatio) <= epsilon;
    }
    
    void OnCameraInputError(const Camera\_Input\* cameraInput, Camera\_ErrorCode errorCode)
    {
        OH\_LOG\_INFO(LOG\_APP, "OnCameraInput errorCode = %{public}d", errorCode);
    }
    
    CameraInput\_Callbacks\* GetCameraInputListener(void)
    {
        static CameraInput\_Callbacks cameraInputCallbacks = {
            .onError = OnCameraInputError
        };
        return &cameraInputCallbacks;
    }
    
    void CaptureSessionOnFocusStateChange(Camera\_CaptureSession\* session, Camera\_FocusState focusState)
    {
        OH\_LOG\_INFO(LOG\_APP, "CaptureSessionOnFocusStateChange");
    }
    
    void CaptureSessionOnError(Camera\_CaptureSession\* session, Camera\_ErrorCode errorCode)
    {
        OH\_LOG\_INFO(LOG\_APP, "CaptureSessionOnError = %{public}d", errorCode);
    }
    
    CaptureSession\_Callbacks\* GetCaptureSessionRegister(void)
    {
        static CaptureSession\_Callbacks captureSessionCallbacks = {
            .onFocusStateChange = CaptureSessionOnFocusStateChange,
            .onError = CaptureSessionOnError
        };
        return &captureSessionCallbacks;
    }
    
    void VideoOutputOnFrameStart(Camera\_VideoOutput\* videoOutput)
    {
        OH\_LOG\_INFO(LOG\_APP, "VideoOutputOnFrameStart");
    }
    
    void VideoOutputOnFrameEnd(Camera\_VideoOutput\* videoOutput, int32\_t frameCount)
    {
        OH\_LOG\_INFO(LOG\_APP, "VideoOutput frameCount = %{public}d", frameCount);
    }
    
    void VideoOutputOnError(Camera\_VideoOutput\* videoOutput, Camera\_ErrorCode errorCode)
    {
        OH\_LOG\_INFO(LOG\_APP, "VideoOutput errorCode = %{public}d", errorCode);
    }
    
    VideoOutput\_Callbacks\* GetVideoOutputListener(void)
    {
        static VideoOutput\_Callbacks videoOutputListener = {
            .onFrameStart = VideoOutputOnFrameStart,
            .onFrameEnd = VideoOutputOnFrameEnd,
            .onError = VideoOutputOnError
        };
        return &videoOutputListener;
    }
    
    void CameraManagerStatusCallback(Camera\_Manager\* cameraManager, Camera\_StatusInfo\* status)
    {
        OH\_LOG\_INFO(LOG\_APP, "CameraManagerStatusCallback is called");
    }
    
    CameraManager\_Callbacks\* GetCameraManagerListener()
    {
        static CameraManager\_Callbacks cameraManagerListener = {
            .onCameraStatus = CameraManagerStatusCallback
        };
        return &cameraManagerListener;
    }
    
    NDKCamera::NDKCamera(char\* previewId, char\* videoId)
    {
        Camera\_Manager\* cameraManager = nullptr;
        Camera\_Device\* cameras = nullptr;
        Camera\_CaptureSession\* captureSession = nullptr;
        Camera\_OutputCapability\* cameraOutputCapability = nullptr;
        Camera\_VideoOutput\* videoOutput = nullptr;
        const Camera\_Profile\* previewProfile = nullptr;
        const Camera\_Profile\* photoProfile = nullptr;
        const Camera\_VideoProfile\* videoProfile = nullptr;
        Camera\_PreviewOutput\* previewOutput = nullptr;
        Camera\_PhotoOutput\* photoOutput = nullptr;
        Camera\_Input\* cameraInput = nullptr;
        uint32\_t size = 0;
        uint32\_t cameraDeviceIndex = 0;
        char\* videoSurfaceId = videoId;
        char\* previewSurfaceId = previewId;
        // 创建CameraManager对象。
        Camera\_ErrorCode ret = OH\_Camera\_GetCameraManager(&cameraManager);
        if (cameraManager == nullptr || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_Camera\_GetCameraManager failed.");
            return;
        }
        // 监听相机状态变化。
        ret = OH\_CameraManager\_RegisterCallback(cameraManager, GetCameraManagerListener());
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_RegisterCallback failed.");
            return;
        }
    
        // 获取相机列表。
        ret = OH\_CameraManager\_GetSupportedCameras(cameraManager, &cameras, &size);
        if (cameras == nullptr || size <= 0 || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_GetSupportedCameras failed.");
            return;
        }
    
        for (int index = 0; index < size; index++) {
            OH\_LOG\_ERROR(LOG\_APP, "cameraId  =  %{public}s ", cameras\[index\].cameraId);              // 获取相机ID。
            OH\_LOG\_ERROR(LOG\_APP, "cameraPosition  =  %{public}d ", cameras\[index\].cameraPosition);  // 获取相机位置。
            OH\_LOG\_ERROR(LOG\_APP, "cameraType  =  %{public}d ", cameras\[index\].cameraType);          // 获取相机类型。
            OH\_LOG\_ERROR(LOG\_APP, "connectionType  =  %{public}d ", cameras\[index\].connectionType);  // 获取相机连接类型。
        }
    
        if (size < cameraDeviceIndex + 1) {
            OH\_LOG\_ERROR(LOG\_APP, "cameraDeviceIndex is invalid.");
            return;
        }
    
        // 获取相机设备支持的输出流能力。
        ret = OH\_CameraManager\_GetSupportedCameraOutputCapability(cameraManager, &cameras\[cameraDeviceIndex\],
                                                                &cameraOutputCapability);
        if (cameraOutputCapability == nullptr || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_GetSupportedCameraOutputCapability failed.");
            return;
        }
    
        if (cameraOutputCapability->previewProfiles == nullptr) {
            OH\_LOG\_ERROR(LOG\_APP, "previewProfiles == null");
            return;
        }
        previewProfile = cameraOutputCapability->previewProfiles\[0\];
        OH\_LOG\_INFO(LOG\_APP, "previewProfile width: %{public}d, height: %{public}d.", previewProfile->size.width,
            previewProfile->size.height);
        if (cameraOutputCapability->photoProfiles == nullptr) {
            OH\_LOG\_ERROR(LOG\_APP, "photoProfiles == null");
            return;
        }
        photoProfile = cameraOutputCapability->photoProfiles\[0\];
    
        if (cameraOutputCapability->videoProfiles == nullptr) {
            OH\_LOG\_ERROR(LOG\_APP, "videoProfiles == null");
            return;
        }
        // 预览流宽高比要与录像流的宽高比一致，如果录制的是hdr视频，请筛选支持hdr的Camera\_VideoProfile。
        Camera\_VideoProfile\*\* videoProfiles = cameraOutputCapability->videoProfiles;
        for (int index = 0; index < cameraOutputCapability->videoProfilesSize; index++) {
            bool isEqual = IsAspectRatioEqual((float)videoProfiles\[index\]->size.width / videoProfiles\[index\]->size.height,
                (float)previewProfile->size.width / previewProfile->size.height);
            // 默认筛选CAMERA\_FORMAT\_YUV\_420\_SP的profile。
            if (isEqual && videoProfiles\[index\]->format == Camera\_Format::CAMERA\_FORMAT\_YUV\_420\_SP) {
                videoProfile = videoProfiles\[index\];
                OH\_LOG\_INFO(LOG\_APP, "videoProfile width: %{public}d, height: %{public}d.", videoProfile->size.width,
                    videoProfile->size.height);
                break;
            }
        }
        if (videoProfile == nullptr) {
            OH\_LOG\_ERROR(LOG\_APP, "Get videoProfile failed.");
            return;
        }
        // 创建VideoOutput对象。
        ret = OH\_CameraManager\_CreateVideoOutput(cameraManager, videoProfile, videoSurfaceId, &videoOutput);
        if (videoOutput == nullptr || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_CreateVideoOutput failed.");
            return;
        }
    
        // 监听视频输出错误信息。
        ret = OH\_VideoOutput\_RegisterCallback(videoOutput, GetVideoOutputListener());
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_VideoOutput\_RegisterCallback failed.");
        }
    
        // 创建会话。
        ret = OH\_CameraManager\_CreateCaptureSession(cameraManager, &captureSession);
        if (captureSession == nullptr || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_CreateCaptureSession failed.");
            return;
        }
        // 监听session错误信息。
        ret = OH\_CaptureSession\_RegisterCallback(captureSession, GetCaptureSessionRegister());
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_RegisterCallback failed.");
        }
    
        // 开始配置会话。
        ret = OH\_CaptureSession\_BeginConfig(captureSession);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_BeginConfig failed.");
            return;
        }
    
        // 创建相机输入流。
        ret = OH\_CameraManager\_CreateCameraInput(cameraManager, &cameras\[cameraDeviceIndex\], &cameraInput);
        if (cameraInput == nullptr || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_CreateCameraInput failed.");
            return;
        }
    
        // 监听cameraInput错误信息。
        ret = OH\_CameraInput\_RegisterCallback(cameraInput, GetCameraInputListener());
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraInput\_RegisterCallback failed.");
        }
    
        // 打开相机。
        ret = OH\_CameraInput\_Open(cameraInput);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraInput\_Open failed.");
            return;
        }
    
        // 向会话中添加相机输入流。
        ret = OH\_CaptureSession\_AddInput(captureSession, cameraInput);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_AddInput failed.");
            return;
        }
    
        // 创建预览输出流,其中参数 surfaceId 参考下面 XComponent 组件，预览流为XComponent组件提供的surface。
        ret = OH\_CameraManager\_CreatePreviewOutput(cameraManager, previewProfile, previewSurfaceId, &previewOutput);
        if (previewProfile == nullptr || previewOutput == nullptr || ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_CreatePreviewOutput failed.");
            return;
        }
    
        // 向会话中添加预览输出流。
        ret = OH\_CaptureSession\_AddPreviewOutput(captureSession, previewOutput);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_AddPreviewOutput failed.");
            return;
        }
    
        // 向会话中添加录像输出流。
        ret = OH\_CaptureSession\_AddVideoOutput(captureSession, videoOutput);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_AddVideoOutput failed.");
            return;
        }
    
        // 提交会话配置。
        ret = OH\_CaptureSession\_CommitConfig(captureSession);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_CommitConfig failed.");
            return;
        }
    
        // 启动会话。
        ret = OH\_CaptureSession\_Start(captureSession);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_Start failed.");
            return;
        }
    
        // 启动录像输出流。
        ret = OH\_VideoOutput\_Start(videoOutput);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_VideoOutput\_Start failed.");
            return;
        }
    
        // 开始录像 ts侧调用avRecorder.start()。
    
        // 停止录像输出流。
        ret = OH\_VideoOutput\_Stop(videoOutput);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_VideoOutput\_Stop failed.");
        }
    
        // 停止录像 ts侧调用avRecorder.stop()。
    
        // 停止当前会话。
        ret = OH\_CaptureSession\_Stop(captureSession);
        if (ret == CAMERA\_OK) {
            OH\_LOG\_INFO(LOG\_APP, "OH\_CaptureSession\_Stop success ");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_Stop failed. %d ", ret);
        }
    
        // 释放相机输入流。
        ret = OH\_CameraInput\_Close(cameraInput);
        if (ret == CAMERA\_OK) {
            OH\_LOG\_INFO(LOG\_APP, "OH\_CameraInput\_Close success ");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraInput\_Close failed. %d ", ret);
        }
    
        // 释放预览输出流。
        ret = OH\_PreviewOutput\_Release(previewOutput);
        if (ret == CAMERA\_OK) {
            OH\_LOG\_INFO(LOG\_APP, "OH\_PreviewOutput\_Release success ");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_PreviewOutput\_Release failed. %d ", ret);
        }
    
        // 释放录像输出流。
        ret = OH\_VideoOutput\_Release(videoOutput);
        if (ret == CAMERA\_OK) {
            OH\_LOG\_INFO(LOG\_APP, "OH\_VideoOutput\_Release success ");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_VideoOutput\_Release failed. %d ", ret);
        }
    
        // 释放会话。
        ret = OH\_CaptureSession\_Release(captureSession);
        if (ret == CAMERA\_OK) {
            OH\_LOG\_INFO(LOG\_APP, "OH\_CaptureSession\_Release success ");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CaptureSession\_Release failed. %d ", ret);
        }
    
        // 资源释放。
        ret = OH\_CameraManager\_DeleteSupportedCameras(cameraManager, cameras, size);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "Delete Cameras failed.");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_DeleteSupportedCameras. ok");
        }
        ret = OH\_CameraManager\_DeleteSupportedCameraOutputCapability(cameraManager, cameraOutputCapability);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "Delete Cameras failed.");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_CameraManager\_DeleteSupportedCameraOutputCapability success");
        }
        ret = OH\_Camera\_DeleteCameraManager(cameraManager);
        if (ret != CAMERA\_OK) {
            OH\_LOG\_ERROR(LOG\_APP, "Delete Cameras failed.");
        } else {
            OH\_LOG\_ERROR(LOG\_APP, "OH\_Camera\_DeleteCameraManager success");
        }
    }
    

#### 示例代码

*   录像示例代码请参考[NDKPhotoVideoSample(C/C++)](https://gitcode.com/HarmonyOS_Samples/guide-snippets/tree/master/CameraKit/NDKPhotoVideoSample)。