mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
507 lines
16 KiB
507 lines
16 KiB
#if !defined(ANDROID_r2_2_2) && !defined(ANDROID_r2_3_3) && !defined(ANDROID_r3_0_1) |
|
#error unsupported version of Android |
|
#endif |
|
|
|
#include <camera/CameraHardwareInterface.h> |
|
#include "camera_wrapper.h" |
|
#include "../include/camera_properties.h" |
|
#include <string> |
|
|
|
//undef logging macro from /system/core/libcutils/loghack.h |
|
#ifdef LOGD |
|
#undef LOGD |
|
#endif |
|
|
|
#ifdef LOGI |
|
#undef LOGI |
|
#endif |
|
|
|
#ifdef LOGW |
|
#undef LOGW |
|
#endif |
|
|
|
#ifdef LOGE |
|
#undef LOGE |
|
#endif |
|
|
|
|
|
// LOGGING |
|
#include <android/log.h> |
|
#define CAMERA_LOG_TAG "OpenCV_NativeCamera" |
|
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
|
|
using namespace android; |
|
|
|
void debugShowFPS() |
|
{ |
|
static int mFrameCount = 0; |
|
static int mLastFrameCount = 0; |
|
static nsecs_t mLastFpsTime = systemTime(); |
|
static float mFps = 0; |
|
|
|
mFrameCount++; |
|
|
|
if (( mFrameCount % 30 ) != 0) |
|
return; |
|
|
|
nsecs_t now = systemTime(); |
|
nsecs_t diff = now - mLastFpsTime; |
|
|
|
if (diff==0) |
|
return; |
|
|
|
mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; |
|
mLastFpsTime = now; |
|
mLastFrameCount = mFrameCount; |
|
LOGI("### Camera FPS ### [%d] Frames, %.2f FPS", mFrameCount, mFps); |
|
} |
|
|
|
class CameraHandler: public CameraListener |
|
{ |
|
protected: |
|
int cameraId; |
|
sp<Camera> camera; |
|
CameraParameters params; |
|
CameraCallback cameraCallback; |
|
void* userData; |
|
|
|
int emptyCameraCallbackReported; |
|
|
|
void doCall(void* buffer, size_t bufferSize) |
|
{ |
|
if (cameraCallback == 0) |
|
{ |
|
if (!emptyCameraCallbackReported) |
|
LOGE("CameraHandler::doCall(void*, size_t): Camera callback is empty!"); |
|
|
|
emptyCameraCallbackReported++; |
|
} |
|
else |
|
{ |
|
bool res = (*cameraCallback)(buffer, bufferSize, userData); |
|
|
|
if(!res) |
|
{ |
|
LOGE("CameraHandler::doCall(void*, size_t): cameraCallback returns false (camera connection will be closed)"); |
|
closeCameraConnect(); |
|
} |
|
} |
|
} |
|
|
|
void doCall(const sp<IMemory>& dataPtr) |
|
{ |
|
if (dataPtr == NULL) |
|
{ |
|
LOGE("CameraHandler::doCall(const sp<IMemory>&): dataPtr==NULL (no frame to handle)"); |
|
return; |
|
} |
|
|
|
size_t size = dataPtr->size(); |
|
if (size <= 0) |
|
{ |
|
LOGE("CameraHandler::doCall(const sp<IMemory>&): IMemory object is of zero size"); |
|
return; |
|
} |
|
|
|
void* buffer = (void *)dataPtr->pointer(); |
|
if (!buffer) |
|
{ |
|
LOGE("CameraHandler::doCall(const sp<IMemory>&): Buffer pointer is NULL"); |
|
return; |
|
} |
|
|
|
doCall(buffer, size); |
|
} |
|
|
|
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) |
|
{ |
|
static uint32_t count = 0; |
|
count++; |
|
|
|
LOGE("Recording cb: %d %lld %%p Offset:%%d Stride:%%d\n", msgType, timestamp); |
|
|
|
if (dataPtr == NULL) |
|
{ |
|
LOGE("postDataTimestamp: dataPtr IS ZERO -- returning"); |
|
camera->releaseRecordingFrame(dataPtr); |
|
LOGE("postDataTimestamp: camera->releaseRecordingFrame(dataPtr) is done"); |
|
return; |
|
} |
|
|
|
uint8_t *ptr = (uint8_t*) dataPtr->pointer(); |
|
if (ptr) |
|
LOGE("VID_CB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9]); |
|
else |
|
LOGE("postDataTimestamp: Ptr is zero"); |
|
|
|
camera->releaseRecordingFrame(dataPtr); |
|
} |
|
|
|
public: |
|
CameraHandler(CameraCallback callback = 0, void* _userData = 0): |
|
cameraId(0), |
|
cameraCallback(callback), |
|
userData(_userData), |
|
emptyCameraCallbackReported(0) |
|
{ |
|
LOGD("Instantiated new CameraHandler (%p, %p)", callback, _userData); |
|
} |
|
|
|
virtual ~CameraHandler() |
|
{ |
|
LOGD("CameraHandler destructor is called"); |
|
} |
|
|
|
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) |
|
{ |
|
LOGE("CameraHandler::Notify: msgType=%d ext1=%d ext2=%d\n", msgType, ext1, ext2); |
|
#if 0 |
|
if ( msgType & CAMERA_MSG_FOCUS ) |
|
LOGE("CameraHandler::Notify AutoFocus %s in %llu us\n", (ext1) ? "OK" : "FAIL", timevalDelay(&autofocus_start)); |
|
|
|
if ( msgType & CAMERA_MSG_SHUTTER ) |
|
LOGE("CameraHandler::Notify Shutter done in %llu us\n", timeval_delay(&picture_start)); |
|
#endif |
|
} |
|
|
|
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) |
|
{ |
|
debugShowFPS(); |
|
|
|
if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) |
|
{ |
|
doCall(dataPtr); |
|
return; |
|
} |
|
|
|
if (msgType != CAMERA_MSG_PREVIEW_FRAME) |
|
LOGE("CameraHandler::postData Recieved message %d is not equal to CAMERA_MSG_PREVIEW_FRAME (%d)", (int) msgType, CAMERA_MSG_PREVIEW_FRAME); |
|
|
|
if ( msgType & CAMERA_MSG_RAW_IMAGE ) |
|
LOGE("CameraHandler::postData Unexpected data format: RAW\n"); |
|
|
|
if (msgType & CAMERA_MSG_POSTVIEW_FRAME) |
|
LOGE("CameraHandler::postData Unexpected data format: Postview frame\n"); |
|
|
|
if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) |
|
LOGE("CameraHandler::postData Unexpected data format: JPEG"); |
|
} |
|
|
|
static CameraHandler* initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters); |
|
void closeCameraConnect(); |
|
double getProperty(int propIdx); |
|
void setProperty(int propIdx, double value); |
|
static void applyProperties(CameraHandler** ppcameraHandler); |
|
|
|
std::string cameraPropertySupportedPreviewSizesString; |
|
std::string cameraPropertyPreviewFormatString; |
|
}; |
|
|
|
|
|
CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters) |
|
{ |
|
LOGD("CameraHandler::initCameraConnect(%p, %d, %p, %p)", callback, cameraId, userData, prevCameraParameters); |
|
|
|
sp<Camera> camera = 0; |
|
|
|
#ifdef ANDROID_r2_2_2 |
|
camera = Camera::connect(); |
|
#endif |
|
#ifdef ANDROID_r2_3_3 |
|
camera = Camera::connect(cameraId); |
|
#endif |
|
|
|
if ( 0 == camera.get() ) |
|
{ |
|
LOGE("initCameraConnect: Unable to connect to CameraService\n"); |
|
return 0; |
|
} |
|
|
|
CameraHandler* handler = new CameraHandler(callback, userData); |
|
camera->setListener(handler); |
|
|
|
handler->camera = camera; |
|
handler->cameraId = cameraId; |
|
|
|
if (prevCameraParameters != 0) |
|
{ |
|
LOGI("initCameraConnect: Setting paramers from previous camera handler"); |
|
camera->setParameters(prevCameraParameters->flatten()); |
|
handler->params.unflatten(prevCameraParameters->flatten()); |
|
} |
|
else |
|
{ |
|
android::String8 params_str = camera->getParameters(); |
|
LOGI("initCameraConnect: [%s]", params_str.string()); |
|
|
|
handler->params.unflatten(params_str); |
|
|
|
LOGD("Supported Cameras: %s", handler->params.get("camera-indexes")); |
|
LOGD("Supported Picture Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES)); |
|
LOGD("Supported Picture Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); |
|
LOGD("Supported Preview Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)); |
|
LOGD("Supported Preview Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS)); |
|
LOGD("Supported Preview Frame Rates: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); |
|
LOGD("Supported Thumbnail Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES)); |
|
LOGD("Supported Whitebalance Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE)); |
|
LOGD("Supported Effects: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_EFFECTS)); |
|
LOGD("Supported Scene Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES)); |
|
LOGD("Supported Focus Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); |
|
LOGD("Supported Antibanding Options: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING)); |
|
LOGD("Supported Flash Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES)); |
|
|
|
|
|
//check if yuv420sp format available. Set this format as preview format. |
|
const char* available_formats = handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); |
|
if (available_formats != 0) |
|
{ |
|
const char* format_to_set = 0; |
|
const char* pos = available_formats; |
|
const char* ptr = pos; |
|
while(true) |
|
{ |
|
while(*ptr != 0 && *ptr != ',') ++ptr; |
|
if (ptr != pos) |
|
{ |
|
if (0 == strncmp(pos, "yuv420sp", ptr - pos)) |
|
{ |
|
format_to_set = "yuv420sp"; |
|
break; |
|
} |
|
if (0 == strncmp(pos, "yuv420i", ptr - pos)) |
|
format_to_set = "yuv420i"; |
|
} |
|
if (*ptr == 0) |
|
break; |
|
pos = ++ptr; |
|
} |
|
|
|
if (0 != format_to_set) |
|
{ |
|
handler->params.setPreviewFormat(format_to_set); |
|
|
|
status_t resParams = handler->camera->setParameters(handler->params.flatten()); |
|
|
|
if (resParams != 0) |
|
LOGE("initCameraConnect: failed to set preview format to %s", format_to_set); |
|
else |
|
LOGD("initCameraConnect: preview format is set to %s", format_to_set); |
|
} |
|
} |
|
} |
|
|
|
#ifdef ANDROID_r2_2_2 |
|
status_t pdstatus = camera->setPreviewDisplay(sp<ISurface>(0 /*new DummySurface*/)); |
|
if (pdstatus != 0) |
|
LOGE("initCameraConnect: failed setPreviewDisplay(0) call; camera migth not work correcttly on some devices"); |
|
#endif |
|
|
|
////ATTENTION: switching between two versions: with and without copying memory inside Android OS |
|
//// see the method CameraService::Client::copyFrameAndPostCopiedFrame and where it is used |
|
#if 1 |
|
camera->setPreviewCallbackFlags( FRAME_CALLBACK_FLAG_ENABLE_MASK | FRAME_CALLBACK_FLAG_COPY_OUT_MASK);//with copy |
|
#else |
|
camera->setPreviewCallbackFlags( FRAME_CALLBACK_FLAG_ENABLE_MASK );//without copy |
|
#endif |
|
|
|
status_t resStart = camera->startPreview(); |
|
|
|
if (resStart != 0) |
|
{ |
|
LOGE("initCameraConnect: startPreview() fails. Closing camera connection..."); |
|
handler->closeCameraConnect(); |
|
handler = 0; |
|
} |
|
|
|
return handler; |
|
} |
|
|
|
void CameraHandler::closeCameraConnect() |
|
{ |
|
if (camera == NULL) |
|
{ |
|
LOGI("... camera is already NULL"); |
|
return; |
|
} |
|
|
|
camera->stopPreview(); |
|
camera->disconnect(); |
|
camera.clear(); |
|
|
|
camera=NULL; |
|
// ATTENTION!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
// When we set |
|
// camera=NULL |
|
// above, the pointed instance of android::Camera object is destructed, |
|
// since this member `camera' has type android::sp<Camera> (android smart pointer template class), |
|
// and this is the only pointer to it. |
|
// |
|
// BUT this instance of CameraHandler is set as a listener for that android::Camera object |
|
// (see the function CameraHandler::initCameraConnect above), |
|
// so this instance of CameraHandler is pointed from that android::Camera object as |
|
// sp<CameraListener> mListener |
|
// and there is no other android smart pointers to this. |
|
// |
|
// It means, when that instance of the android::Camera object is destructed, |
|
// it calls destructor for this CameraHandler instance too. |
|
// |
|
// So, this line `camera=NULL' causes to the call `delete this' |
|
// (see destructor of the template class android::sp) |
|
// |
|
// So, we must not call `delete this' after the line, since it just has been called indeed |
|
} |
|
|
|
double CameraHandler::getProperty(int propIdx) |
|
{ |
|
LOGD("CameraHandler::getProperty(%d)", propIdx); |
|
|
|
switch (propIdx) |
|
{ |
|
case ANDROID_CAMERA_PROPERTY_FRAMEWIDTH: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
return w; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
return h; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING: |
|
{ |
|
cameraPropertySupportedPreviewSizesString = params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES); |
|
union {const char* str;double res;} u; |
|
memset(&u.res, 0, sizeof(u.res)); |
|
u.str = cameraPropertySupportedPreviewSizesString.c_str(); |
|
return u.res; |
|
} |
|
|
|
case ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING: |
|
{ |
|
const char* fmt = params.get(CameraParameters::KEY_PREVIEW_FORMAT); |
|
if (fmt == CameraParameters::PIXEL_FORMAT_YUV422SP) |
|
fmt = "yuv422sp"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_YUV420SP) |
|
fmt = "yuv420sp"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_YUV422I) |
|
fmt = "yuv422i"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_RGB565) |
|
fmt = "rgb565"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_JPEG) |
|
fmt = "jpeg"; |
|
cameraPropertyPreviewFormatString = fmt; |
|
|
|
union {const char* str;double res;} u; |
|
memset(&u.res, 0, sizeof(u.res)); |
|
u.str = cameraPropertyPreviewFormatString.c_str(); |
|
return u.res; |
|
} |
|
|
|
}; |
|
return -1; |
|
} |
|
|
|
void CameraHandler::setProperty(int propIdx, double value) |
|
{ |
|
LOGD("CameraHandler::setProperty(%d, %f)", propIdx, value); |
|
|
|
switch (propIdx) |
|
{ |
|
case ANDROID_CAMERA_PROPERTY_FRAMEWIDTH: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
w = (int)value; |
|
params.setPreviewSize(w, h); |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
h = (int)value; |
|
params.setPreviewSize(w, h); |
|
} |
|
break; |
|
}; |
|
} |
|
|
|
void CameraHandler::applyProperties(CameraHandler** ppcameraHandler) |
|
{ |
|
LOGD("CameraHandler::applyProperties()"); |
|
|
|
if (ppcameraHandler == 0) |
|
{ |
|
LOGE("applyProperties: Passed NULL ppcameraHandler"); |
|
return; |
|
} |
|
|
|
if (*ppcameraHandler == 0) |
|
{ |
|
LOGE("applyProperties: Passed null *ppcameraHandler"); |
|
return; |
|
} |
|
|
|
LOGD("CameraHandler::applyProperties()"); |
|
CameraHandler* previousCameraHandler=*ppcameraHandler; |
|
CameraParameters curCameraParameters(previousCameraHandler->params.flatten()); |
|
|
|
CameraCallback cameraCallback=previousCameraHandler->cameraCallback; |
|
void* userData=previousCameraHandler->userData; |
|
int cameraId=previousCameraHandler->cameraId; |
|
|
|
LOGD("CameraHandler::applyProperties(): before previousCameraHandler->closeCameraConnect"); |
|
previousCameraHandler->closeCameraConnect(); |
|
LOGD("CameraHandler::applyProperties(): after previousCameraHandler->closeCameraConnect"); |
|
|
|
|
|
LOGD("CameraHandler::applyProperties(): before initCameraConnect"); |
|
CameraHandler* handler=initCameraConnect(cameraCallback, cameraId, userData, &curCameraParameters); |
|
LOGD("CameraHandler::applyProperties(): after initCameraConnect, handler=0x%x", (int)handler); |
|
if (handler == NULL) { |
|
LOGE("ERROR in applyProperties --- cannot reinit camera"); |
|
handler=initCameraConnect(cameraCallback, cameraId, userData, NULL); |
|
LOGD("CameraHandler::applyProperties(): repeate initCameraConnect after ERROR, handler=0x%x", (int)handler); |
|
if (handler == NULL) { |
|
LOGE("ERROR in applyProperties --- cannot reinit camera AGAIN --- cannot do anything else"); |
|
} |
|
} |
|
(*ppcameraHandler)=handler; |
|
} |
|
|
|
|
|
extern "C" { |
|
|
|
void* initCameraConnectC(void* callback, int cameraId, void* userData) |
|
{ |
|
return CameraHandler::initCameraConnect((CameraCallback)callback, cameraId, userData, NULL); |
|
} |
|
|
|
void closeCameraConnectC(void** camera) |
|
{ |
|
CameraHandler** cc = (CameraHandler**)camera; |
|
(*cc)->closeCameraConnect(); |
|
*cc = 0; |
|
} |
|
|
|
double getCameraPropertyC(void* camera, int propIdx) |
|
{ |
|
return ((CameraHandler*)camera)->getProperty(propIdx); |
|
} |
|
|
|
void setCameraPropertyC(void* camera, int propIdx, double value) |
|
{ |
|
((CameraHandler*)camera)->setProperty(propIdx,value); |
|
} |
|
|
|
void applyCameraPropertiesC(void** camera) |
|
{ |
|
CameraHandler::applyProperties((CameraHandler**)camera); |
|
} |
|
|
|
}
|
|
|