目录

预览流二次处理(C/C++)

通过ImageReceiver创建预览输出,获取预览流实时数据,以供后续进行图像二次处理,比如应用可以对其添加滤镜算法等。

开发步骤

详细的API说明请参考OH_Camera。

  1. 导入NDK接口,接口中提供了相机相关的属性和方法,导入方法如下。

    #include <cstdint>
    #include <cstdlib>
    #include "hilog/log.h"
    #include <memory>
    #include <new>
    #include <map>
    #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/camera_device.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 <multimedia/media_library/media_asset_manager_capi.h>
    #include <multimedia/media_library/media_asset_change_request_capi.h>
    #include <multimedia/media_library/media_access_helper_capi.h>
    #include <multimedia/image_framework/image/image_packer_native.h>
  2. 在CMake脚本中链接相关动态库。

    target_link_libraries(entry PUBLIC
        libace_napi.z.so
        libhilog_ndk.z.so
        libohimage.so
        libimage_receiver.so
        libnative_image.so
        libohcamera.so
        libnative_buffer.so
    )
  3. 初始化图片接收器ImageReceiver实例,获取SurfaceId。

    通过image的OH_ImageReceiverNative_Create方法创建OH_ImageReceiverNative实例,再通过实例的OH_ImageReceiverNative_GetReceivingSurfaceId方法获取SurfaceId。

    void InitImageReceiver(uint64_t &receiverSurfaceID)
    {
        OH_ImageReceiverOptions *options = nullptr;
        // 注意捕获错误码处理异常及对象判空,当前示例仅展示调用流程。
        // 设置图片参数。
        Image_ErrorCode errCode = OH_ImageReceiverOptions_Create(&options);
        if (errCode != IMAGE_SUCCESS || options == nullptr) {
            OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_Create call failed");
            return;
        }
        Image_Size imgSize;
        imgSize.width = PREVIEW_WIDTH; // 创建预览流的宽。
        imgSize.height = PREVIEW_HEIGHT; // 创建预览流的高。
        int32_t capacity = 8; // BufferQueue里最大Image数量,推荐填写8。
        errCode = OH_ImageReceiverOptions_SetSize(options, imgSize);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_SetSize call failed");
        }
        errCode = OH_ImageReceiverOptions_SetCapacity(options, capacity);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverOptions_SetCapacity call failed");
        }
        // 创建OH_ImageReceiverNative对象。
        OH_ImageReceiverNative *receiver = nullptr;
        errCode = OH_ImageReceiverNative_Create(options, &receiver);
        if (errCode != IMAGE_SUCCESS || receiver == nullptr) {
            OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_Create call failed");
            return;
        }
    
        errCode = OH_ImageReceiverNative_On(receiver, CallbackReadNextImage);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "%{public}s image receiver on failed, errCode: %{public}d.", __func__, errCode);
            OH_ImageReceiverOptions_Release(options);
            OH_ImageReceiverNative_Release(receiver);
            return;
        }
        // 获取OH_ImageReceiverNative对象的SurfaceId。
        errCode = OH_ImageReceiverNative_GetReceivingSurfaceId(receiver, &receiverSurfaceID);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "OH_ImageReceiverNative_GetReceivingSurfaceId call failed");
        } else {
            OH_LOG_INFO(LOG_APP, "receiver surfaceID:%{public}lu", receiverSurfaceID);
        }
    }
  4. 通过上一步获取到的SurfaceId创建预览流(在创建预览流之前需要将SurfaceId类型转成char *),参考预览(C/C++)步骤4。

  5. 创建会话,使能会话,参考会话管理(C/C++)。

  6. 注册ImageReceiver图片接收器的回调,监听获取每帧上报图像内容。

    void copyBuffer(OH_NativeBuffer *srcBuffer, size_t srcSize, OHNativeWindowBuffer *dstBuffer)
    {
        OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest %{public}s IN", __func__);
        void *srcVir = nullptr;
        OH_NativeBuffer_Map(srcBuffer, &srcVir);
        BufferHandle *bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(dstBuffer);
        OH_LOG_INFO(LOG_APP,
            "ImageReceiverNativeCTest %{public}s bufferHandle info fd= %{public}d , width= %{public}d, "
            "height=%{public}d, stride= %{public}d, size= %{public}d, format= %{public}d, usage= %{public}lu",
            __func__, bufferHandle->fd, bufferHandle->width, bufferHandle->height, bufferHandle->stride, bufferHandle->size,
            bufferHandle->format, bufferHandle->usage);
    
        void *mappedAddr =
            mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0);
        std::memcpy(static_cast<unsigned char *>(mappedAddr), static_cast<unsigned char *>(srcVir), srcSize);
        munmap(mappedAddr, bufferHandle->size);
    
        OH_NativeBuffer_Unmap(srcBuffer);
        OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest %{public}s SUCCESS", __func__);
    }
    
    void ShowImage(OH_ImageNative *image)
    {
        OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest %{public}s IN", __func__);
        if (g_ndkCamera == nullptr) {
            return;
        }
        uint64_t xComponentSurfaceId = std::stoull(g_xComponentSurfaceIdSlave);
        OH_LOG_ERROR(LOG_APP, "ImageReceiverNativeCTest %{public}s XComponentId is : %{public}lu.", __func__,
            xComponentSurfaceId);
        OHNativeWindow *nativeWindow = nullptr;
        int32_t res = OH_NativeWindow_CreateNativeWindowFromSurfaceId(xComponentSurfaceId, &nativeWindow);
        OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest %{public}s XComponentId is : %{public}lu.",
            __func__, xComponentSurfaceId);
        if (res != 0) {
            OH_LOG_ERROR(LOG_APP, "CreateSurfaceId failed, errCode: %{public}d.", res);
            return;
        }
    
        // 关键:调整nativeWindow大小及format,需要与image的大小、format保持一致。
        res = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_BUFFER_GEOMETRY, g_imageWidth, g_imageHeight);
        res = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_FORMAT, NATIVEBUFFER_PIXEL_FMT_YCRCB_420_SP); // NV21
        
        int32_t displayRotation = g_ndkCamera->GetDefaultDisplayRotation();
        int32_t previewRotation = static_cast<int32_t>(g_ndkCamera->GetPreviewRotation(displayRotation));
        if (g_isFront && (displayRotation == ROTATION_90 || displayRotation == ROTATION_270)) {
            previewRotation = (previewRotation + ROTATION_180) % ROTATION_360;
        }
        OH_NativeBuffer_TransformType transformType = g_ndkCamera->GetNativeBufferTransformType(previewRotation, g_isFront);
        res = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_TRANSFORM, transformType);
    
        OH_NativeBuffer *imageBuffer = nullptr;
        Image_ErrorCode errCode = OH_ImageNative_GetByteBuffer(image, g_jpegComponent, &imageBuffer);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "ShowImage GetByteBuffer failed, errCode: %{public}d.", errCode);
            return;
        }
        Image_Size imgSize = {};
        OH_ImageNative_GetImageSize(image, &imgSize);
        OH_LOG_INFO(LOG_APP, "%{public}s imgSize is : %{public}u, %{public}u.", __func__, imgSize.width, imgSize.height);
        size_t bufSize = 0;
        OH_ImageNative_GetBufferSize(image, g_jpegComponent, &bufSize);
    
        OHNativeWindowBuffer *nativeWindowBuffer = nullptr;
        int fenceFd = -1;
        res = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &fenceFd);
        if (res != 0) {
            OH_LOG_ERROR(LOG_APP, "ShowImage RequestBuffer failed, errCode: %{public}d.", res);
            return;
        }
        // 将image数据拷贝到nativeWindowBuffer上。
        copyBuffer(imageBuffer, bufSize, nativeWindowBuffer);
    
        Region region1{};
        res = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, nativeWindowBuffer, fenceFd, region1);
        if (res != 0) {
            OH_LOG_ERROR(LOG_APP, "ShowImage FlushBuffer failed, errCode: %{public}d.", res);
            return;
        }
        OH_LOG_INFO(LOG_APP, "ImageReceiverNativeCTest %{public}s SUCCESS", __func__);
    }
    
    static void CallbackReadNextImage(OH_ImageReceiverNative *receiver)
    {
        OH_LOG_INFO(LOG_APP, "CallbackReadNextImage %{public}s IN", __func__);
        // 读取OH_ImageReceiverNative下一张图片对象。
        OH_ImageNative *image = nullptr;
        Image_ErrorCode errCode = OH_ImageReceiverNative_ReadNextImage(receiver, &image);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP,
                "CallbackReadNextImage %{public}s get image receiver next image failed, errCode: %{public}d.", __func__,
                errCode);
            return;
        }
    
        ShowImage(image);
    
        // 释放OH_ImageNative实例。
        errCode = OH_ImageNative_Release(image);
        if (errCode != IMAGE_SUCCESS) {
            OH_LOG_ERROR(LOG_APP, "CallbackReadNextImage %{public}s release image native failed, errCode: %{public}d.",
                __func__, errCode);
        }
        OH_LOG_INFO(LOG_APP, "CallbackReadNextImage %{public}s SUCCESS", __func__);
    }