HarmonyOS鸿蒙Next NDK下打开相机报错CAMERA_SERVICE_FATAL_ERROR

HarmonyOS鸿蒙Next NDK下打开相机报错CAMERA_SERVICE_FATAL_ERROR 我在NDK下打开相机,在执行OH_CaptureSession_CommitConfig函数时返回CAMERA_SERVICE_FATAL_ERROR,实在找不到原因了。

demo下载地址:https://gitee.com/chen_yi_ze/harmony-camera-test.git

14 回复
  1. 你代码没打开相机,在获取相机输出能力前需打开。

  2. 预览分辨率选第一个。

改俩地就行

cke_1093.png

更多关于HarmonyOS鸿蒙Next NDK下打开相机报错CAMERA_SERVICE_FATAL_ERROR的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


哦,就是这个问题,感谢大神指点!!!!!!!!!!!!!!!!!

我看了你仓库里的代码,CAMERA_SERVICE_FATAL_ERROR 大概率不是“CommitConfig 本身有问题”,而是前面的输入流/输出流/会话模式组合不合法,等到 CommitConfig 时才被相机服务整体校验失败

你这份 demo 里至少有 3 个高概率问题

直接结论

最可疑的是这三处:

  1. Camera_Input 创建后没有 OH_CameraInput_Open(cameraInput)
  2. 你用 OH_CameraManager_GetSupportedCameraOutputCapabilityWithSceneMode(..., NORMAL_VIDEO, ...) 取了 NORMAL_VIDEO 的能力,却没有对 session 调 OH_CaptureSession_SetSessionMode(captureSession, NORMAL_VIDEO)
  3. 你硬编码取 previewProfiles[5],没有校验数组长度,也没有按 surface 宽高比匹配

这三项里,前两项是最容易直接导致 OH_CaptureSession_CommitConfig 返回 CAMERA_SERVICE_FATAL_ERROR 的。


你代码里的具体问题

你当前核心代码是这样:

  • CreateCameraInput
  • GetSupportedCameraOutputCapabilityWithSceneMode(..., NORMAL_VIDEO, ...)
  • selectedPreviewProfile = previewCap->previewProfiles[5]
  • CreatePreviewOutput
  • CreateCaptureSession
  • BeginConfig
  • AddInput
  • AddPreviewOutput
  • CommitConfig

但和官方 NDK 样例比,少了两个关键步骤:

1. 缺少 OH_CameraInput_Open

官方拍照 NDK 样例在 CreateCameraInput 之后,明确会调用:

  • OH_CameraInput_RegisterCallback(...)
  • OH_CameraInput_Open(cameraInput)

你当前代码没有 open,相机输入流很可能还没进入可用状态,就被加入 session 了。
参考官方 C/C++ 拍照实践样例:Photo Capture Practices (C/C++)

2. 缺少 OH_CaptureSession_SetSessionMode

官方会话管理文档明确建议:

  • CreateCaptureSession 后,立即调用 OH_CaptureSession_SetSessionMode()
  • 并且这个接口不能在 BeginConfig 之后调用

你的代码拿能力时已经指定了 NORMAL_VIDEO

C++

OH_CameraManager_GetSupportedCameraOutputCapabilityWithSceneMode(
    cameraManager, selectedCamera, NORMAL_VIDEO, &previewCap
);

但 session 本身没有设置成 NORMAL_VIDEO。这会导致:

  • 你拿的是视频场景下支持的 output profile
  • 但 session 仍处于默认/未明确设置的模式
  • CommitConfig 时服务端发现输入输出组合与 session mode 不一致,直接整体拒绝

参考:

3. previewProfiles[5] 非常危险

你这里:

Camera_Profile * selectedPreviewProfile = previewCap->previewProfiles[5];

问题有两个:

  • 没检查 previewProfilesSize 是否大于 5
  • 即使数组够长,第 6 个 profile 也未必适合当前 XComponentsurfaceId

