使用Image_NativeModule完成图片接收
图像接收类,用于获取组件的surfaceId、接收最新的图片、读取下一张图片以及释放ImageReceiver实例。结合camera API实现的相机预览示例代码可参考预览流二次处理(C/C++)。
说明:
ImageReceiver只作为图片的接收方、消费者,在ImageReceiver设置的size、format等属性实际上并不会生效。图片属性需要在发送方、生产者进行设置,可参考预览(C/C++)设置previewProfiles。
开发步骤
添加依赖
在进行应用开发之前,开发者需要打开native工程的src/main/cpp/CMakeLists.txt,在target_link_libraries依赖中添加libohimage.so、libimage_receiver.so、libnative_image.so以及日志依赖libhilog_ndk.z.so。
target_link_libraries(entry PUBLIC libhilog_ndk.z.so libohimage.so libimage_receiver.so libnative_image.so)
Native接口调用
具体接口说明请参考Image_NativeModule。
下述代码主要演示了Receiver的初始化、相机预览流的创建以及获取图像的信息和Receiver的释放等相关功能。
说明:
部分接口在API version 20以后才支持,需要开发者在进行开发时选择合适的API版本。
-
导入相关头文件。
#include <hilog/log.h> #include "napi/native_api.h" #include <string> #include <multimedia/image_framework/image/image_native.h> #include <multimedia/image_framework/image/image_receiver_native.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" #include <mutex> #include <shared_mutex> // C++17以上使用 #include <condition_variable> -
常量定义。
#undef LOG_DOMAIN #define LOG_DOMAIN 0x3200 #undef LOG_TAG #define LOG_TAG "MY_TAG" #define IMAGE_WIDTH 320 #define IMAGE_HEIGHT 480 #define IMAGE_CAPACITY 2 -
定义全局变量。
static OH_ImageReceiverNative* g_receiver = nullptr; static std::mutex g_mutex; static std::shared_mutex shared_receiver_mutex; static std::condition_variable g_condVar; static bool g_imageReady = false; static OH_ImageNative* g_imageInfoResult = nullptr; -
定义一些工具类函数,用来处理napi的返回值和参数类型的转换。
// 处理napi返回值。 napi_value GetJsResultDemo(napi_env env, int result) { napi_value resultNapi = nullptr; napi_create_int32(env, result, &resultNapi); return resultNapi; } // 将uint64_t转换为一个以null结尾的char数组。 std::unique_ptr<char[]> ConvertUint64ToCharTemp(uint64_t value) { std::string strValue = std::to_string(value); auto charBuffer = std::make_unique<char[]>(strValue.size() + 1); std::copy(strValue.begin(), strValue.end(), charBuffer.get()); charBuffer[strValue.size()] = '\0'; return charBuffer; } -
初始化Receiver。
-
创建并设置ReceiverOptions。
static Image_ErrorCode CreateAndConfigOptions(OH_ImageReceiverOptions** options) { Image_ErrorCode errCode = OH_ImageReceiverOptions_Create(options); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Create image receiver options failed, errCode: %{public}d.", errCode); return errCode; } Image_Size imgSize = {IMAGE_WIDTH, IMAGE_HEIGHT}; errCode = OH_ImageReceiverOptions_SetSize(*options, imgSize); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Set image receiver options size failed, errCode: %{public}d.", errCode); OH_ImageReceiverOptions_Release(*options); return errCode; } errCode = OH_ImageReceiverOptions_SetCapacity(*options, IMAGE_CAPACITY); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Set image receiver options capacity failed, errCode: %{public}d.", errCode); OH_ImageReceiverOptions_Release(*options); return errCode; } return IMAGE_SUCCESS; } -
获取ReceiverOptions。
static Image_ErrorCode ValidateOptions(OH_ImageReceiverOptions* options) { Image_Size imgSizeRead; Image_ErrorCode errCode = OH_ImageReceiverOptions_GetSize(options, &imgSizeRead); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Get image receiver options size failed, errCode: %{public}d.", errCode); return errCode; } if (imgSizeRead.width != IMAGE_WIDTH || imgSizeRead.height != IMAGE_HEIGHT) { OH_LOG_ERROR(LOG_APP, "Get image receiver options size failed," "width: %{public}d, height: %{public}d.", imgSizeRead.width, imgSizeRead.height); return IMAGE_BAD_PARAMETER; } int32_t capacity = 0; errCode = OH_ImageReceiverOptions_GetCapacity(options, &capacity); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Get image receiver options capacity failed, errCode: %{public}d.", errCode); return errCode; } if (capacity != IMAGE_CAPACITY) { OH_LOG_ERROR(LOG_APP, "Get image receiver options capacity failed, capacity: %{public}d.", capacity); return IMAGE_BAD_PARAMETER; } return IMAGE_SUCCESS; } -
创建Receiver对象。
static Image_ErrorCode CreateReceiver(OH_ImageReceiverOptions* options, OH_ImageReceiverNative** receiver) { Image_ErrorCode errCode = OH_ImageReceiverNative_Create(options, receiver); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Create image receiver failed, errCode: %{public}d.", errCode); return errCode; } return IMAGE_SUCCESS; } -
定义获取下一张图片的callback函数。
static void OnCallback(OH_ImageReceiverNative* receiver) { OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest buffer available."); // 共享锁(读) std::shared_lock<std::shared_mutex> lock(shared_receiver_mutex); OH_ImageNative* image = nullptr; Image_ErrorCode errCode = OH_ImageReceiverNative_ReadNextImage(receiver, &image); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "ImageReceiverNativeCTest get image receiver next image failed," "errCode: %{public}d.", errCode); OH_ImageNative_Release(image); return; } else { std::lock_guard<std::mutex> lock(g_mutex); g_imageInfoResult = image; g_imageReady = true; } g_condVar.notify_one(); } -
注册callback。
static Image_ErrorCode RegisterCallbackAndQuery(OH_ImageReceiverNative* receiver) { uint64_t surfaceID = 0; Image_ErrorCode errCode = OH_ImageReceiverNative_On(receiver, OnCallback); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Image receiver on failed, errCode: %{public}d.", errCode); return errCode; } errCode = OH_ImageReceiverNative_GetReceivingSurfaceId(receiver, &surfaceID); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Get image receiver surfaceID failed, errCode: %{public}d.", errCode); return errCode; } OH_LOG_INFO(LOG_APP, "Get image receiver surfaceID: %{public}lu.", surfaceID); Image_Size imgSizeRead; errCode = OH_ImageReceiverNative_GetSize(receiver, &imgSizeRead); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Get image receiver size failed, errCode: %{public}d.", errCode); return errCode; } OH_LOG_INFO(LOG_APP, "Get image receiver size: width = %{public}d, height = %{public}d.", imgSizeRead.width, imgSizeRead.height); int32_t capacity = 0; errCode = OH_ImageReceiverNative_GetCapacity(receiver, &capacity); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Get image receiver capacity failed, errCode: %{public}d.", errCode); return errCode; } OH_LOG_INFO(LOG_APP, "Get image receiver capacity: %{public}d.", capacity); return IMAGE_SUCCESS; } -
初始化Receiver的整体流程。
static napi_value ImageReceiverNativeCTest(napi_env env, napi_callback_info info) { if (g_receiver != nullptr) { OH_ImageReceiverNative_Off(g_receiver); OH_ImageReceiverNative_Release(g_receiver); g_receiver = nullptr; } OH_ImageReceiverOptions* options = nullptr; Image_ErrorCode errCode = CreateAndConfigOptions(&options); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "CreateAndConfigOptions failed errCode=%{public}d", errCode); return GetJsResultDemo(env, errCode); } errCode = ValidateOptions(options); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "ValidateOptions failed errCode=%{public}d", errCode); OH_ImageReceiverOptions_Release(options); return GetJsResultDemo(env, errCode); } errCode = CreateReceiver(options, &g_receiver); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "CreateReceiver failed errCode=%{public}d", errCode); OH_ImageReceiverOptions_Release(options); return GetJsResultDemo(env, errCode); } errCode = RegisterCallbackAndQuery(g_receiver); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "RegisterCallbackAndQuery failed errCode=%{public}d", errCode); OH_ImageReceiverOptions_Release(options); OH_ImageReceiverNative_Release(g_receiver); g_receiver = nullptr; return GetJsResultDemo(env, errCode); } OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest create and config success."); OH_ImageReceiverOptions_Release(options); return GetJsResultDemo(env, IMAGE_SUCCESS); }
-
-
调用相机拍照流进行拍照,触发回调。
-
创建一个CameraManager实例。
Camera_ErrorCode InitCameraManagerAndInput(Camera_Manager*& cameraManager, Camera_Device*& cameras, uint32_t& size, Camera_Input*& cameraInput) { cameraManager = nullptr; cameras = nullptr; size = 0; cameraInput = nullptr; Camera_ErrorCode ret = OH_Camera_GetCameraManager(&cameraManager); if (cameraManager == nullptr || ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_Camera_GetCameraManager failed."); return ret; } ret = OH_CameraManager_GetSupportedCameras(cameraManager, &cameras, &size); if (cameras == nullptr || size < 1 || ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameras failed."); return ret; } for (uint32_t i = 0; i < size; ++i) { OH_LOG_INFO(LOG_APP, "Camera[%{public}u]: id=%{public}s, position=%{public}d, type=%{public}d, " "connectionType=%{public}d", i, cameras[i].cameraId, cameras[i].cameraPosition, cameras[i].cameraType, cameras[i].connectionType); } ret = OH_CameraManager_CreateCameraInput(cameraManager, &cameras[0], &cameraInput); if (cameraInput == nullptr || ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCameraInput failed.ret:%{public}d", ret); return ret; } return CAMERA_OK; } -
获取相机输出能力。
Camera_ErrorCode GetCameraOutputCapability(Camera_Manager* cameraManager, Camera_Device* cameras, uint32_t cameraDeviceIndex, Camera_OutputCapability*& capability) { capability = nullptr; Camera_ErrorCode ret = OH_CameraManager_GetSupportedCameraOutputCapability(cameraManager, &cameras[cameraDeviceIndex], &capability); if (capability == nullptr || ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CameraManager_GetSupportedCameraOutputCapability failed."); } return ret; } -
创建相机捕获会话,用于捕获相机拍摄的照片。
Camera_CaptureSession* CreateAndStartSession(Camera_Manager* cameraManager, Camera_Input* cameraInput, int sessionMode) { Camera_CaptureSession* captureSession = nullptr; Camera_ErrorCode ret = OH_CameraManager_CreateCaptureSession(cameraManager, &captureSession); if (captureSession == nullptr || ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreateCaptureSession failed."); return nullptr; } ret = OH_CaptureSession_SetSessionMode(captureSession, static_cast<Camera_SceneMode>(sessionMode)); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_SetSessionMode failed."); return nullptr; } ret = OH_CaptureSession_BeginConfig(captureSession); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_BeginConfig failed."); return nullptr; } ret = OH_CaptureSession_AddInput(captureSession, cameraInput); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddInput failed."); return nullptr; } return captureSession; } -
开启捕获会话。
static Camera_ErrorCode StartCaptureSession(Camera_Manager* mgr, Camera_Input* input, Camera_PreviewOutput* previewOutput, Camera_CaptureSession** sessionOut) { *sessionOut = CreateAndStartSession(mgr, input, NORMAL_PHOTO); if (*sessionOut == nullptr) { OH_LOG_ERROR(LOG_APP, "CreateAndStartSession failed."); return CAMERA_INVALID_ARGUMENT; } Camera_ErrorCode ret = OH_CaptureSession_AddPreviewOutput(*sessionOut, previewOutput); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_AddPreviewOutput failed."); return ret; } ret = OH_CaptureSession_CommitConfig(*sessionOut); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_CommitConfig failed."); return ret; } ret = OH_CaptureSession_Start(*sessionOut); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CaptureSession_Start failed."); } return ret; } -
创建相机拍照流。
Camera_ErrorCode StartTakePhoto(char* str) { char* photoSurfaceId = str; Camera_Manager* cameraManager = nullptr; Camera_Device* cameras = nullptr; uint32_t size = 0; Camera_Input* cameraInput = nullptr; Camera_ErrorCode ret = InitCameraManagerAndInput(cameraManager, cameras, size, cameraInput); if (ret != CAMERA_OK) return ret; Camera_OutputCapability* cameraOutputCapability = nullptr; ret = GetCameraOutputCapability(cameraManager, cameras, 0, cameraOutputCapability); if (ret != CAMERA_OK) return ret; const Camera_Profile* photoProfile = cameraOutputCapability->previewProfiles[0]; Camera_PreviewOutput* previewOutput = nullptr; ret = OH_CameraManager_CreatePreviewOutput(cameraManager, photoProfile, photoSurfaceId, &previewOutput); if (photoProfile == nullptr || previewOutput == nullptr || ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CameraManager_CreatePreviewOutput failed."); return ret; } ret = OH_CameraInput_Open(cameraInput); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "OH_CameraInput_open failed."); return ret; } Camera_CaptureSession* captureSession = nullptr; ret = StartCaptureSession(cameraManager, cameraInput, previewOutput, &captureSession); if (ret != CAMERA_OK) { OH_LOG_ERROR(LOG_APP, "StartCaptureSession failed."); return ret; } return CAMERA_OK; } -
调用相机拍照的整体流程。
static napi_value TakePhoto(napi_env env, napi_callback_info info) { if (g_receiver == nullptr) { OH_LOG_ERROR(LOG_APP, "ImageReceiver not initialized."); return GetJsResultDemo(env, IMAGE_BAD_PARAMETER); } uint64_t surfaceId = 0; Image_ErrorCode errCode = OH_ImageReceiverNative_GetReceivingSurfaceId(g_receiver, &surfaceId); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Get surfaceId failed."); return GetJsResultDemo(env, errCode); } auto surfaceId_c = ConvertUint64ToCharTemp(surfaceId); Camera_ErrorCode photoRet = StartTakePhoto(surfaceId_c.get()); return GetJsResultDemo(env, photoRet); }
-
-
获取Receiver接收到的图片信息。
-
等待OnCallback回调通知。
// 同步等待。 static OH_ImageNative* NotifyJsImageInfoSync() { std::unique_lock<std::mutex> lock(g_mutex); g_imageReady = false; g_imageInfoResult = nullptr; // 等待OnCallback回调通知。 bool ret = g_condVar.wait_for(lock, std::chrono::seconds(1), [] { OH_LOG_INFO(LOG_APP, "NotifyJsImageInfoSync: wait_for wakeup, g_imageReady=%{public}d", g_imageReady); return g_imageReady; }); if (!ret) { OH_LOG_ERROR(LOG_APP, "NotifyJsImageInfoSync: wait_for timeout."); return nullptr; } return g_imageInfoResult; } -
获取图片大小。
// 获取图片大小。 static napi_value GetImageSizeInfo(napi_env env, OH_ImageNative* image) { OH_LOG_INFO(LOG_APP, "GetImageSizeInfo: enter, image=%{public}p", image); Image_Size imgSizeRead; Image_ErrorCode errCode = OH_ImageNative_GetImageSize(image, &imgSizeRead); OH_LOG_INFO(LOG_APP, "GetImageSizeInfo: GetImageSize errCode=%{public}d, width=%{public}d, height=%{public}d", errCode, imgSizeRead.width, imgSizeRead.height); if (errCode == IMAGE_SUCCESS) { napi_value resultObj; napi_create_object(env, &resultObj); napi_value width; napi_value height; napi_create_int32(env, imgSizeRead.width, &width); napi_create_int32(env, imgSizeRead.height, &height); napi_set_named_property(env, resultObj, "width", width); napi_set_named_property(env, resultObj, "height", height); OH_LOG_INFO(LOG_APP, "GetImageSizeInfo: exit"); return resultObj; } OH_LOG_ERROR(LOG_APP, "GetImageSizeInfo: Failed to get image size"); return nullptr; } -
获取组件类型。
// 获取组件类型。 static size_t GetComponentTypeSize(OH_ImageNative* image, size_t& componentTypeSize) { OH_LOG_INFO(LOG_APP, "GetComponentTypeSize: enter, image=%{public}p", image); // 获取组件类型的大小。 Image_ErrorCode errCode = OH_ImageNative_GetComponentTypes(image, nullptr, &componentTypeSize); OH_LOG_INFO(LOG_APP, "GetComponentTypeSize: GetComponentTypes (query size) errCode=%{public}d," "componentTypeSize=%{public}zu", errCode, componentTypeSize); return componentTypeSize; } -
获取组件信息。
// 获取组件信息。 static napi_value GetComponentInfo(napi_env env, size_t componentTypeSize, OH_ImageNative* image, napi_value resultObj) { if (componentTypeSize > 0) { uint32_t* components = new uint32_t[componentTypeSize]; Image_ErrorCode errCode = OH_ImageNative_GetComponentTypes(image, &components, &componentTypeSize); OH_LOG_INFO(LOG_APP, "GetImageInfoObject: GetComponentTypes (get types) errCode=%{public}d," "firstComponent=%{public}u", errCode, componentTypeSize > 0 ? components[0] : 0); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "GetImageInfoObject: GetComponentTypes (get types) failed"); delete [] components; return resultObj; } OH_NativeBuffer* nativeBuffer = nullptr; errCode = OH_ImageNative_GetByteBuffer(image, components[0], &nativeBuffer); if (errCode == IMAGE_SUCCESS) { OH_LOG_INFO(LOG_APP, "Get native buffer success."); } size_t nativeBufferSize = 0; errCode = OH_ImageNative_GetBufferSize(image, components[0], &nativeBufferSize); OH_LOG_INFO(LOG_APP, "GetImageInfoObject: GetBufferSize errCode=%{public}d, nativeBufferSize=%{public}zu", errCode, nativeBufferSize); if (errCode == IMAGE_SUCCESS) { napi_value bufSize; napi_create_int32(env, static_cast<int32_t>(nativeBufferSize), &bufSize); napi_set_named_property(env, resultObj, "bufferSize", bufSize); } int32_t rowStride = 0; errCode = OH_ImageNative_GetRowStride(image, components[0], &rowStride); OH_LOG_INFO(LOG_APP, "GetImageInfoObject: GetRowStride errCode=%{public}d," "rowStride=%{public}d", errCode, rowStride); if (errCode == IMAGE_SUCCESS) { napi_value jsRowStride; napi_create_int32(env, rowStride, &jsRowStride); napi_set_named_property(env, resultObj, "rowStride", jsRowStride); } int32_t pixelStride = 0; errCode = OH_ImageNative_GetPixelStride(image, components[0], &pixelStride); OH_LOG_INFO(LOG_APP, "GetImageInfoObject: GetPixelStride errCode=%{public}d, pixelStride=%{public}d", errCode, pixelStride); if (errCode == IMAGE_SUCCESS) { napi_value jsPixelStride; napi_create_int32(env, pixelStride, &jsPixelStride); napi_set_named_property(env, resultObj, "pixelStride", jsPixelStride); } delete [] components; } return resultObj; } -
获取图片属性并封装为napi对象。
// 获取图像属性并封装为napi对象。 static napi_value GetImageInfoObject(napi_env env, OH_ImageNative* image) { OH_LOG_INFO(LOG_APP, "GetImageInfoObject: enter, image=%{public}p", image); napi_value resultObj; napi_create_object(env, &resultObj); resultObj = GetImageSizeInfo(env, image); size_t componentTypeSize = 0; componentTypeSize = GetComponentTypeSize(image, componentTypeSize); if (componentTypeSize > 0) { resultObj = GetComponentInfo(env, componentTypeSize, image, resultObj); } int64_t timestamp = 0; Image_ErrorCode errCode = OH_ImageNative_GetTimestamp(image, ×tamp); OH_LOG_INFO(LOG_APP, "GetImageInfoObject: GetTimestamp errCode=%{public}d, timestamp=%{public}ld", errCode, timestamp); if (errCode == IMAGE_SUCCESS) { napi_value jsTimestamp; napi_create_int64(env, timestamp, &jsTimestamp); napi_set_named_property(env, resultObj, "timestamp", jsTimestamp); } OH_LOG_INFO(LOG_APP, "GetImageInfoObject: exit"); return resultObj; } -
获取ReceiverImageInfo的整体流程。
static napi_value GetReceiverImageInfo(napi_env env, napi_callback_info info) { OH_ImageNative* image = NotifyJsImageInfoSync(); if (!image) { napi_value undefined; napi_get_undefined(env, &undefined); return undefined; } napi_value resultObj = GetImageInfoObject(env, image); OH_ImageNative_Release(image); return resultObj; }
-
-
释放receiver。
static napi_value ReleaseImageReceiver(napi_env env, napi_callback_info info) { if (g_receiver == nullptr) { OH_LOG_INFO(LOG_APP, "No image receiver to release."); return nullptr; } Image_ErrorCode errCode = OH_ImageReceiverNative_Off(g_receiver); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "ImageReceiverNativeCTest image receiver off failed, errCode: %{public}d.", errCode); } // 独占锁(写) std::unique_lock<std::shared_mutex> lock(shared_receiver_mutex); errCode = OH_ImageReceiverNative_Release(g_receiver); if (errCode != IMAGE_SUCCESS) { OH_LOG_ERROR(LOG_APP, "Release image receiver failed, errCode: %{public}d.", errCode); } g_receiver = nullptr; return GetJsResultDemo(env, errCode); }