21:46:12.532 10809-10809 C03931/com.exa...AceXcomponent com.example.hm I [(100000:100000:scope)] XComponent[previewWindow] native OnSurfaceCreated
21:46:12.764 11213-11213 A05612/commonUI/ASP com.huawe...commonUI I [SPC][PermissionDialog][ViewModel]: group: CAMERA, title: 允许“demo”访问你的相机?, reason: 拍照.
在初次授权时,重新调用相机的初始化流程。可以通过授权返回结果中dialogShownResults的值是否为true,判断当前是否是初次授权弹窗状态。
getPermission(permissions: Permissions[]): Promise<boolean> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let context: Context = this.uiContext.getHostContext() as common.UIAbilityContext;
return new Promise((resolve) => {
atManager.requestPermissionsFromUser(context, permissions,
(err: BusinessError, data: PermissionRequestResult) => {
if (err) {
console.log(`previewstreamsdemotest requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
return resolve(false);
} else {
console.info('PermissionRequestResult data:' + JSON.stringify(data));
if (data.authResults[0] != 0) {
return resolve(false);
}
// 第一次授权时候切换通道
if (data.dialogShownResults !== undefined &&
data.dialogShownResults[0] === true &&
data.authResults[0] === 0) {
console.info('previewstreamsdemotest 已切换摄像头通道');
this.PreviewCamera.switchChannel();
this.channelId = this.PreviewCamera.GETCHANNELID();
this.channelWidth = this.PreviewCamera.GETCHANNELWIDTH();
this.channelHeight = this.PreviewCamera.GETCHANNELHEIGHT();
}
return resolve(true);
}
});
});
} PermissionRequestResult data:{"permissions":["ohos.permission.CAMERA"],"authResults":[0],"dialogShownResults":[true]}
PermissionRequestResult data:{"permissions":["ohos.permission.CAMERA"],"authResults":[-1],"dialogShownResults":[true]}
PermissionRequestResult data:{"permissions":["ohos.permission.CAMERA"],"authResults":[0],"dialogShownResults":[false]}
完整代码示例如下:
export const add: (a: number, b: number) => number; export const switchChannel: () => void; export const GETCHANNELID: () => number; export const GETCHANNELWIDTH: () => number; export const GETCHANNELHEIGHT: () => number;
import abilityAccessCtrl, { Context, PermissionRequestResult, Permissions } from '@ohos.abilityAccessCtrl';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';
import camera from '@ohos.multimedia.camera';
@Entry
@Component
struct Index {
previewController: XComponentController = new XComponentController;
photoController: XComponentController = new XComponentController;
surfaceId: string = '';
isUserAgent: boolean = false;
uiContext = this.getUIContext();
@State channelId: number = 0;
@State channelWidth: number = 480;
@State channelHeight: number = 480;
pixelMap: PixelMap | undefined = undefined;
photoOutput: camera.PhotoOutput | undefined = undefined;
private PreviewCamera: ESObject;
private isAuthorized: boolean = false;
getPermission(permissions: Permissions[]): Promise<boolean> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let context: Context = this.uiContext.getHostContext() as common.UIAbilityContext;
return new Promise((resolve) => {
atManager.requestPermissionsFromUser(context, permissions,
(err: BusinessError, data: PermissionRequestResult) => {
if (err) {
console.log(`previewstreamsdemotest requestPermissionsFromUser fail, err->${JSON.stringify(err)}`);
return resolve(false);
} else {
console.info('PermissionRequestResult data:' + JSON.stringify(data));
if (data.authResults[0] != 0) {
return resolve(false);
}
// 第一次授权时候切换通道
if (data.dialogShownResults !== undefined &&
data.dialogShownResults[0] === true &&
data.authResults[0] === 0) {
console.info('previewstreamsdemotest 已切换摄像头通道');
this.PreviewCamera.switchChannel();
this.channelId = this.PreviewCamera.GETCHANNELID();
this.channelWidth = this.PreviewCamera.GETCHANNELWIDTH();
this.channelHeight = this.PreviewCamera.GETCHANNELHEIGHT();
}
return resolve(true);
}
});
});
}
aboutToAppear(): void {
//user_grant用户授权
this.getPermission(['ohos.permission.CAMERA']).then(async (res) => {
if (!res) {
this.isAuthorized = false;
let context = this.uiContext.getHostContext() as common.UIAbilityContext;
context.startAbility({
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: 'application_info_entry', //application_settings application_info_entry systemui_notification_settings
parameters: {
pushParams: 'com.example.previewstreamsdemo'
}
});
return;
}
this.isAuthorized = true;
});
}
aboutToDisappear(): void {
}
build() {
Column() {
XComponent({
id: 'previewWindow',
type: XComponentType.SURFACE,
libraryname: 'entry',
controller: this.previewController,
})
.onLoad((es: ESObject) => {
this.PreviewCamera = es;
let a: SurfaceRect = {
offsetX: 10, // X 偏移量
offsetY: 20, // Y 偏移量
surfaceWidth: 1080, // Surface 宽度
surfaceHeight: 1440 // Surface 高度//
};
this.previewController.setXComponentSurfaceRect(a);
console.info('sf test XComponent has been inited');
})
.width('1080px')
.height('1440px');
Button('切换摄像头通道').onClick(() => {
console.info('已切换摄像头通道');
if (this.isAuthorized) {
this.PreviewCamera.switchChannel();
this.channelId = this.PreviewCamera.GETCHANNELID();
this.channelWidth = this.PreviewCamera.GETCHANNELWIDTH();
this.channelHeight = this.PreviewCamera.GETCHANNELHEIGHT();
let a = this.previewController.getXComponentSurfaceRect();
console.info('sf test' + a.surfaceWidth.toString());
}
});
Text('通道:' + this.channelId);
Text('通道像素宽度:' + this.channelWidth);
Text('通道像素高度:' + this.channelHeight);
}.justifyContent(FlexAlign.SpaceAround)
.height('100%')
.width('100%');
}
} /*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ace/xcomponent/native_interface_xcomponent.h>
#include "napi/native_api.h"
#include "hilog/log.h"
#include "camera.h"
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0x3200 // 全局domain宏,标识业务领域
#define LOG_TAG "MY_TAG" // 全局tag宏,标识模块日志tag
NDKCamera *g_camera;
static napi_value Add(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
napi_valuetype valuetype0;
napi_typeof(env, args[0], &valuetype0);
napi_valuetype valuetype1;
napi_typeof(env, args[1], &valuetype1);
double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
napi_value sum;
napi_create_double(env, value0 + value1, &sum);
return sum;
}
static napi_value switchChannel(napi_env env, napi_callback_info info)
{
if (g_camera == nullptr) {
g_camera = NDKCamera::GetInstance();
if (g_camera == nullptr) {
return nullptr;
}
}
g_camera->SwitchPreviewChannel();
return nullptr;
}
static napi_value GETCHANNELID(napi_env env, napi_callback_info info)
{
napi_value napi_id;
int32_t id;
if (g_camera == nullptr) {
g_camera = NDKCamera::GetInstance();
if (g_camera == nullptr) {
return nullptr;
}
}
id = g_camera->GETCHANNELID();
if (napi_ok != napi_create_int32(env, id, &napi_id)) {
OH_LOG_ERROR(LOG_APP, "GETCHANNELID:napi_create_int32 failed");
return nullptr;
}
return napi_id;
}
static napi_value GETCHANNELWIDTH(napi_env env, napi_callback_info info)
{
napi_value napi_width;
int32_t width;
if (g_camera == nullptr) {
g_camera = NDKCamera::GetInstance();
if (g_camera == nullptr) {
return nullptr;
}
}
width = g_camera->GETCHANNELWIDTH();
if (napi_ok != napi_create_int32(env, width, &napi_width)) {
OH_LOG_ERROR(LOG_APP, "GETCHANNELWIDTH:napi_create_int32 failed");
return nullptr;
}
return napi_width;
}
static napi_value GETCHANNELHEIGHT(napi_env env, napi_callback_info info)
{
napi_value napi_height;
int32_t height;
if (g_camera == nullptr) {
g_camera = NDKCamera::GetInstance();
if (g_camera == nullptr) {
return nullptr;
}
}
height = g_camera->GETCHANNELHEIGHT();
if (napi_ok != napi_create_int32(env, height, &napi_height)) {
OH_LOG_ERROR(LOG_APP, "GETCHANNELHEIGHT:napi_create_int32 failed");
return nullptr;
}
return napi_height;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr},
{"switchChannel", nullptr, switchChannel, nullptr, nullptr, nullptr, napi_default, nullptr},
{"GETCHANNELID", nullptr, GETCHANNELID, nullptr, nullptr, nullptr, napi_default, nullptr},
{"GETCHANNELWIDTH", nullptr, GETCHANNELWIDTH, nullptr, nullptr, nullptr, napi_default, nullptr},
{"GETCHANNELHEIGHT", nullptr, GETCHANNELHEIGHT, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
napi_value exportInstance = nullptr;
// 用来解析出被wrap了NativeXComponent指针的属性
napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
OH_NativeXComponent *nativeXComponent = nullptr;
// 通过napi_unwrap接口,解析出NativeXComponent的实例指针
napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent));
// 获取XComponentId
char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize);
OH_NativeXComponent_Callback *callback = new OH_NativeXComponent_Callback();
callback->OnSurfaceCreated = OnSurfaceCreatedCB;
callback->OnSurfaceChanged = OnSurfaceChangedCB;
callback->OnSurfaceDestroyed = OnSurfaceDestroyedCB;
callback->DispatchTouchEvent = DispatchTouchEventCB;
// 注册回调函数
OH_NativeXComponent_RegisterCallback(nativeXComponent, callback);
g_camera = NDKCamera::GetInstance();
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void *)0),
.reserved = {0},
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); } /*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*/
#include <cstdint>
#include <cstring>
#include <sstream>
#include <sys/mman.h>
#include <accesstoken/ability_access_control.h>
#include "hilog/log.h"
#include "camera.h"
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0x3200 // 全局domain宏,标识业务领域
#define LOG_TAG "MY_TAG" // 全局tag宏,标识模块日志tag
OHNativeWindow *g_nativeWindow = nullptr;
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 PreviewOutputOnFrameStart(Camera_PreviewOutput *previewOutput)
{
OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameStart");
}
void PreviewOutputOnFrameEnd(Camera_PreviewOutput *previewOutput, int32_t frameCount)
{
OH_LOG_INFO(LOG_APP, "PreviewOutputOnFrameEnd = %{public}d", frameCount);
}
void PreviewOutputOnError(Camera_PreviewOutput *previewOutput, Camera_ErrorCode errorCode)
{
OH_LOG_INFO(LOG_APP, "PreviewOutputOnError = %{public}d", errorCode);
}
PreviewOutput_Callbacks *GetPreviewOutputListener(void)
{
static PreviewOutput_Callbacks previewOutputListener = {.onFrameStart = PreviewOutputOnFrameStart,
.onFrameEnd = PreviewOutputOnFrameEnd,
.onError = PreviewOutputOnError};
return &previewOutputListener;
}
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 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;
}
// YUV到RGB的转换公式
int YUV2RGBA(unsigned char y, unsigned char u, unsigned char v)
{
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
r = (unsigned char)(y + 1.4075 * (v - 128));
g = (unsigned char)(y - 0.34455 * (u - 128) - 0.7169 * (v - 128));
b = (unsigned char)(y + 1.779 * (u - 128));
// 构建RGBA整数值
return (0xff << 24) | (int)(r << 16) | (int)(g << 8) | (int)b;
}
// 将YUV420数据转换为RGBA整数值
void YUV420ToRGBAInt(unsigned char *src, int *dst, int width, int height, int stride)
{
unsigned char *pY = src;
unsigned char *pU = src + width * height;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned char u = pU[(y / 2) * width + (x / 2) * 2];
unsigned char v = pU[(y / 2) * width + (x / 2) * 2 + 1];
dst[y * stride + x] = YUV2RGBA(pY[y * width + x], u, v);
}
}
}
static void OnCallback(OH_ImageReceiverNative *receiver)
{
int32_t yStride, uStride, vStride, sWidth, sHeight;
// 读取 OH_ImageReceiverNative 的下一个图片对象
OH_ImageNative *image = nullptr;
OH_ImageReceiverNative_ReadNextImage(receiver, &image);
// 读取 OH_ImageNative 的 size 属性
Image_Size size;
OH_ImageNative_GetImageSize(image, &size);
sWidth = size.width;
sHeight = size.height;
OH_LOG_ERROR(LOG_APP, "size [%{public}s]:[%{public}u],sWidth [%{public}d],sHeight [%{public}d]", __FUNCTION__,
__LINE__, sWidth, sHeight);
// 读取 OH_ImageNative 的组件列表的元素个数。
size_t componentTypeSize = 0;
OH_ImageNative_GetComponentTypes(image, nullptr, &componentTypeSize);
// 读取 OH_ImageNative 的组件列表。
uint32_t *componentTypes = new uint32_t[componentTypeSize];
OH_ImageNative_GetComponentTypes(image, &componentTypes, &componentTypeSize);
uint32_t component = componentTypes[0];
// 读取 OH_ImageNative 的第一个组件所对应的缓冲区对象。
OH_NativeBuffer *nativeBuffer = nullptr;
OH_ImageNative_GetByteBuffer(image, component, &nativeBuffer);
OH_ImageNative_GetRowStride(image, component, &yStride);
uStride = yStride;
vStride = yStride;
void *srcVir = nullptr;
OH_NativeBuffer_Map(nativeBuffer, &srcVir);
uint8_t *srcBuffer = static_cast<uint8_t *>(srcVir);
if (yStride != size.width) {
// 传给其他支持stride的接口处理,或去除stride数据
// 去除stride数据示例:将byteBuffer中的数据去除stride,拷贝得到新的dstBuffer数据
size_t dstBufferSize = size.width * size.height * 1.5; // 相机预览流返回NV21格式
std::unique_ptr<uint8_t[]> dstBuffer = std::make_unique<uint8_t[]>(dstBufferSize);
uint8_t *dstPtr = dstBuffer.get();
for (int j = 0; j < size.height * 1.5; j++) {
std::copy_n(static_cast<const uint8_t*>(srcBuffer), size.width, static_cast<uint8_t*>(dstPtr));
dstPtr += size.width;
srcBuffer += yStride;
}
srcBuffer = dstBuffer.get();
}
OH_LOG_ERROR(LOG_APP, "local [%{public}s]:[%{public}u],sWidth [%{public}d],yStride [%{public}d]", __FUNCTION__,
__LINE__, sWidth, yStride);
OHNativeWindow *nativeWindow;
OH_LOG_ERROR(LOG_APP, "local [%{public}s]:[%{public}u], [%{public}p]", __FUNCTION__, __LINE__, g_nativeWindow);
// 设置 OHNativeWindowBuffer 的宽高
int32_t code = SET_BUFFER_GEOMETRY;
// 这里的nativeWindow是从上一步骤中的回调函数中获得的
int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(g_nativeWindow, code, sWidth, sHeight);
code = GET_BUFFER_GEOMETRY;
int32_t h, w;
// 这里的nativeWindow是从上一步骤中的回调函数中获得的
ret = OH_NativeWindow_NativeWindowHandleOpt(g_nativeWindow, code, &h, &w);
OH_LOG_ERROR(LOG_APP, "local H W[%{public}s]:[%{public}u], [%{public}d] [%{public}d]", __FUNCTION__, __LINE__, h,
w);
code = SET_TRANSFORM;
int32_t transform = NATIVEBUFFER_ROTATE_270;
ret = OH_NativeWindow_NativeWindowHandleOpt(g_nativeWindow, code, transform);
OHNativeWindowBuffer *buffer = nullptr;
int releaseFenceFd = -1;
// 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
ret = OH_NativeWindow_NativeWindowRequestBuffer(g_nativeWindow, &buffer, &releaseFenceFd);
if (ret != 0 || buffer == nullptr) {
return;
}
// 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
BufferHandle *bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
// 使用系统接口mmap将bufferHandle对应的共享内存映射到用户空间,可以通过映射出来的虚拟地址向bufferHandle中写入图像数据
// bufferHandle->virAddr是bufferHandle在共享内存中的起始地址,bufferHandle->size是bufferHandle在共享内存中的内存占用大小
void *mappedAddr =
mmap(bufferHandle->virAddr, (bufferHandle->size), PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0);
if (mappedAddr == MAP_FAILED) {
return;
}
OH_LOG_ERROR(LOG_APP, "local size [%{public}s]:[%{public}u], [%{public}d]", __FUNCTION__, __LINE__,
(bufferHandle->size));
YUV420ToRGBAInt(srcBuffer, (int *)mappedAddr, sWidth, sHeight, bufferHandle->stride / 4);
// 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
Region region{nullptr, 0};
// 通过OH_NativeWindow_NativeWindowFlushBuffer提交给消费者使用,例如:显示在屏幕上。
OH_NativeWindow_NativeWindowFlushBuffer(g_nativeWindow, buffer, -1, region);
// 内存使用完记得去掉内存映射
int result = munmap(mappedAddr, (bufferHandle->size));
if (result == -1) {
return;
}
OH_NativeBuffer_Unmap(nativeBuffer);
int errCode = OH_ImageNative_Release(image);
OH_LOG_ERROR(LOG_APP, "zhulin local [%{public}s]:[%{public}u], [%{public}d] ok", __FUNCTION__, __LINE__, errCode);
}
NDKCamera *g_ndkCamera = nullptr;
NDKCameraErrorCode NDKCamera::Init()
{
uint32_t size = 0;
// 创建CameraManager对象
Camera_ErrorCode ret = OH_Camera_GetCameraManager(&_cameraManager);
if (_cameraManager == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_Camera_GetCameraMananger failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 监听相机状态变化
ret = OH_CameraManager_RegisterCallback(_cameraManager, GetCameraManagerListener());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_RegisterCallback failed.");
return ERROR_FAILED;
}
// 获取相机列表
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 ERROR_FAILED;
}
for (int i = 0; i < size; i++) {
OH_LOG_ERROR(
LOG_APP,
"OH_CameraManager_GetSupportedCameras camera %{public}d.Pos: %{public}d,Type: %{public}d,Conn: %{public}d",
i, _cameras[i].cameraPosition, _cameras[i].cameraType, _cameras[i].connectionType);
}
// 创建相机输入流
ret = OH_CameraManager_CreateCameraInput(_cameraManager, &_cameras[cameraDeviceIndex], &_cameraInput);
if (_cameraInput == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed.");
return ERROR_FAILED;
}
// 监听cameraInput错误信息
ret = OH_CameraInput_RegisterCallback(_cameraInput, GetCameraInputListener());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed.");
return ERROR_FAILED;
}
// 打开相机
ret = OH_CameraInput_Open(_cameraInput);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed.");
return ERROR_FAILED;
}
// 获取相机设备支持的输出流能力
ret = OH_CameraManager_GetSupportedCameraOutputCapability(_cameraManager, &_cameras[cameraDeviceIndex],
&_cameraOutputCapability);
if (_cameraOutputCapability == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameraOutputCapability failed.");
return ERROR_FAILED;
}
uint32_t cameraOrientitaion;
ret = OH_CameraDevice_GetCameraOrientation(&_cameras[cameraDeviceIndex], &cameraOrientitaion);
if (_cameraOutputCapability->previewProfilesSize < 0) {
OH_LOG_ERROR(LOG_APP, "previewProfilesSize == null");
return ERROR_FAILED;
}
for (int i = 0; i < _cameraOutputCapability->previewProfilesSize; i++) {
OH_LOG_INFO(LOG_APP, "%{public}d: previewProfile width:%{public}d height:%{public}d format:%{public}d ", i,
_cameraOutputCapability->previewProfiles[i]->size.width,
_cameraOutputCapability->previewProfiles[i]->size.height,
_cameraOutputCapability->previewProfiles[i]->format);
if (CAMERA_FORMAT_YUV_420_SP == _cameraOutputCapability->previewProfiles[i]->format) {
previewProfile = _cameraOutputCapability->previewProfiles[i];
}
}
for (int i = 0; i < _cameraOutputCapability->photoProfilesSize; i++) {
OH_LOG_INFO(LOG_APP, "%{public}d: photoProfile width:%{public}d height:%{public}d format:%{public}d ", i,
_cameraOutputCapability->photoProfiles[i]->size.width,
_cameraOutputCapability->photoProfiles[i]->size.height,
_cameraOutputCapability->photoProfiles[i]->format);
if (CAMERA_FORMAT_YUV_420_SP == _cameraOutputCapability->photoProfiles[i]->format) {
previewProfile = _cameraOutputCapability->photoProfiles[i];
}
}
previewProfile = _cameraOutputCapability->previewProfiles[previewProfileId];
if (_cameraOutputCapability->photoProfilesSize < 0) {
OH_LOG_ERROR(LOG_APP, "photoProfilesSize == null");
}
_photoProfile = _cameraOutputCapability->photoProfiles[photoProfileId];
Image_ErrorCode ErrCode;
Image_Size imageSize = {previewProfile->size.width, previewProfile->size.height};
ErrCode = OH_ImageReceiverOptions_Create(&_options);
if (IMAGE_SUCCESS != ErrCode) {
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_Create failed.ErrCode %{public}d", ErrCode);
return ERROR_FAILED;
}
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_Create success.options 0x%{public}p", _options);
ErrCode = OH_ImageReceiverOptions_SetSize(_options, imageSize);
if (IMAGE_SUCCESS != ErrCode) {
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_SetSize failed.ErrCode %{public}d", ErrCode);
return ERROR_FAILED;
}
ErrCode = OH_ImageReceiverOptions_SetCapacity(_options, 8);
if (IMAGE_SUCCESS != ErrCode) {
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_SetCapacity failed.ErrCode %{public}d", ErrCode);
}
// 读取 OH_ImageReceiverOptions 的 capacity 属性
int32_t capacity = 0;
ErrCode = OH_ImageReceiverOptions_GetCapacity(_options, &capacity);
if (ErrCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP,
"ImageReceiverNativeCTest get image receiver options capacity failed, errCode: %{public}d.",
ErrCode);
OH_ImageReceiverOptions_Release(_options);
return ERROR_FAILED;
}
// 检查读取到的 capacity 值是否为设定值
if (capacity != 8) {
OH_LOG_ERROR(LOG_APP,
"ImageReceiverNativeCTest get image receiver options capacity failed, capacity: %{public}d.",
capacity);
OH_ImageReceiverOptions_Release(_options);
return ERROR_FAILED;
}
ErrCode = OH_ImageReceiverNative_Create(_options, &_receiver);
if (IMAGE_SUCCESS != ErrCode) {
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_Create failed.ErrCode %{public}d", ErrCode);
}
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_Create success.receiver 0x%{public}p", _receiver);
ErrCode = OH_ImageReceiverNative_On(_receiver, OnCallback);
if (ErrCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "ImageReceiverNativeCTest image receiver on failed, errCode: %{public}d.", ErrCode);
OH_ImageReceiverOptions_Release(_options);
OH_ImageReceiverNative_Release(_receiver);
return ERROR_FAILED;
}
ErrCode = OH_ImageReceiverNative_GetReceivingSurfaceId(_receiver, &imageReceiverSurfaceId);
if (ErrCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP,
"OH_ImageReceiverNative_GetReceivingSurfaceId image receiver on failed, errCode: %{public}d.",
ErrCode);
OH_ImageReceiverOptions_Release(_options);
OH_ImageReceiverNative_Release(_receiver);
return ERROR_FAILED;
}
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_GetReceivingSurfaceId imageReceiverSurfaceId %{public}lu",
imageReceiverSurfaceId);
std::ostringstream surfaceIDString;
surfaceIDString << imageReceiverSurfaceId;
// 创建预览输出流
ret = OH_CameraManager_CreatePreviewOutput(_cameraManager, previewProfile, surfaceIDString.str().c_str(),
&_previewOutput);
if (previewProfile == nullptr || _previewOutput == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed.");
return ERROR_FAILED;
} else {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput success.previewSurfaceId : %{public}s",
surfaceIDString.str().c_str());
}
// 监听预览输出错误信息
ret = OH_PreviewOutput_RegisterCallback(_previewOutput, GetPreviewOutputListener());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed.");
return ERROR_FAILED;
}
// 创建会话
ret = OH_CameraManager_CreateCaptureSession(_cameraManager, &_captureSession);
if (_captureSession == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 监听session错误信息
ret = OH_CaptureSession_RegisterCallback(_captureSession, GetCaptureSessionRegister());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 开始配置会话
ret = OH_CaptureSession_BeginConfig(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 向会话中添加相机输入流
ret = OH_CaptureSession_AddInput(_captureSession, _cameraInput);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddInput failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 向会话中添加预览输出流
ret = OH_CaptureSession_AddPreviewOutput(_captureSession, _previewOutput);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 提交会话配置
ret = OH_CaptureSession_CommitConfig(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 启动会话
ret = OH_CaptureSession_Start(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
return ERROR_SUCCESS;
}
// 定义回调函数
void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
{
// 可获取 OHNativeWindow 实例
g_nativeWindow = static_cast<OHNativeWindow *>(window);
// 此回调触发后,window默认引用计数会设置为1,若存在并发使用了window相关的接口和xcompnent析构的情况,
// 则需要通过OH_NativeWindow_NativeObjectReference和OH_NativeWindow_NativeObjectUnreference对window进行
// 手动引用计数加1和减1,防止xcomponent析构后,并发调用window相关接口触发野指针或空指针的崩溃。
}
void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window)
{
// 可获取 OHNativeWindow 实例
g_nativeWindow = static_cast<OHNativeWindow *>(window);
// ...
}
void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window)
{
// 可获取 OHNativeWindow 实例
OHNativeWindow *nativeWindow = static_cast<OHNativeWindow *>(window);
// 此回调触发后,会将window进行引用计数减1的操作,当window的应用计数为0后,会触发window的析构,
// window析构后,不可再通过window进行接口调用,否则可能会触发野指针或空指针的崩溃。
}
void DispatchTouchEventCB(OH_NativeXComponent *component, void *window)
{
// 可获取 OHNativeWindow 实例
OHNativeWindow *nativeWindow = static_cast<OHNativeWindow *>(window);
// ...
}
NDKCameraErrorCode NDKCamera::SwitchPreviewChannel()
{
Camera_ErrorCode ret;
Image_ErrorCode ErrCode;
if (NULL == _cameraOutputCapability) {
return ERROR_FAILED;
}
if (_cameraOutputCapability->previewProfilesSize < 0) {
OH_LOG_ERROR(LOG_APP, "previewProfilesSize == null");
return ERROR_FAILED;
}
previewProfileId = (previewProfileId + 1) % _cameraOutputCapability->previewProfilesSize;
previewProfile = _cameraOutputCapability->previewProfiles[previewProfileId];
if (NULL == _options) {
return ERROR_FAILED;
}
// 创建相机输入流
ret = OH_CameraManager_CreateCameraInput(_cameraManager, &_cameras[cameraDeviceIndex], &_cameraInput);
if (_cameraInput == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed.");
return ERROR_FAILED;
}
// 监听cameraInput错误信息
ret = OH_CameraInput_RegisterCallback(_cameraInput, GetCameraInputListener());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraInput_RegisterCallback failed.");
return ERROR_FAILED;
}
// 打开相机
ret = OH_CameraInput_Open(_cameraInput);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraInput_Open failed.");
return ERROR_FAILED;
}
Image_Size imageSize = {previewProfile->size.width, previewProfile->size.height};
ErrCode = OH_ImageReceiverOptions_SetSize(_options, imageSize);
if (IMAGE_SUCCESS != ErrCode) {
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_SetSize failed.ErrCode %{public}d", ErrCode);
return ERROR_FAILED;
}
// 释放之前创建的_receiver
OH_ImageReceiverNative_Release(_receiver);
// 根据新的profile重新创建_receiver
ErrCode = OH_ImageReceiverNative_Create(_options, &_receiver);
if (IMAGE_SUCCESS != ErrCode) {
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_Create failed.ErrCode %{public}d", ErrCode);
return ERROR_FAILED;
}
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_Create success.receiver 0x%{public}p", _receiver);
ErrCode = OH_ImageReceiverNative_On(_receiver, OnCallback);
if (ErrCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "ImageReceiverNativeCTest image receiver on failed, errCode: %{public}d.", ErrCode);
OH_ImageReceiverOptions_Release(_options);
OH_ImageReceiverNative_Release(_receiver);
return ERROR_FAILED;
}
ErrCode = OH_ImageReceiverNative_GetReceivingSurfaceId(_receiver, &imageReceiverSurfaceId);
if (ErrCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP,
"OH_ImageReceiverNative_GetReceivingSurfaceId image receiver on failed, errCode: %{public}d.",
ErrCode);
OH_ImageReceiverOptions_Release(_options);
OH_ImageReceiverNative_Release(_receiver);
return ERROR_FAILED;
}
OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_GetReceivingSurfaceId imageReceiverSurfaceId %{public}lu",
imageReceiverSurfaceId);
std::ostringstream surfaceIDString;
surfaceIDString << imageReceiverSurfaceId;
// 创建预览输出流,其中参数 previewSurfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface
ret = OH_CameraManager_CreatePreviewOutput(_cameraManager, previewProfile, surfaceIDString.str().c_str(),
&_previewOutput);
if (previewProfile == nullptr || _previewOutput == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed.");
return ERROR_FAILED;
} else {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput success.previewSurfaceId : %{public}s",
surfaceIDString.str().c_str());
}
// 监听预览输出错误信息
ret = OH_PreviewOutput_RegisterCallback(_previewOutput, GetPreviewOutputListener());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_PreviewOutput_RegisterCallback failed.");
return ERROR_FAILED;
}
// 创建会话
ret = OH_CaptureSession_Release(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Release failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
ret = OH_CameraManager_CreateCaptureSession(_cameraManager, &_captureSession);
if (_captureSession == nullptr || ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 监听session错误信息
ret = OH_CaptureSession_RegisterCallback(_captureSession, GetCaptureSessionRegister());
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_RegisterCallback failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 开始配置会话
ret = OH_CaptureSession_BeginConfig(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 向会话中添加相机输入流
ret = OH_CaptureSession_AddInput(_captureSession, _cameraInput);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddInput failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 向会话中添加预览输出流
ret = OH_CaptureSession_AddPreviewOutput(_captureSession, _previewOutput);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 提交会话配置
ret = OH_CaptureSession_CommitConfig(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
// 启动会话
ret = OH_CaptureSession_Start(_captureSession);
if (ret != CAMERA_OK) {
OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed.ret : %{public}d", ret);
return ERROR_FAILED;
}
return ERROR_SUCCESS;
}
NDKCamera *NDKCamera::GetInstance()
{
if (g_ndkCamera == nullptr) {
g_ndkCamera = new NDKCamera();
}
if (g_ndkCamera->Init() != ERROR_SUCCESS) {
return nullptr;
}
return g_ndkCamera;
}
int NDKCamera::GETCHANNELID() { return previewProfileId; }
int NDKCamera::GETCHANNELWIDTH() { return previewProfile->size.width; }
int NDKCamera::GETCHANNELHEIGHT() { return previewProfile->size.height; }
NDKCameraErrorCode NDKCamera::CheckSelfPermission()
{
if (!OH_AT_CheckSelfPermission(OHOS_PERMISSION_CAMERA)) {
return ERROR_FAILED;
}
return ERROR_SUCCESS;
} /*
* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*/
#ifndef MYCAMERANATIVE_CAMERA_H
#define MYCAMERANATIVE_CAMERA_H
#include <multimedia/image_framework/image/image_receiver_native.h>
#include <ace/xcomponent/native_interface_xcomponent.h>
#include "ohcamera/camera.h"
#include "ohcamera/camera_device.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"
typedef enum NDKCameraErrorCode {
ERROR_SUCCESS = 0,
ERROR_FAILED,
} NDKCameraErrorCode;
#define OHOS_PERMISSION_CAMERA "ohos.permission.CAMERA"
class NDKCamera {
public:
NDKCameraErrorCode SwitchPreviewChannel(); // 切换摄像头通道
static NDKCameraErrorCode CheckSelfPermission();
int GETCHANNELID();
int GETCHANNELWIDTH();
int GETCHANNELHEIGHT();
static NDKCamera * GetInstance();
private:
NDKCameraErrorCode Init();
Camera_Manager* _cameraManager = nullptr;
Camera_Device* _cameras = nullptr;
Camera_CaptureSession* _captureSession = nullptr;
Camera_OutputCapability* _cameraOutputCapability = nullptr;
const Camera_Profile* previewProfile = nullptr;
const Camera_Profile* _photoProfile = nullptr;
int previewProfileId = 0;
int photoProfileId = 0;
Camera_PreviewOutput* _previewOutput = nullptr;
Camera_PhotoOutput* _photoOutput = nullptr;
Camera_Input* _cameraInput = nullptr;
OH_ImageReceiverOptions* _options = nullptr;
OH_ImageReceiverNative * _receiver = nullptr;
uint64_t imageReceiverSurfaceId = 0;
uint32_t cameraDeviceIndex = 0;
};
extern void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window);
extern void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window);
extern void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window);
extern void DispatchTouchEventCB(OH_NativeXComponent* component, void* window);
#endif // MYCAMERANATIVE_CAMERA_H # the minimum version of CMake.
cmake_minimum_required(VERSION 3.5)
project(MyCameraNative)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_library(entry SHARED napi_init.cpp camera.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so)
target_link_libraries(entry PUBLIC libohcamera.so
libace_ndk.z.so
libhilog_ndk.z.so
libimage_receiver.so
libohimage.so
libnative_image.so
libimage_ndk.z.so
libimage_receiver_ndk.z.so
libnative_buffer.so
libnative_window.so
libability_access_control.so)