官方预览文档的示例是:

  • previewProfiles 里选可用的 profile
  • 通常选第一项,或者按 surface 宽高比 匹配
    参考:预览(C/C++)

如果 profile 和 surface 不匹配,有些设备不会在 CreatePreviewOutput 时报错,而是到 CommitConfig 才炸。


我建议你先这样改

如果你现在只是想“先把预览跑起来”,最小修复方案如下:

修复版调用顺序

Camera_Manager *cameraManager = nullptr;
Camera_Input *cameraInput = nullptr;
Camera_CaptureSession *captureSession = nullptr;
Camera_PreviewOutput *previewOutput = nullptr;
Camera_OutputCapability *previewCap = nullptr;

ret = OH_Camera_GetCameraManager(&cameraManager);

ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameraDevices, &size);
Camera_Device *selectedCamera = &cameraDevices[0];

ret = OH_CameraManager_CreateCameraInput(cameraManager, selectedCamera, &cameraInput);
if (ret != CAMERA_OK || cameraInput == nullptr) {
    return nullptr;
}

ret = OH_CameraInput_Open(cameraInput);
if (ret != CAMERA_OK) {
    return nullptr;
}

// 如果你要走 NORMAL_VIDEO,就 session 也设成 NORMAL_VIDEO
ret = OH_CameraManager_GetSupportedCameraOutputCapabilityWithSceneMode(
    cameraManager, selectedCamera, NORMAL_VIDEO, &previewCap
);

if (ret != CAMERA_OK || previewCap == nullptr || previewCap->previewProfilesSize == 0) {
    return nullptr;
}

// 先不要取 [5],先取 [0] 验证流程
Camera_Profile *selectedPreviewProfile = previewCap->previewProfiles[0];

ret = OH_CameraManager_CreatePreviewOutput(
    cameraManager, selectedPreviewProfile, surfaceId, &previewOutput
);
if (ret != CAMERA_OK || previewOutput == nullptr) {
    return nullptr;
}

ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession);
if (ret != CAMERA_OK || captureSession == nullptr) {
    return nullptr;
}

ret = OH_CaptureSession_SetSessionMode(captureSession, NORMAL_VIDEO);
if (ret != CAMERA_OK) {
    return nullptr;
}

ret = OH_CaptureSession_BeginConfig(captureSession);
if (ret != CAMERA_OK) {
    return nullptr;
}

ret = OH_CaptureSession_AddInput(captureSession, cameraInput);
if (ret != CAMERA_OK) {
    return nullptr;
}

ret = OH_CaptureSession_AddPreviewOutput(captureSession, previewOutput);
if (ret != CAMERA_OK) {
    return nullptr;
}

ret = OH_CaptureSession_CommitConfig(captureSession);
if (ret != CAMERA_OK) {
    return nullptr;
}

ret = OH_CaptureSession_Start(captureSession);

进一步建议

1. 不要只看 CommitConfig 的错误

你现在每一步都在覆盖 ret,但几乎没判断。
建议每一步都立即判错打印,否则前面某一步已经失败,你最后只看到 CommitConfig,会误判。

2. 先加 CanAdd... 预检查

官方 API 里有:

  • OH_CaptureSession_CanAddInput
  • OH_CaptureSession_CanAddPreviewOutput

你可以在 AddInput / AddPreviewOutput 前先判断,会比直接到 CommitConfig 才炸更容易定位。
参考:capture_session.h

3. 给 session / preview / input 注册错误回调

官方样例里都注册了回调:

  • OH_CaptureSession_RegisterCallback
  • OH_PreviewOutput_RegisterCallback
  • OH_CameraInput_RegisterCallback

这样很多“服务拒绝原因”会在日志里更早暴露。
参考:Photo Capture Practices (C/C++)

4. 检查 surfaceId

你是从 XComponentController.getXComponentSurfaceId() 直接拿的。
虽然你是在点击后调用,通常时机问题不大,但还是建议打印确认:

  • surfaceId != nullptr
  • strlen(surfaceId) > 0

