Changed algorithm of Android camera synchronisation --- added "auto-grab" mode.

This commit is contained in:
Leonid Beynenson 2011-04-29 19:03:41 +00:00
parent e7ef84b2c2
commit e262f054ad
2 changed files with 83 additions and 26 deletions

View File

@ -353,6 +353,7 @@ enum
CV_CAP_PROP_TRIGGER_DELAY =25, CV_CAP_PROP_TRIGGER_DELAY =25,
CV_CAP_PROP_WHITE_BALANCE_RED_V =26, CV_CAP_PROP_WHITE_BALANCE_RED_V =26,
CV_CAP_PROP_MAX_DC1394 =27, CV_CAP_PROP_MAX_DC1394 =27,
CV_CAP_PROP_AUTOGRAB =1024, // property for highgui class CvCapture_Android only
// OpenNI map generators // OpenNI map generators
CV_CAP_OPENNI_DEPTH_GENERATOR = 0, CV_CAP_OPENNI_DEPTH_GENERATOR = 0,
CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 31, CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 31,

View File

@ -102,10 +102,18 @@ private:
bool m_hasGray; bool m_hasGray;
bool m_hasColor; bool m_hasColor;
enum CvCapture_Android_DataState {
CVCAPTURE_ANDROID_STATE_NO_FRAME=0,
CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED,
CVCAPTURE_ANDROID_STATE_HAS_FRAME_GRABBED
};
volatile CvCapture_Android_DataState m_dataState;
//synchronization //synchronization
pthread_mutex_t m_nextFrameMutex; pthread_mutex_t m_nextFrameMutex;
pthread_cond_t m_nextFrameCond; pthread_cond_t m_nextFrameCond;
volatile bool m_waitingNextFrame; volatile bool m_waitingNextFrame;
volatile bool m_shouldAutoGrab;
void prepareCacheForYUV420i(int width, int height); void prepareCacheForYUV420i(int width, int height);
static bool convertYUV420i2Grey(int width, int height, const unsigned char* yuv, cv::Mat& resmat); static bool convertYUV420i2Grey(int width, int height, const unsigned char* yuv, cv::Mat& resmat);
@ -131,11 +139,15 @@ public:
if(isConnected() && buffer != 0 && bufferSize > 0) if(isConnected() && buffer != 0 && bufferSize > 0)
{ {
m_framesReceived++; m_framesReceived++;
if (m_capture->m_waitingNextFrame) if (m_capture->m_waitingNextFrame || m_capture->m_shouldAutoGrab)
{ {
m_capture->setFrame(buffer, bufferSize);
pthread_mutex_lock(&m_capture->m_nextFrameMutex); pthread_mutex_lock(&m_capture->m_nextFrameMutex);
m_capture->setFrame(buffer, bufferSize);
m_capture->m_dataState = CvCapture_Android::CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED;
m_capture->m_waitingNextFrame = false;//set flag that no more frames required at this moment m_capture->m_waitingNextFrame = false;//set flag that no more frames required at this moment
pthread_cond_broadcast(&m_capture->m_nextFrameCond); pthread_cond_broadcast(&m_capture->m_nextFrameCond);
pthread_mutex_unlock(&m_capture->m_nextFrameMutex); pthread_mutex_unlock(&m_capture->m_nextFrameMutex);
} }
@ -174,7 +186,9 @@ CvCapture_Android::CvCapture_Android(int cameraId)
m_frameYUV420inext = 0; m_frameYUV420inext = 0;
m_hasGray = false; m_hasGray = false;
m_hasColor = false; m_hasColor = false;
m_dataState = CVCAPTURE_ANDROID_STATE_NO_FRAME;
m_waitingNextFrame = false; m_waitingNextFrame = false;
m_shouldAutoGrab = false;
m_framesGrabbed = 0; m_framesGrabbed = 0;
m_CameraParamsChanged = false; m_CameraParamsChanged = false;
@ -209,16 +223,22 @@ CvCapture_Android::~CvCapture_Android()
{ {
((HighguiAndroidCameraActivity*)m_activity)->LogFramesRate(); ((HighguiAndroidCameraActivity*)m_activity)->LogFramesRate();
//m_activity->disconnect() will be automatically called inside destructor;
delete m_frameYUV420i;
delete m_frameYUV420inext;
m_frameYUV420i = 0;
m_frameYUV420inext = 0;
pthread_mutex_lock(&m_nextFrameMutex); pthread_mutex_lock(&m_nextFrameMutex);
unsigned char *tmp1=m_frameYUV420i;
unsigned char *tmp2=m_frameYUV420inext;
m_frameYUV420i = 0;
m_frameYUV420inext = 0;
delete tmp1;
delete tmp2;
m_dataState=CVCAPTURE_ANDROID_STATE_NO_FRAME;
pthread_cond_broadcast(&m_nextFrameCond); pthread_cond_broadcast(&m_nextFrameCond);
pthread_mutex_unlock(&m_nextFrameMutex); pthread_mutex_unlock(&m_nextFrameMutex);
//m_activity->disconnect() will be automatically called inside destructor;
delete m_activity; delete m_activity;
m_activity = 0; m_activity = 0;
@ -255,12 +275,21 @@ bool CvCapture_Android::setProperty( int propIdx, double propValue )
case CV_CAP_PROP_FRAME_HEIGHT: case CV_CAP_PROP_FRAME_HEIGHT:
m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT, propValue); m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT, propValue);
break; break;
case CV_CAP_PROP_AUTOGRAB:
m_shouldAutoGrab=(propValue != 0);
break;
default: default:
CV_Error( CV_StsOutOfRange, "Failed attempt to SET unsupported camera property." ); CV_Error( CV_StsOutOfRange, "Failed attempt to SET unsupported camera property." );
break; return false;
} }
if (propIdx != CV_CAP_PROP_AUTOGRAB) {// property for highgui class CvCapture_Android only
m_CameraParamsChanged = true; m_CameraParamsChanged = true;
} }
res = true;
}
return res; return res;
} }
@ -270,59 +299,84 @@ bool CvCapture_Android::grabFrame()
if( !isOpened() ) if( !isOpened() )
return false; return false;
bool res=false;
pthread_mutex_lock(&m_nextFrameMutex); pthread_mutex_lock(&m_nextFrameMutex);
if (m_CameraParamsChanged) if (m_CameraParamsChanged)
{ {
m_activity->applyProperties(); m_activity->applyProperties();
m_CameraParamsChanged = false; m_CameraParamsChanged = false;
m_dataState= CVCAPTURE_ANDROID_STATE_NO_FRAME;//we will wait new frame
} }
if (m_dataState!=CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED) {
m_waitingNextFrame = true; m_waitingNextFrame = true;
pthread_cond_wait(&m_nextFrameCond, &m_nextFrameMutex); pthread_cond_wait(&m_nextFrameCond, &m_nextFrameMutex);
int res=pthread_mutex_unlock(&m_nextFrameMutex); }
if (res) {
LOGE("Error in CvCapture_Android::grabFrame: pthread_mutex_unlock returned %d --- probably, this object has been destroyed", res); if (m_dataState == CVCAPTURE_ANDROID_STATE_HAS_NEW_FRAME_UNGRABBED) {
//swap current and new frames
unsigned char* tmp = m_frameYUV420i;
m_frameYUV420i = m_frameYUV420inext;
m_frameYUV420inext = tmp;
//discard cached frames
m_hasGray = false;
m_hasColor = false;
m_dataState=CVCAPTURE_ANDROID_STATE_HAS_FRAME_GRABBED;
m_framesGrabbed++;
res=true;
}
int res_unlock=pthread_mutex_unlock(&m_nextFrameMutex);
if (res_unlock) {
LOGE("Error in CvCapture_Android::grabFrame: pthread_mutex_unlock returned %d --- probably, this object has been destroyed", res_unlock);
return false; return false;
} }
m_framesGrabbed++; return res;
return true;
} }
IplImage* CvCapture_Android::retrieveFrame( int outputType ) IplImage* CvCapture_Android::retrieveFrame( int outputType )
{ {
IplImage* image = 0; IplImage* image = NULL;
if (0 != m_frameYUV420i)
unsigned char *current_frameYUV420i=m_frameYUV420i;
//Attention! all the operations in this function below should occupy less time than the period between two frames from camera
if (NULL != current_frameYUV420i)
{ {
switch(outputType) switch(outputType)
{ {
case CV_CAP_ANDROID_COLOR_FRAME: case CV_CAP_ANDROID_COLOR_FRAME:
if (!m_hasColor) if (!m_hasColor)
if (!(m_hasColor = convertYUV420i2BGR888(m_width, m_height, m_frameYUV420i, m_frameColor.mat))) if (!(m_hasColor = convertYUV420i2BGR888(m_width, m_height, current_frameYUV420i, m_frameColor.mat)))
return 0; return NULL;
image = m_frameColor.getIplImagePtr(); image = m_frameColor.getIplImagePtr();
break; break;
case CV_CAP_ANDROID_GREY_FRAME: case CV_CAP_ANDROID_GREY_FRAME:
if (!m_hasGray) if (!m_hasGray)
if (!(m_hasGray = convertYUV420i2Grey(m_width, m_height, m_frameYUV420i, m_frameGray.mat))) if (!(m_hasGray = convertYUV420i2Grey(m_width, m_height, current_frameYUV420i, m_frameGray.mat)))
return 0; return NULL;
image = m_frameGray.getIplImagePtr(); image = m_frameGray.getIplImagePtr();
break; break;
case CV_CAP_ANDROID_COLOR_FRAME_RGB: case CV_CAP_ANDROID_COLOR_FRAME_RGB:
if (!m_hasColor) if (!m_hasColor)
if (!(m_hasColor = convertYUV420i2RGB888(m_width, m_height, m_frameYUV420i, m_frameColor.mat))) if (!(m_hasColor = convertYUV420i2RGB888(m_width, m_height, current_frameYUV420i, m_frameColor.mat)))
return 0; return NULL;
image = m_frameColor.getIplImagePtr(); image = m_frameColor.getIplImagePtr();
break; break;
default: default:
LOGE("Unsupported frame output format: %d", outputType); LOGE("Unsupported frame output format: %d", outputType);
CV_Error( CV_StsOutOfRange, "Output frame format is not supported." ); CV_Error( CV_StsOutOfRange, "Output frame format is not supported." );
image = 0; image = NULL;
break; break;
} }
} }
return image; return image;
} }
//Attention: this method should be called inside pthread_mutex_lock(m_nextFrameMutex) only
void CvCapture_Android::setFrame(const void* buffer, int bufferSize) void CvCapture_Android::setFrame(const void* buffer, int bufferSize)
{ {
int width = m_activity->getFrameWidth(); int width = m_activity->getFrameWidth();
@ -335,12 +389,13 @@ void CvCapture_Android::setFrame(const void* buffer, int bufferSize)
return; return;
} }
//allocate memery if needed //allocate memory if needed
prepareCacheForYUV420i(width, height); prepareCacheForYUV420i(width, height);
//copy data //copy data
memcpy(m_frameYUV420inext, buffer, bufferSize); memcpy(m_frameYUV420inext, buffer, bufferSize);
#if 0 //moved this part of code into grabFrame
//swap current and new frames //swap current and new frames
unsigned char* tmp = m_frameYUV420i; unsigned char* tmp = m_frameYUV420i;
m_frameYUV420i = m_frameYUV420inext; m_frameYUV420i = m_frameYUV420inext;
@ -349,6 +404,7 @@ void CvCapture_Android::setFrame(const void* buffer, int bufferSize)
//discard cached frames //discard cached frames
m_hasGray = false; m_hasGray = false;
m_hasColor = false; m_hasColor = false;
#endif
} }
void CvCapture_Android::prepareCacheForYUV420i(int width, int height) void CvCapture_Android::prepareCacheForYUV420i(int width, int height)