如何使用ndk打开camera

写在之前

因业务需求需要使用c++代码打开camera,之前没怎么接触过c++的应用,也算是一种全新的挑战吧。其实代码很简单,但是这中间有很多的坑,记录一下避免大家出现同样的问题。此方法打开camera的代码全是c++的,不需要使用到java,这样可以提高响应速度提升性能,优化用户体验。如果想要在打开camera后集成一些别的库实现一些接口,这样会比java更好。

但是这中间的坑就在这里,如果不在AndroidManifest.xml申请权限,camera是一定打不开的,而且它还不会报错,真是晕了。。。

附上代码

ACameraManager* cameraManager = nullptr;
ACameraDevice* cameraDevice = nullptr;
ACaptureRequest* captureRequest = nullptr;
ACameraOutputTarget* cameraOutputTarget = nullptr;
ACameraCaptureSession* captureSession = nullptr;
AImageReader* imageReader = nullptr;
ANativeWindow* nativeWindow = nullptr;
AImage* image = nullptr;

// Callback functions
void onCameraDeviceError(void* context, ACameraDevice* device, int error) {
    // Handle camera device error
}
void onCameraDeviceDisconnected(void* context, ACameraDevice* device) {
    // Handle camera device disconnected
}
void onCaptureSessionClosed(void* context, ACameraCaptureSession* session) {
    // Handle capture session closed
}
void onCaptureSessionActive(void* context, ACameraCaptureSession* session) {
    // Handle capture session active
}

void eventCallback(void* context ,func_getHandEvent event){
    cont = context;
    getHandEvent = event;
}

void onImageAvailable(void* context, AImageReader* reader) {
    media_status_t mStatus = AImageReader_acquireLatestImage(reader, &image);
    if (mStatus != AMEDIA_OK) {
        return;
    }else{
    	//一般打开摄像头后最重要的就在这里
    	//如果想要做什么事一定是在这个回调处获取得到的image进行处理
        //handleHandData(image);
    }
    //得到image处理完后记得删除,不然缓冲区溢出了你打开的camera就寄了
    AImage_delete(image);
}

bool openCamera(const char* cameraId) {
    // 根据cameraID打开摄像头
    ACameraDevice_StateCallbacks deviceStateCallbacks {
            .context = nullptr,
            .onDisconnected = onCameraDeviceDisconnected,
            .onError = onCameraDeviceError
    };
    camera_status_t status = ACameraManager_openCamera(cameraManager, cameraId, &deviceStateCallbacks, &cameraDevice);
    return status == ACAMERA_OK;
}

bool createCaptureRequest(ACameraDevice_request_template templateId) {
    camera_status_t status = ACameraDevice_createCaptureRequest(cameraDevice, templateId, &captureRequest);
    if (status != ACAMERA_OK) return false;
    status = ACaptureRequest_addTarget(captureRequest, cameraOutputTarget);
    return status == ACAMERA_OK;
}

bool createCaptureSession() {
    int *i = nullptr;
    ACaptureSessionOutputContainer* outputContainer = nullptr;
    ACaptureSessionOutput* sessionOutput = nullptr;
    //初始化ACaptureSessionOutputContainer
    camera_status_t status = ACaptureSessionOutputContainer_create(&outputContainer);
    if (status != ACAMERA_OK) return false;
    //初始化ACaptureSessionOutput
    status = ACaptureSessionOutput_create(nativeWindow, &sessionOutput);
    if (status != ACAMERA_OK) return false;
    status = ACaptureSessionOutputContainer_add(outputContainer, sessionOutput);
    if (status != ACAMERA_OK) return false;
    ACameraCaptureSession_stateCallbacks sessionStateCallbacks {
            .context = nullptr,
            .onClosed = onCaptureSessionClosed,
            .onReady = nullptr,
            .onActive = onCaptureSessionActive
    };
    //初始化ACameraCaptureSession
    status = ACameraDevice_createCaptureSession(cameraDevice, outputContainer, &sessionStateCallbacks, &captureSession);
    if (status != ACAMERA_OK) return false;
	//在这里开始去重复请求拿到图片进行输出
    status = ACameraCaptureSession_setRepeatingRequest(captureSession, nullptr, 1, &captureRequest,
                                                       i++);
    return status == ACAMERA_OK;
}