我认为你这个 demo 最可能的根因排序

按概率排,我会这样判断:

  1. 未调用 OH_CameraInput_Open(cameraInput)
  2. GetSupportedCameraOutputCapabilityWithSceneMode(NORMAL_VIDEO) 和 session 未 SetSessionMode(NORMAL_VIDEO) 不一致
  3. previewProfiles[5] 选到了不兼容当前 surface 的 profile

你这个回答太详细了,非常好,就是这个原因!

开发者你好,根据你的问题推测可能的原因大概率是:相机资源抢占、生命周期管理混乱、配置参数非法、权限缺失、前后台切换未正确释放资源,您可以根据这些问题排查下看看是否可以解决。

我本人看来这些问题都没有。

开发者你好,当前使用你这边提供的代码,增加判断OH_CaptureSession_CommitConfig是否异常,并没有出现CAMERA_SERVICE_FATAL_ERROR的报错。

// 提交配置
ret = OH_CaptureSession_CommitConfig(
    captureSession); // 这里报错:CAMERA_SERVICE_FATAL_ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
if (ret != CAMERA_OK) {
    OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed.");
}

麻烦提供一下完整hilog日志。 hilog日志获取: 在IDE右下角DeviceFileBrowser, 路径:data-log-hilog, 对应时间段的hilog(不是hilog_kmsg)开头的日志 还有 hilog_dict-- 文件

感谢您的回答,我按照5楼的方法已经解决了。

应该先确认OH_CaptureSession_CommitConfig 返回 CAMERA_SERVICE_FATAL_ERROR,给的是什么错误码是底层相机服务发生了崩溃还是相机进入了无法恢复的状态。

建议可以尝试用HiLog日志或者删代码方法排查

感谢您的回答,我按照5楼的方法已经解决了。

你这个问题 ,真费时间啊, 给个采纳吧谢谢 效果图,我重写了你的 napi_init.cpp ,

你的代码的问题:

StartCommitConfig 之前导致 CAMERA_SERVICE_FATAL_ERROR

hardcode previewProfiles[5]如果设备只有 3 个配置会越界崩溃

无 Release 函数相机打开后无法释放

然后我就重写了一下 你看下你是 先自己研究一下, 还是我把代码文件给你

cke_1763.jpeg

非常感谢您的回答,我按照5楼的方法已经解决了。

CAMERA_SERVICE_FATAL_ERROR 表示相机服务进程发生致命错误。常见原因:应用未在 module.json5 中声明 ohos.permission.CAMERA 权限或未在运行时动态授予;NDK 相机接口 OH_Camera_InitializeOH_Camera_CreateInput 传入无效参数(如 cameraId 为空或 surface 格式不匹配);系统相机服务因资源竞争或驱动异常崩溃。

该错误通常是因为在调用 CommitConfig 前未向 CaptureSession 添加任何输出流,或传入的 surface 无效。请检查以下点:

  1. 必须至少添加一个 PreviewOutput 或 PhotoOutput:OH_CaptureSession_AddPreviewOutput / OH_CaptureSession_AddPhotoOutput,且在 CommitConfig 之前至少添加一个。
  2. 确保 surface 有效:surface 必须由 XComponent 的 surfaceId 通过 OH_NativeWindow_CreateNativeWindowFromSurfaceId 创建,且分辨率需是相机支持的分辨率(可通过 OH_CameraManager_GetSupportedSceneModes 等查询)。
  3. 确认已在 module.json5 中声明 ohos.permission.CAMERA 权限,并在运行时动态申请。
  4. 不要重复提交同一个 session;若需更改配置,先 Stop 再重新 Commit

若上述步骤均正确,仍可能因 surface 尺寸与当前相机能力不匹配导致服务终止,请尝试使用典型预览尺寸如 1920×1080。

回到顶部