// Tencent is pleased to support the open source community by making ncnn available. // // Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. // // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // https://opensource.org/licenses/BSD-3-Clause // // Unless required by applicable law or agreed to in writing, software distributed // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "ndkcamera.h" #include #include #include #include #include #include #include "mat.h" #include "gpu.h" #include "Camera2Helper.h" #include #include static void onAvailabilityCallback(void* context, const char* cameraId) { ((NdkCamera*)context)->onAvailabilityCallback(cameraId); // ALOGI("CameraStatus::onAvailability CameraId: %s", cameraId); XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::onAvailability CameraId: %s", cameraId); } static void onUnavailabilityCallback(void* context, const char* cameraId) { ((NdkCamera*)context)->onUnavailabilityCallback(cameraId); XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::onUnavailability CameraId: %s", cameraId); } static void onDisconnected(void* context, ACameraDevice* device) { XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::onDisconnected CameraId: %s", ACameraDevice_getId(device)); } static void onError(void* context, ACameraDevice* device, int error) { if (ACAMERA_ERROR_CAMERA_DEVICE == error) { } XYLOG(XYLOG_SEVERITY_ERROR, "CameraStatus::onError CameraId: %s err=%d", ACameraDevice_getId(device), error); std::string msg = "NdkCamera error code=" + std::to_string(error); ((NdkCamera*)context)->on_error(msg); // __android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onError %p %d", device, error); } static void onImageAvailable(void* context, AImageReader* reader) { ((NdkCamera*)context)->onImageAvailable(reader); } static void onSessionActive(void* context, ACameraCaptureSession *session) { ALOGD("onSessionActive %p", session); } static void onSessionReady(void* context, ACameraCaptureSession *session) { ALOGD("onSessionReady %p", session); ((NdkCamera*)context)->onSessionReady(session); } static void onSessionClosed(void* context, ACameraCaptureSession *session) { XYLOG(XYLOG_SEVERITY_INFO, "onSessionClosed %p", session); } void onCaptureFailed(void* context, ACameraCaptureSession* session, ACaptureRequest* request, ACameraCaptureFailure* failure) { XYLOG(XYLOG_SEVERITY_WARNING, "onCaptureFailed session=%p request=%p reason=%d", session, request, failure->reason); } void onCaptureSequenceCompleted(void* context, ACameraCaptureSession* session, int sequenceId, int64_t frameNumber) { ALOGD("onCaptureSequenceCompleted %p %d %ld", session, sequenceId, frameNumber); } void onCaptureSequenceAborted(void* context, ACameraCaptureSession* session, int sequenceId) { ALOGD("onCaptureSequenceAborted %p %d", session, sequenceId); } void onCaptureProgressed(void* context, ACameraCaptureSession* session, ACaptureRequest* request, const ACameraMetadata* result) { ACameraMetadata_const_entry val = { 0 }; camera_status_t status = ACAMERA_ERROR_BASE; val = { 0 }; status = ACameraMetadata_getConstEntry(result, ACAMERA_CONTROL_AF_STATE, &val); if (status == ACAMERA_OK) { uint8_t afState = *(val.data.u8); ALOGD("onCaptureProgressed AF_STATE=%u", (unsigned int)afState); // ((NdkCamera*)context)->onCaptureProgressed(session, request, result); } } void onCaptureCompleted(void* context, ACameraCaptureSession* session, ACaptureRequest* request, const ACameraMetadata* result) { ((NdkCamera*)context)->onCaptureCompleted(session, request, result); } NdkCamera::NdkCamera(int32_t width, int32_t height, const NdkCamera::CAMERA_PARAMS& params) { camera_facing = 0; camera_orientation = 0; m_params = params; m_firstFrame = true; mWidth = width; mHeight = height; m_imagesCaptured = ~0; afSupported = false; hdrSupported = false; nightModeSupported = false; nightPortraitModeSupported = false; camera_manager_cb.context = this; camera_manager_cb.onCameraAvailable = ::onAvailabilityCallback; camera_manager_cb.onCameraUnavailable = ::onUnavailabilityCallback; camera_device = 0; image_reader = 0; image_reader_surface = 0; image_reader_target = 0; capture_request = 0; capture_session_output_container = 0; capture_session_output = 0; capture_session = 0; captureSequenceId = 0; } NdkCamera::~NdkCamera() { close(); } int NdkCamera::open(const std::string& cameraId) { XYLOG(XYLOG_SEVERITY_DEBUG, "DBG::try open %s", cameraId.c_str()); // camera_facing = _camera_facing; camera_manager.Create(); // ACameraManager_registerAvailabilityCallback(camera_manager, &camera_manager_cb); // find camera bool foundIt = false; DisplayDimension disp(mWidth, mHeight); DisplayDimension foundRes = disp; camera_status_t status = ACAMERA_OK; ALOGD("Start ACameraManager_getCameraIdList"); { ACameraIdList *camera_id_list = 0; for (int retry = 0; retry < 100; retry++) { status = ACameraManager_getCameraIdList(camera_manager, &camera_id_list); AASSERT(status == ACAMERA_OK, "ACameraManager_getCameraIdList return error, %d", status); for (int i = 0; i < camera_id_list->numCameras; ++i) { const char *id = camera_id_list->cameraIds[i]; if (cameraId.compare(id) == 0) { foundIt = true; break; } } ACameraManager_deleteCameraIdList(camera_id_list); if (foundIt) { break; } std::this_thread::sleep_for(std::chrono::milliseconds(16)); } ALOGD("End ACameraManager_getCameraIdList"); // ACameraManager_unregisterAvailabilityCallback(camera_manager, &camera_manager_cb); if (!foundIt) { XYLOG(XYLOG_SEVERITY_ERROR, "Camera Not Found on ID: %s", cameraId.c_str()); return 1; } mCameraId = cameraId; ACameraMetadata * camera_metadata = 0; status = ACameraManager_getCameraCharacteristics(camera_manager, cameraId.c_str(), &camera_metadata); AASSERT(status == ACAMERA_OK, "ACameraManager_getCameraCharacteristics return error, %d", status); { ACameraMetadata_const_entry e = {0}; camera_status_t status = ACameraMetadata_getConstEntry(camera_metadata,ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &e); // format of the data: format, width, height, input?, type int32 // DisplayDimension foundRes(4000, 4000); // DisplayDimension maxJPG(0, 0); foundIt = false; DisplayDimension temp; for (int i = 0; i < e.count; i += 4) { int32_t input = e.data.i32[i + 3]; int32_t format = e.data.i32[i + 0]; if (input) continue; if (format == AIMAGE_FORMAT_YUV_420_888 || format == AIMAGE_FORMAT_JPEG) { DisplayDimension res(e.data.i32[i + 1], e.data.i32[i + 2]); if (!disp.IsSameRatio(res)) { if (res.width() >= mWidth && res.height() >= mHeight) { temp = res; } continue; } if (format == AIMAGE_FORMAT_YUV_420_888 && res > disp) { foundIt = true; foundRes = res; } } } if (!foundIt) { foundRes = temp; foundIt = true; } } if (!foundIt || foundRes.width() == 0 || foundRes.height() == 0) { ACameraMetadata_free(camera_metadata); XYLOG(XYLOG_SEVERITY_ERROR, "Camera RES(%d, %d) Not Found on ID: %s", mWidth, mHeight, cameraId.c_str()); return 1; } // foundRes.Flip(); // query faceing acamera_metadata_enum_android_lens_facing_t facing = ACAMERA_LENS_FACING_FRONT; { ACameraMetadata_const_entry e = {0}; status = ACameraMetadata_getConstEntry(camera_metadata, ACAMERA_LENS_FACING, &e); AASSERT(status == ACAMERA_OK, "ACameraMetadata_getConstEntry::ACAMERA_LENS_FACING return error, %d", status); if (status == ACAMERA_OK) { facing = (acamera_metadata_enum_android_lens_facing_t) e.data.u8[0]; } } camera_facing = facing; // query orientation int orientation = 0; { ACameraMetadata_const_entry e = {0}; status = ACameraMetadata_getConstEntry(camera_metadata, ACAMERA_SENSOR_ORIENTATION, &e); AASSERT(status == ACAMERA_OK, "ACameraMetadata_getConstEntry::ACAMERA_SENSOR_ORIENTATION return error, %d", status); if (status == ACAMERA_OK) { orientation = (int) e.data.i32[0]; } } camera_orientation = orientation; { ACameraMetadata_const_entry e = {0}; status = ACameraMetadata_getConstEntry(camera_metadata,ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &e); } { ACameraMetadata_const_entry e = {0}; status = ACameraMetadata_getConstEntry(camera_metadata,ACAMERA_CONTROL_AF_AVAILABLE_MODES, &e); // AASSERT(status == ACAMERA_OK, "ACameraMetadata_getConstEntry::ACAMERA_CONTROL_AF_AVAILABLE_MODES return error, %d", status); afSupported = (status == ACAMERA_OK) && !(e.count == 0 || (e.count == 1 && e.data.u8[0] == ACAMERA_CONTROL_AF_MODE_OFF)); } { ACameraMetadata_const_entry val = {0}; status = ACameraMetadata_getConstEntry(camera_metadata,ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val); // AASSERT(status == ACAMERA_OK, "ACameraMetadata_getConstEntry::ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE return error, %d", status); if (status == ACAMERA_OK) { exposureRange.min_ = val.data.i64[0]; if (exposureRange.min_ < kMinExposureTime) { exposureRange.min_ = kMinExposureTime; } exposureRange.max_ = val.data.i64[1]; if (exposureRange.max_ > kMaxExposureTime) { exposureRange.max_ = kMaxExposureTime; } // exposureTime = exposureRange.value(2); } else { ALOGW("Unsupported ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE"); exposureRange.min_ = exposureRange.max_ = 0l; // exposureTime_ = 0l; } } { ACameraMetadata_const_entry val = {0}; status = ACameraMetadata_getConstEntry(camera_metadata, ACAMERA_CONTROL_AE_COMPENSATION_RANGE, &val); if (status == ACAMERA_OK) { aeCompensationRange.min_ = val.data.i32[0]; aeCompensationRange.max_ = val.data.i32[1]; } else { ALOGW("Unsupported ACAMERA_CONTROL_AE_COMPENSATION_RANGE"); aeCompensationRange.min_ = aeCompensationRange.max_ = 0l; } } { ACameraMetadata_const_entry val = {0}; status = ACameraMetadata_getConstEntry(camera_metadata,ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val); if (status == ACAMERA_OK) { sensitivityRange.min_ = val.data.i32[0]; sensitivityRange.max_ = val.data.i32[1]; } else { ALOGW("failed for ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE"); sensitivityRange.min_ = sensitivityRange.max_ = 0; } } { ACameraMetadata_const_entry e = {0}; status = ACameraMetadata_getConstEntry(camera_metadata,ACAMERA_CONTROL_AVAILABLE_SCENE_MODES, &e); if (status == ACAMERA_OK) { for (int i = 0; i < e.count; i++) { if (ACAMERA_CONTROL_SCENE_MODE_HDR == e.data.u8[i]) { hdrSupported = true; break; } else if (ACAMERA_CONTROL_SCENE_MODE_NIGHT == e.data.u8[i]) { nightModeSupported = true; } else if (ACAMERA_CONTROL_SCENE_MODE_NIGHT_PORTRAIT == e.data.u8[i]) { nightPortraitModeSupported = true; } } } } ACameraMetadata_free(camera_metadata); } // open camera { ACameraDevice_StateCallbacks camera_device_state_callbacks; camera_device_state_callbacks.context = this; camera_device_state_callbacks.onDisconnected = onDisconnected; camera_device_state_callbacks.onError = onError; status = ACameraManager_openCamera(camera_manager, cameraId.c_str(), &camera_device_state_callbacks, &camera_device); if (status != ACAMERA_OK) { XYLOG(XYLOG_SEVERITY_ERROR, "Failed to open camera %s res=%d", cameraId.c_str(), status); return 1; } } XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::Open %s Orientation=%d width=%d height=%d", cameraId.c_str(), camera_orientation, foundRes.width(), foundRes.height()); // setup imagereader and its surface { // media_status_t mstatus = AImageReader_new(foundRes.width(), foundRes.height(), AIMAGE_FORMAT_YUV_420_888, /*maxImages*/2, &image_reader); media_status_t mstatus = AImageReader_new(foundRes.org_width(), foundRes.org_height(), AIMAGE_FORMAT_YUV_420_888, /*maxImages*/2, &image_reader); if (mstatus == AMEDIA_OK) { AImageReader_ImageListener listener; listener.context = this; listener.onImageAvailable = ::onImageAvailable; mstatus = AImageReader_setImageListener(image_reader, &listener); mstatus = AImageReader_getWindow(image_reader, &image_reader_surface); // ANativeWindow_setBuffersGeometry(image_reader_surface, width, height,WINDOW_FORMAT_RGBX_8888); ANativeWindow_acquire(image_reader_surface); } } // std::this_thread::sleep_for(std::chrono::milliseconds(128)); // capture request { ACameraDevice_request_template templateId = (afSupported && m_params.autoFocus) ? TEMPLATE_PREVIEW : TEMPLATE_STILL_CAPTURE; status = ACameraDevice_createCaptureRequest(camera_device, templateId, &capture_request); int32_t fpsRange[2] = {1,1}; status = ACaptureRequest_setEntry_i32(capture_request, ACAMERA_CONTROL_AE_TARGET_FPS_RANGE,2,fpsRange); if (m_params.autoExposure) { uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_ON; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AE_MODE, 1, &aeMode); // ACaptureRequest_setEntry_i32(capture_request, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity_); uint8_t aePrecatureTrigger = ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_START; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER, 1, &aePrecatureTrigger); uint8_t aeLockOff = ACAMERA_CONTROL_AE_LOCK_OFF; // ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AE_LOCK, 1, &aeLockOff); } else { uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_OFF; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AE_MODE, 1, &aeMode); if (m_params.sensibility > 0) { int32_t sensitivity = m_params.sensibility; status = ACaptureRequest_setEntry_i32(capture_request, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity); } if (m_params.exposureTime > 0) { int64_t exposureTime = ((int64_t)m_params.exposureTime) * 1000000; status = ACaptureRequest_setEntry_i64(capture_request, ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime); } } if (afSupported && m_params.autoFocus) { // uint8_t afMode = ACAMERA_CONTROL_AF_MODE_CONTINUOUS_VIDEO; uint8_t afMode = ACAMERA_CONTROL_AF_MODE_CONTINUOUS_PICTURE; // uint8_t afMode = ACAMERA_CONTROL_AF_MODE_AUTO; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AF_MODE, 1, &afMode); uint8_t trig = ACAMERA_CONTROL_AF_TRIGGER_START; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AF_TRIGGER, 1, &trig); m_imagesCaptured = (status == ACAMERA_OK) ? ~0 : 0; } else { uint8_t trig = ACAMERA_CONTROL_AF_TRIGGER_START; // status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AF_TRIGGER, 1, &trig); m_imagesCaptured = (status == ACAMERA_OK) ? ~0 : 0; } // TODO: // m_imagesCaptured = 0; uint8_t awbMode = ACAMERA_CONTROL_AWB_MODE_AUTO; // res = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_AWB_MODE, 1, &awbMode); if (hdrSupported && m_params.hdrMode) { uint8_t hdrMode = ACAMERA_CONTROL_SCENE_MODE_HDR; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_SCENE_MODE, 1,&hdrMode); } if (m_params.nightMode) { if (nightModeSupported) { uint8_t sceneMode = ACAMERA_CONTROL_SCENE_MODE_NIGHT; status = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_SCENE_MODE, 1, &sceneMode); } if (nightPortraitModeSupported) { uint8_t modeEnabled = 1; // ACAMERA_CONTROL_SCENE_MODE_HDR // res = ACaptureRequest_setEntry_u8(capture_request, ACAMERA_CONTROL_SCENE_MODE_NIGHT_PORTRAIT, 1, &modeEnabled); } } status = ACameraOutputTarget_create(image_reader_surface, &image_reader_target); status = ACaptureRequest_addTarget(capture_request, image_reader_target); } // capture session { ACameraCaptureSession_stateCallbacks camera_capture_session_state_callbacks; camera_capture_session_state_callbacks.context = this; camera_capture_session_state_callbacks.onActive = onSessionActive; camera_capture_session_state_callbacks.onReady = ::onSessionReady; camera_capture_session_state_callbacks.onClosed = onSessionClosed; status = ACaptureSessionOutputContainer_create(&capture_session_output_container); status = ACaptureSessionOutput_create(image_reader_surface, &capture_session_output); status = ACaptureSessionOutputContainer_add(capture_session_output_container, capture_session_output); status = ACameraDevice_createCaptureSession(camera_device, capture_session_output_container, &camera_capture_session_state_callbacks, &capture_session); ACameraCaptureSession_captureCallbacks camera_capture_session_capture_callbacks; camera_capture_session_capture_callbacks.context = this; camera_capture_session_capture_callbacks.onCaptureStarted = 0; camera_capture_session_capture_callbacks.onCaptureProgressed = ::onCaptureProgressed; camera_capture_session_capture_callbacks.onCaptureCompleted = ::onCaptureCompleted; camera_capture_session_capture_callbacks.onCaptureFailed = onCaptureFailed; camera_capture_session_capture_callbacks.onCaptureSequenceCompleted = onCaptureSequenceCompleted; camera_capture_session_capture_callbacks.onCaptureSequenceAborted = onCaptureSequenceAborted; camera_capture_session_capture_callbacks.onCaptureBufferLost = 0; if (m_imagesCaptured != 0) { status = ACameraCaptureSession_setRepeatingRequest(capture_session, &camera_capture_session_capture_callbacks, 1, &capture_request, &captureSequenceId); } else { status = ACameraCaptureSession_capture(capture_session, &camera_capture_session_capture_callbacks, 1, &capture_request, &captureSequenceId); } m_startTime = GetMicroTimeStamp(); } return status == ACAMERA_OK ? 0 : 1; } void NdkCamera::close() { XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::try close %s", mCameraId.c_str()); camera_status_t res = ACAMERA_OK; if ((ACameraManager *)camera_manager != NULL) { // res = ACameraManager_unregisterAvailabilityCallback(camera_manager, &camera_manager_cb); } if (capture_session) { // res = ACameraCaptureSession_stopRepeating(capture_session); ACameraCaptureSession_close(capture_session); capture_session = 0; } if (capture_request) { res = ACaptureRequest_removeTarget(capture_request, image_reader_target); ACaptureRequest_free(capture_request); capture_request = 0; } if (image_reader_target) { ACameraOutputTarget_free(image_reader_target); image_reader_target = 0; } if (capture_session_output) { if (capture_session_output_container) { ACaptureSessionOutputContainer_remove(capture_session_output_container, capture_session_output); } ACaptureSessionOutput_free(capture_session_output); capture_session_output = 0; } if (capture_session_output_container) { ACaptureSessionOutputContainer_free(capture_session_output_container); capture_session_output_container = 0; } if (camera_device) { XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::close device %s, %p", mCameraId.c_str(), camera_device); ACameraDevice_close(camera_device); XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::closed device %s, %p", mCameraId.c_str(), camera_device); camera_device = 0; } if (image_reader_surface) { ANativeWindow_release(image_reader_surface); image_reader_surface = 0; } if (image_reader != NULL) { // AImageReader_setImageListener(image_reader, NULL); XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::AImageReader_delete %s", mCameraId.c_str()); AImageReader_delete(image_reader); XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::End AImageReader_delete %s", mCameraId.c_str()); image_reader = 0; } XYLOG(XYLOG_SEVERITY_INFO, "CameraStatus::closed %s", mCameraId.c_str()); } void NdkCamera::onImageAvailable(AImageReader* reader) { ALOGD("onImageAvailable %p", reader); AImage* image = 0; media_status_t status = AImageReader_acquireLatestImage(reader, &image); if (status != AMEDIA_OK) { // error XYLOG(XYLOG_SEVERITY_ERROR, "AImageReader_acquireLatestImage error: %d", status); return; } if (m_imagesCaptured == ~0 || m_imagesCaptured >= 1) { // XYLOG(XYLOG_SEVERITY_DEBUG, "m_imagesCaptured=%u wait for next image", m_imagesCaptured); // Not Ready Or Taken AImage_delete(image); return; } int32_t format; AImage_getFormat(image, &format); // ASSERT(format == AIMAGE_FORMAT_YUV_420_888); int32_t width = 0; int32_t height = 0; AImage_getWidth(image, &width); AImage_getHeight(image, &height); int32_t y_pixelStride = 0; int32_t u_pixelStride = 0; int32_t v_pixelStride = 0; AImage_getPlanePixelStride(image, 0, &y_pixelStride); AImage_getPlanePixelStride(image, 1, &u_pixelStride); AImage_getPlanePixelStride(image, 2, &v_pixelStride); int32_t y_rowStride = 0; int32_t u_rowStride = 0; int32_t v_rowStride = 0; AImage_getPlaneRowStride(image, 0, &y_rowStride); AImage_getPlaneRowStride(image, 1, &u_rowStride); AImage_getPlaneRowStride(image, 2, &v_rowStride); uint8_t* y_data = 0; uint8_t* u_data = 0; uint8_t* v_data = 0; int y_len = 0; int u_len = 0; int v_len = 0; AImage_getPlaneData(image, 0, &y_data, &y_len); AImage_getPlaneData(image, 1, &u_data, &u_len); AImage_getPlaneData(image, 2, &v_data, &v_len); if (u_data == v_data + 1 && v_data == y_data + width * height && y_pixelStride == 1 && u_pixelStride == 2 && v_pixelStride == 2 && y_rowStride == width && u_rowStride == width && v_rowStride == width) { // already nv21 :) on_image((unsigned char*)y_data, (int)width, (int)height); } else { // construct nv21 unsigned char* nv21 = new unsigned char[width * height + width * height / 2]; { // Y unsigned char* yptr = nv21; for (int y=0; yGetSensorOrientation(&facing, &angle)) { if (facing == ACAMERA_LENS_FACING_FRONT) { imageRotation = (angle + rotation_) % 360; imageRotation = (360 - imageRotation) % 360; } else { imageRotation = (angle - rotation_ + 360) % 360; } } */ int orgWidth = mWidth; int orgHeight = mHeight; // int co = camera_orientation > 0 ? camera_orientation + 90 : camera_orientation; if (m_params.orientation != 0) { int co = 0; if (camera_facing == ACAMERA_LENS_FACING_FRONT) { co = (camera_orientation + (m_params.orientation - 1) * 90) % 360; co = (360 - co) % 360; } else { co = (camera_orientation - (m_params.orientation - 1) * 90 + 360) % 360; } XYLOG(XYLOG_SEVERITY_DEBUG, "Orientation=%d Facing=%d", co, camera_facing); // int co = 0; if (co == 0) { w = nv21_width; h = nv21_height; rotate_type = camera_facing == ACAMERA_LENS_FACING_FRONT ? 2 : 1; } else if (co == 90) { w = nv21_height; h = nv21_width; orgWidth = mHeight; orgHeight = mWidth; rotate_type = camera_facing == ACAMERA_LENS_FACING_FRONT ? 5 : 6; } else if (co == 180) { w = nv21_width; h = nv21_height; rotate_type = camera_facing == ACAMERA_LENS_FACING_FRONT ? 4 : 3; } else if (co == 270) { w = nv21_height; h = nv21_width; orgWidth = mHeight; orgHeight = mWidth; rotate_type = camera_facing == ACAMERA_LENS_FACING_FRONT ? 7 : 8; } nv21_rotated.create(h + h / 2, w, CV_8UC1); ncnn::kanna_rotate_yuv420sp(nv21, nv21_width, nv21_height, nv21_rotated.data, w, h, rotate_type); yuv420data = nv21_rotated.data; } else { w = nv21_width; h = nv21_height; XYLOG(XYLOG_SEVERITY_DEBUG, "NO Orientation Facing=%d", camera_facing); } // nv21_rotated to rgb cv::Mat rgb; if (w == orgWidth && h == orgHeight) { rgb.create(h, w, CV_8UC3); // ncnn::yuv420sp2rgb(nv21_rotated.data, w, h, rgb.data); ncnn::yuv420sp2rgb_nv12(yuv420data, w, h, rgb.data); } else { cv::Mat org(h, w, CV_8UC3); ncnn::yuv420sp2rgb_nv12(yuv420data, w, h, org.data); if (w * orgHeight == h * orgWidth) // Same Ratio { cv::resize(org, rgb, cv::Size(orgWidth, orgHeight)); } else { // Crop image int left = (w - orgWidth) / 2; int top = (h - orgHeight) / 2; rgb = org(cv::Range(top, top + orgHeight), cv::Range(left, left + orgWidth)); } } on_image(rgb); } void NdkCamera::onSessionReady(ACameraCaptureSession *session) { return; camera_status_t status = ACAMERA_OK; ACameraCaptureSession_captureCallbacks camera_capture_session_capture_callbacks; camera_capture_session_capture_callbacks.context = this; camera_capture_session_capture_callbacks.onCaptureStarted = 0; camera_capture_session_capture_callbacks.onCaptureProgressed = ::onCaptureProgressed; camera_capture_session_capture_callbacks.onCaptureCompleted = ::onCaptureCompleted; camera_capture_session_capture_callbacks.onCaptureFailed = onCaptureFailed; camera_capture_session_capture_callbacks.onCaptureSequenceCompleted = onCaptureSequenceCompleted; camera_capture_session_capture_callbacks.onCaptureSequenceAborted = onCaptureSequenceAborted; camera_capture_session_capture_callbacks.onCaptureBufferLost = 0; if (m_imagesCaptured != 0) { status = ACameraCaptureSession_setRepeatingRequest(capture_session, &camera_capture_session_capture_callbacks, 1, &capture_request, &captureSequenceId); } else { status = ACameraCaptureSession_capture(capture_session, &camera_capture_session_capture_callbacks, 1, &capture_request, &captureSequenceId); } } void NdkCamera::onCaptureCompleted(ACameraCaptureSession* session, ACaptureRequest* request, const ACameraMetadata* result) { // CALL_REQUEST(setEntry_i64(requests_[PREVIEW_REQUEST_IDX].request_, // ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime_)); // ACameraMetadata_getConstEntry(result, ) ACameraMetadata_const_entry val = { 0 }; camera_status_t status = ACAMERA_ERROR_BASE; uint8_t afState = 0; if (m_imagesCaptured == ~0) { if (afSupported && (m_params.autoFocus != 0)) { val = { 0 }; status = ACameraMetadata_getConstEntry(result, ACAMERA_CONTROL_AF_STATE, &val); afState = *(val.data.u8); ALOGD("onCaptureCompleted AF_STATE=%u", (unsigned int)afState); if (afState == ACAMERA_CONTROL_AF_STATE_PASSIVE_FOCUSED || afState == ACAMERA_CONTROL_AF_STATE_FOCUSED_LOCKED) // if (afState != ACAMERA_CONTROL_AF_STATE_INACTIVE) { m_imagesCaptured = 0; } else { unsigned long long ts = GetMicroTimeStamp(); if (ts - m_startTime >= m_params.focusTimeout) { ALOGD("onCaptureCompleted Timeout for AutoFocus And will Capture AF_STATE=%u", (unsigned int)afState); m_imagesCaptured = 0; } } } else { m_imagesCaptured = 0; } } if (m_imagesCaptured != 0 || camera_facing == 2) { return; } val = { 0 }; status = ACameraMetadata_getConstEntry(result, ACAMERA_SENSOR_EXPOSURE_TIME, &val); int64_t exTime = (status == ACAMERA_OK) ? val.data.i64[0] : -1; mResult.exposureTime = exTime; val = { 0 }; status = ACameraMetadata_getConstEntry(result, ACAMERA_CONTROL_AE_MODE, &val); uint8_t aeMode = (status == ACAMERA_OK) ? val.data.u8[0] : 0; // ACaptureRequest_setEntry_i32(capture_request, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity_); mResult.autoExposure = aeMode; val = { 0 }; float focusDistance = NAN; if (afSupported && (m_params.autoFocus != 0)) { status = ACameraMetadata_getConstEntry(result, ACAMERA_LENS_FOCUS_DISTANCE, &val); if (status == ACAMERA_OK) { focusDistance = *val.data.f; } } mResult.FocusDistance = focusDistance; val = { 0 }; status = ACameraMetadata_getConstEntry(result, ACAMERA_CONTROL_AF_STATE, &val); mResult.afState = *(val.data.u8); ALOGD("onCaptureCompleted AF_STATE=%u", (unsigned int)afState); val = {0}; status = ACameraMetadata_getConstEntry(result, ACAMERA_SENSOR_SENSITIVITY, &val); mResult.sensitibity = *(val.data.i32); val = {0}; status = ACameraMetadata_getConstEntry(result, ACAMERA_CONTROL_SCENE_MODE, &val); mResult.hdrMode = (*(val.data.u8) == ACAMERA_CONTROL_SCENE_MODE_HDR) ? 1 : 0; val = {0}; status = ACameraMetadata_getConstEntry(result, ACAMERA_CONTROL_AF_MODE, &val); mResult.autoFocus = *(val.data.u8); ALOGD("onCaptureCompleted EXPOSURE_TIME=%lld, FocusDis=%f camera id=%s, AE=%s AF_STATE=%u", exTime, focusDistance, mCameraId.c_str(), ((aeMode == 1) ? "ON" : "OFF"), afState); // __android_log_print(ANDROID_LOG_WARN, "NdkCamera", "onCaptureCompleted %p %p %p", session, request, result); } void NdkCamera::onAvailabilityCallback(const char* cameraId) { std::string s(cameraId); m_locker.lock(); m_availableCameras.insert(s); m_locker.unlock(); } void NdkCamera::onUnavailabilityCallback(const char* cameraId) { std::string s(cameraId); m_locker.lock(); m_availableCameras.erase(s); m_locker.unlock(); } bool NdkCamera::IsCameraAvailable(const std::string& cameraId) { bool existed = false; m_locker.lock(); existed = (m_availableCameras.find(cameraId) != m_availableCameras.cend()); m_locker.unlock(); return existed; }