bool createImageReader(int width, int height, int format, int maxImages) {
    //要循环去读取图片,创建一个reader
    media_status_t status = AImageReader_new(width, height, format, maxImages, &imageReader);
    if (status != AMEDIA_OK) {
        LOGI(TAG,"创建失败");
        return false;
    }
	//在这里注册AImage的回调,重中之重
    AImageReader_ImageListener imageListener {
            .context = nullptr,
            .onImageAvailable = onImageAvailable
    };
    status = AImageReader_setImageListener(imageReader, &imageListener);
    if (status != AMEDIA_OK) return false;
    status = AImageReader_getWindow(imageReader, &nativeWindow);
    return status == AMEDIA_OK;
}
// 帮助类end


//以上都是帮助类,使用startCamera()函数对所需的类初始化并打开camera
void startCamera()
{
    // 开始使用摄像头预览
    cameraManager = ACameraManager_create();
    // 获取摄像头id
    ACameraIdList *cameraIdList = nullptr;
    ACameraManager_getCameraIdList(cameraManager, &cameraIdList);
    const char *cameraId = nullptr;
    for (int i = 0; i < cameraIdList->numCameras; i++)
    {
        const char *id = cameraIdList->cameraIds[i];
        ACameraMetadata *metadata = nullptr;
        ACameraManager_getCameraCharacteristics(cameraManager, id, &metadata);
        ACameraMetadata_const_entry entry;
        ACameraMetadata_getConstEntry(metadata, ACAMERA_LENS_FACING, &entry);
        auto facing = static_cast<acamera_metadata_enum_android_lens_facing_t>(entry.data.u8[0]);
        if (facing == ACAMERA_LENS_FACING_FRONT)
        {
            cameraId = id;
            LOGI(TAG,"cameraid=====%s",cameraId);
            break;
        }
    }

    // 打开摄像头并且读取image
    //camera的参数自己定制
    if (openCamera(cameraId) && createImageReader(1440 , 1080, AIMAGE_FORMAT_YUV_420_888, 2)){
        // 创建一个输出的目标
        ACameraOutputTarget_create(nativeWindow, &cameraOutputTarget);
        // 创建捕获请求和捕获会话
        if (createCaptureRequest(TEMPLATE_RECORD)){
            createCaptureSession();

        }
    }
}

//简单的暂停一下
void pauseCamera(){
    ACameraDevice_close(cameraDevice);
    cameraDevice = nullptr;
}

//关闭camera,注意要释放掉不为空的结构
void stopCamera(){
    // Stop the camera and preview and release the resources
    if (captureSession != nullptr) {
        ACameraCaptureSession_stopRepeating(captureSession);
        ACameraCaptureSession_close(captureSession);
        captureSession = nullptr;
    }
    if (captureRequest != nullptr) {
        ACaptureRequest_removeTarget(captureRequest, cameraOutputTarget);
        ACaptureRequest_free(captureRequest);
        captureRequest = nullptr;
    }
    if (cameraOutputTarget != nullptr) {
        ACameraOutputTarget_free(cameraOutputTarget);
        cameraOutputTarget = nullptr;
    }
    if (cameraDevice != nullptr) {
        ACameraDevice_close(cameraDevice);
        cameraDevice = nullptr;
    }
    if (imageReader != nullptr) {
        AImageReader_delete(imageReader);
        imageReader = nullptr;
    }
    if (cameraManager != nullptr) {
        ACameraManager_delete(cameraManager);
        cameraManager = nullptr;
    }
    // Closed the camera and preview successfully
}

想说的话

相信大家使用ndk打开camera不仅仅只是想打开camera这么简单,那么最重要的一环就是在onImageAvailable()回调函数中去进行需要的数据处理,每一个回调得到的AImage都可以获取并通过本地集成的算法库解析出想要的数据,一定要注意要在AndroidManifest.xml中注册camera权限,不然啥错也不会报但就是打不开,顺手可以请求其他的权限

    <uses-permission android:name="android.permission.CAMERA"
        tools:ignore="PermissionImpliesUnsupportedChromeOsHardware" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这段代码只是打开了camera,但是没有实现预览,预览的代码可以在网上搜一搜很简单。那么我们这里不进行预览的话可以怎样做呢?诶,我们可以把这个apk的mainActivity也隐藏掉,将他直接当成一个系统服务需要的时候进行开启。我猜人脸识别的功能原理大概也是这样吧,只是集成了不同的算法库。
那有的朋友就要问了,不进行预览我们怎么知道究竟有没有成功打开camera呢?这里有两种方法

  1. 在onImageAvailable()函数中保存得到的AImage,push到本地进行查看
  2. 查看日志

请添加图片描述
CamX会告诉你答案~

结束

以上就是全流程了,因为把公司业务相关代码删除了所以整理的可能不太清晰。如有错漏的地方欢迎指出让我修改到位QAQ

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值