预览流二次处理(C/C++)
通过ImageReceiver创建预览输出,获取预览流实时数据,以供后续进行图像二次处理,比如应用可以对其添加滤镜算法等。
开发步骤
详细的API说明请参考OH_Camera。
-
导入NDK接口,接口中提供了相机相关的属性和方法,导入方法如下。
#include <cstdint>#include <cstdlib>#include "hilog/log.h"#include <memory>#include <new>#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> -
在CMake脚本中链接相关动态库。
target_link_libraries(entry PUBLIClibace_napi.z.solibhilog_ndk.z.solibohimage.solibimage_receiver.solibnative_image.solibohcamera.solibnative_buffer.so) -
初始化图片接收器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);}} -
通过上一步获取到的SurfaceId创建预览流(在创建预览流之前需要将SurfaceId类型转成char *),参考预览(C/C++)步骤4。
-
创建会话,使能会话,参考会话管理(C/C++)。
-
注册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__);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);if (res != 0) {OH_LOG_ERROR(LOG_APP,"ShowImage CreateNativeWindowFromSurfaceId 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// 设置旋转角度,后置默认旋转90,则需要将nativeWindow旋转270度,前置默认270,则需要将nativeWindow旋转90度。if (g_isFront) {res = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_TRANSFORM, NATIVEBUFFER_FLIP_V_ROT90);} else {res = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, SET_TRANSFORM, NATIVEBUFFER_ROTATE_270);}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, "ImageReceiverNativeCTest %{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__);}