#include "CameraDebug.h" #if DBG_CALLBACK #define LOG_NDEBUG 0 #endif #define LOG_TAG "CallbackNotifier" #include #include #include #include "V4L2CameraDevice2.h" #include "CallbackNotifier.h" #include "PreviewWindow.h" extern "C" int scaler(unsigned char * psrc, unsigned char * pdst, int src_w, int src_h, int dst_w, int dst_h, int fmt, int align); namespace android { /* String representation of camera messages. */ static const char* lCameraMessages[] = { "CAMERA_MSG_ERROR", "CAMERA_MSG_SHUTTER", "CAMERA_MSG_FOCUS", "CAMERA_MSG_ZOOM", "CAMERA_MSG_PREVIEW_FRAME", "CAMERA_MSG_VIDEO_FRAME", "CAMERA_MSG_POSTVIEW_FRAME", "CAMERA_MSG_RAW_IMAGE", "CAMERA_MSG_COMPRESSED_IMAGE", "CAMERA_MSG_RAW_IMAGE_NOTIFY", "CAMERA_MSG_PREVIEW_METADATA", "CAMERA_MSG_CONTINUOUSSNAP", "CAMERA_MSG_SNAP" "CAMERA_MSG_SNAP_THUMB" "CAMERA_MSG_SNAP_FD", "CAMERA_SMART_MSG_STATUS" }; static const int lCameraMessagesNum = sizeof(lCameraMessages) / sizeof(char*); /* Builds an array of strings for the given set of messages. * Param: * msg - Messages to get strings for, * strings - Array where to save strings * max - Maximum number of entries in the array. * Return: * Number of strings saved into the 'strings' array. */ static int GetMessageStrings(uint32_t msg, const char** strings, int max) { int index = 0; int out = 0; while (msg != 0 && out < max && index < lCameraMessagesNum) { while ((msg & 0x1) == 0 && index < lCameraMessagesNum) { msg >>= 1; index++; } if ((msg & 0x1) != 0 && index < lCameraMessagesNum) { strings[out] = lCameraMessages[index]; out++; msg >>= 1; index++; } } return out; } /* Logs messages, enabled by the mask. */ #if DEBUG_MSG static void PrintMessages(uint32_t msg) { const char* strs[lCameraMessagesNum]; const int translated = GetMessageStrings(msg, strs, lCameraMessagesNum); for (int n = 0; n < translated; n++) { LOGV(" %s", strs[n]); } } #else #define PrintMessages(msg) (void(0)) #endif /*static void formatToNV21(void *dst, void *src, int width, int height, size_t stride, uint32_t offset, unsigned int bytesPerPixel, size_t length, int pixelFormat) { unsigned int alignedRow, row; unsigned char *bufferDst, *bufferSrc; unsigned char *bufferDstEnd, *bufferSrcEnd; uint16_t *bufferSrc_UV; unsigned long y_uv[2]; y_uv[0] = (unsigned long)src; y_uv[1] = (unsigned long)src + width*height; // NV12 -> NV21 if (pixelFormat == V4L2_PIX_FMT_NV12) { bytesPerPixel = 1; bufferDst = ( unsigned char * ) dst; bufferDstEnd = ( unsigned char * ) dst + width*height*bytesPerPixel; bufferSrc = ( unsigned char * ) y_uv[0] + offset; bufferSrcEnd = ( unsigned char * ) ( ( size_t ) y_uv[0] + length + offset); row = width*bytesPerPixel; alignedRow = stride-width; int stride_bytes = stride / 8; uint32_t xOff = offset % stride; uint32_t yOff = offset / stride; // going to convert from NV12 here and return // Step 1: Y plane: iterate through each row and copy for ( int i = 0 ; i < height ; i++) { memcpy(bufferDst, bufferSrc, row); bufferSrc += stride; bufferDst += row; if ( ( bufferSrc > bufferSrcEnd ) || ( bufferDst > bufferDstEnd ) ) { break; } } bufferSrc_UV = ( uint16_t * ) ((uint8_t*)y_uv[1] + (stride/2)*yOff + xOff); uint16_t *bufferDst_UV; // Step 2: UV plane: convert NV12 to NV21 by swapping U & V bufferDst_UV = (uint16_t *) (((uint8_t*)dst)+row*height); for (int i = 0 ; i < height/2 ; i++, bufferSrc_UV += alignedRow/2) { int n = width; asm volatile ( " pld [%[src], %[src_stride], lsl #2] \n\t" " cmp %[n], #32 \n\t" " blt 1f \n\t" "0: @ 32 byte swap \n\t" " sub %[n], %[n], #32 \n\t" " vld2.8 {q0, q1} , [%[src]]! \n\t" " vswp q0, q1 \n\t" " cmp %[n], #32 \n\t" " vst2.8 {q0,q1},[%[dst]]! \n\t" " bge 0b \n\t" "1: @ Is there enough data? \n\t" " cmp %[n], #16 \n\t" " blt 3f \n\t" "2: @ 16 byte swap \n\t" " sub %[n], %[n], #16 \n\t" " vld2.8 {d0, d1} , [%[src]]! \n\t" " vswp d0, d1 \n\t" " cmp %[n], #16 \n\t" " vst2.8 {d0,d1},[%[dst]]! \n\t" " bge 2b \n\t" "3: @ Is there enough data? \n\t" " cmp %[n], #8 \n\t" " blt 5f \n\t" "4: @ 8 byte swap \n\t" " sub %[n], %[n], #8 \n\t" " vld2.8 {d0, d1} , [%[src]]! \n\t" " vswp d0, d1 \n\t" " cmp %[n], #8 \n\t" " vst2.8 {d0[0],d1[0]},[%[dst]]! \n\t" " bge 4b \n\t" "5: @ end \n\t" #ifdef NEEDS_ARM_ERRATA_754319_754320 " vmov s0,s0 @ add noop for errata item \n\t" #endif : [dst] "+r" (bufferDst_UV), [src] "+r" (bufferSrc_UV), [n] "+r" (n) : [src_stride] "r" (stride_bytes) : "cc", "memory", "q0", "q1" ); } } }*/ static void NV12ToYVU420(void* psrc, void* pdst, int width, int height) { uint8_t* psrc_y = (uint8_t*)psrc; uint8_t* pdst_y = (uint8_t*)pdst; uint8_t* psrc_uv = (uint8_t*)psrc + width * height; uint8_t* pdst_uv = (uint8_t*)pdst + width * height; for(int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { *(uint8_t*)(pdst_y + i * width + j) = *(uint8_t*)(psrc_y + i * width + j); } } for(int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { *(uint8_t*)(pdst_uv + i * width / 2 + j) = *(uint8_t*)(psrc_uv + i * width + j * 2); *(uint8_t*)(pdst_uv + (width / 2) * (height / 2) + i * width / 2 + j) = *(uint8_t*)(psrc_uv + i * width + j * 2 + 1); } } } static void NV21ToYVU420(void* psrc, void* pdst, int width, int height) { uint8_t* psrc_y = (uint8_t*)psrc; uint8_t* pdst_y = (uint8_t*)pdst; uint8_t* psrc_uv = (uint8_t*)psrc + width * height; uint8_t* pdst_uv = (uint8_t*)pdst + width * height; for(int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { *(uint8_t*)(pdst_y + i * width + j) = *(uint8_t*)(psrc_y + i * width + j); } } for(int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { *(uint8_t*)(pdst_uv + i * width / 2 + j) = *(uint8_t*)(psrc_uv + i * width + j * 2 + 1); *(uint8_t*)(pdst_uv + (width / 2) * (height / 2) + i * width / 2 + j) = *(uint8_t*)(psrc_uv + i * width + j * 2); } } } static void YVU420ToNV21(void* psrc, void* pdst, int width, int height) { uint8_t* psrc_y = (uint8_t*)psrc; uint8_t* pdst_y = (uint8_t*)pdst; uint8_t* psrc_uv = (uint8_t*)psrc + width * height; uint8_t* pdst_uv = (uint8_t*)pdst + width * height; for(int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { *(uint8_t*)(pdst_y + i * width + j) = *(uint8_t*)(psrc_y + i * width + j); } } for(int i = 0; i < height / 2; i++) { for (int j = 0; j < width / 2; j++) { *(uint8_t*)(pdst_uv + i * width + j * 2 + 1) = *(uint8_t*)(psrc_uv + i * width / 2 + j); *(uint8_t*)(pdst_uv + i * width + j * 2) = *(uint8_t*)(psrc_uv + (width / 2) * (height / 2) + i * width / 2 + j); } } } static void createMap(int s_w,int s_h, int d_w, int d_h,int* mMap_w,int* mMap_h) { int i,j; int w_index_cur = -1; int w_index_new; int h_index_cur = -1; int h_index_new; memset((void *)mMap_w,0,d_w*sizeof(int)); memset((void *)mMap_h,0,d_h*sizeof(int)); i = 0; j = 0; while (i < s_w && j < d_w) { w_index_new = i*d_w/s_w; if ( w_index_new != w_index_cur) { mMap_w[j]= i; j++; w_index_cur = w_index_new; } i++; } j = 0; i = 0; while (i < s_h && j < d_h) { h_index_new = i*d_h/s_h; if ( h_index_new != h_index_cur) { mMap_h[j]= i; j++; h_index_cur = h_index_new; } i++; } } static bool yuv420spDownScale(void* psrc, void* pdst, int src_w, int src_h, int dst_w, int dst_h) { char * psrc_y = (char *)psrc; char * pdst_y = (char *)pdst; char * psrc_uv = (char *)psrc + src_w * src_h; char * pdst_uv = (char *)pdst + dst_w * dst_h; int scale = 1; int scale_w = src_w / dst_w; int scale_h = src_h / dst_h; int h, w; if (dst_w > src_w || dst_h > src_h) { LOGE("error size, %dx%d -> %dx%d\n", src_w, src_h, dst_w, dst_h); return false; } if (scale_w == scale_h) { scale = scale_w; } LOGV("scale = %d\n", scale); if (scale == 1) { if ((src_w == dst_w) && (src_h == dst_h)) { memcpy((char*)pdst, (char*)psrc, dst_w * dst_h * 3/2); } else { // crop for (h = 0; h < dst_h; h++) { memcpy((char*)pdst + h * dst_w, (char*)psrc + h * src_w, dst_w); } for (h = 0; h < dst_h / 2; h++) { memcpy((char*)pdst_uv + h * dst_w, (char*)psrc_uv + h * src_w, dst_w); } } return true; } for (h = 0; h < dst_h; h++) { for (w = 0; w < dst_w; w++) { *(pdst_y + h * dst_w + w) = *(psrc_y + h * scale * src_w + w * scale); } } for (h = 0; h < dst_h / 2; h++) { for (w = 0; w < dst_w; w+=2) { *((short*)(pdst_uv + h * dst_w + w)) = *((short*)(psrc_uv + h * scale * src_w + w * scale)); } } return true; } static bool yuv420spDown_noneScale(void* psrc, void* pdst, int src_w, int src_h, int dst_w, int dst_h) { char * psrc_y = (char *)psrc; char * pdst_y = (char *)pdst; char * psrc_uv = (char *)psrc + src_w * src_h; char * pdst_uv = (char *)pdst + dst_w * dst_h; int y_h_index[dst_h]; int y_w_index[dst_w]; int uv_h_index[dst_h/2]; int uv_w_index[dst_w]; int h, w; if (dst_w > src_w || dst_h > src_h) { LOGE("error size, %dx%d -> %dx%d\n", src_w, src_h, dst_w, dst_h); return false; } //y createMap(src_w,src_h,dst_w,dst_h,y_w_index,y_h_index); for (h = 0; h < dst_h; h++) { for (w = 0; w < dst_w; w++) { *(pdst_y + h * dst_w + w) = *(psrc_y +y_h_index[h]* src_w + y_w_index[w]); } } //uv createMap(src_w/2,src_h/2,dst_w/2,dst_h/2,uv_w_index,uv_h_index); for (h = 0; h < dst_h / 2; h++) { for (w = 0; w < dst_w; w+=2) { *((short*)(pdst_uv + h * dst_w + w)) = *((short*)(psrc_uv +uv_h_index[h]* src_w + uv_w_index[w/2]*2)); } } return true; } static bool yuv420pDownScale_align(void* psrc, void* pdst, int src_w, int src_h, int dst_w, int dst_h,int yStride,int uvStride) { char * psrc_y = (char *)psrc; char * pdst_y = (char *)pdst; char * psrc_uv = (char *)psrc + src_w * src_h; char * pdst_uv = (char *)pdst + dst_w * dst_h; memset(pdst_uv,128,uvStride*dst_h/2); int scale_w = src_w / dst_w; int scale_h = src_h / dst_h; int h, w; if (dst_w > src_w || dst_h > src_h) { LOGE("error size, %dx%d -> %dx%d\n", src_w, src_h, dst_w, dst_h); return false; } LOGD("src_w :%d,src_h :%d,dst_w: %d, dst_h :%d,yStride :%d,uvStride:%d,scale_w: %d,scale_h %d", src_w, src_h, dst_w, dst_h, yStride,uvStride,scale_w,scale_h); //y int y_h_index[dst_h]; int y_w_index[dst_w]; createMap(src_w,src_h,dst_w,dst_h,y_w_index,y_h_index); for (h = 0; h < dst_h; h++) { for (w = 0; w < dst_w; w++) { *(pdst_y + h *yStride + w) = *(psrc_y + y_h_index[h]* src_w + y_w_index[w]); } } int uv_h_index[dst_h/2]; int uv_w_index[dst_w/2]; createMap(src_w/2,src_h/2,dst_w/2,dst_h/2,uv_w_index,uv_h_index); //V for (h = 0; h < dst_h/2 ; h++) { for (w = 0; w < dst_w/2; w++) { *(pdst_uv + h * uvStride+ w) = *(psrc_uv + uv_h_index[h]* src_w/2 + uv_w_index[w]); } } //u for (h = 0; h < dst_h/2 ; h++ ) { for (w = 0; w < dst_w/2; w++) { *(pdst_uv + (h+dst_h/2)* uvStride+ w) = *(psrc_uv + src_w * src_h/4 + uv_h_index[h]* src_w/2 + uv_w_index[w]); } } return true; } CallbackNotifier::CallbackNotifier() : mNotifyCB(NULL), mDataCB(NULL), mDataCBTimestamp(NULL), mGetMemoryCB(NULL), mCallbackCookie(NULL), mMessageEnabler(0), mVideoRecEnabled(false), mSavePictureCnt(0), mSavePictureMax(0), mJpegQuality(90), mJpegRotate(0), mPictureWidth(640), mPictureHeight(480), mThumbWidth(0), mThumbHeight(0), mGpsLatitude(0.0), mGpsLongitude(0.0), mGpsAltitude(0.0), mGpsTimestamp(0), mFocalLength(0.0), mWhiteBalance(0), mFd(0), mCBWidth(0), mCBHeight(0), mBufferList(NULL), mSaveThreadExited(false), mIsSinglePicture(true), mContinuousFdIndex(0), mISOSpeed(0), mMeteringMode(0), mFlashUsed(0), mExposureMode(0) { LOGV("CallbackNotifier construct"); memset(mContinuousFd,0,sizeof(mContinuousFd)); memset(mGpsMethod, 0, sizeof(mGpsMethod)); memset(mCallingProcessName, 0, sizeof(mCallingProcessName)); strcpy(mExifMake, "MID MAKE"); // default strcpy(mExifModel, "MID MODEL"); // default memset(mDateTime, 0, sizeof(mDateTime)); strcpy(mDateTime, "2012:10:24 17:30:00"); memset(mFolderPath, 0, sizeof(mFolderPath)); memset(mSnapPath, 0, sizeof(mSnapPath)); } CallbackNotifier::~CallbackNotifier() { LOGV("CallbackNotifier disconstruct"); } /**************************************************************************** * Camera API ***************************************************************************/ void CallbackNotifier::setCallbacks(camera_notify_callback notify_cb, camera_data_callback data_cb, camera_data_timestamp_callback data_cb_timestamp, camera_request_memory get_memory, void* user) { LOGV("%s: %p, %p, %p, %p (%p)", __FUNCTION__, notify_cb, data_cb, data_cb_timestamp, get_memory, user); Mutex::Autolock locker(&mObjectLock); mNotifyCB = notify_cb; mDataCB = data_cb; mDataCBTimestamp = data_cb_timestamp; mGetMemoryCB = get_memory; mCallbackCookie = user; mBufferList = new BufferListManager(); if (mBufferList == NULL) { LOGE("create BufferListManager failed"); } mSaveThreadExited = false; // init picture thread mSavePictureThread = new DoSavePictureThread(this); pthread_mutex_init(&mSavePictureMutex, NULL); pthread_cond_init(&mSavePictureCond, NULL); mSavePictureThread->startThread(); pthread_mutex_init(&mPictureFdMutex, NULL); pthread_cond_init(&mPictureFdCond, NULL); } void CallbackNotifier::enableMessage(uint msg_type) { LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type); PrintMessages(msg_type); Mutex::Autolock locker(&mObjectLock); mMessageEnabler |= msg_type; LOGV("**** Currently enabled messages:"); PrintMessages(mMessageEnabler); } void CallbackNotifier::disableMessage(uint msg_type) { LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type); PrintMessages(msg_type); Mutex::Autolock locker(&mObjectLock); mMessageEnabler &= ~msg_type; LOGV("**** Currently enabled messages:"); PrintMessages(mMessageEnabler); } void CallbackNotifier::enableSmartMessage(uint msg_type) { LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type); PrintMessages(msg_type); Mutex::Autolock locker(&mObjectLock); mSmartMessageEnabler |= msg_type; LOGV("**** Currently enabled smart detection messages:"); PrintMessages(mSmartMessageEnabler); } void CallbackNotifier::disableSmartMessage(uint msg_type) { LOGV("%s: msg_type = 0x%x", __FUNCTION__, msg_type); PrintMessages(msg_type); Mutex::Autolock locker(&mObjectLock); mSmartMessageEnabler &= ~msg_type; LOGV("**** Currently disabled smart detection messages:"); PrintMessages(mSmartMessageEnabler); } status_t CallbackNotifier::enableVideoRecording() { F_LOG; for(int index = 0;index data = 0x%x !",index,mCam_buff[index]->data); } mVideoRecEnabled = true; return NO_ERROR; } void CallbackNotifier::disableVideoRecording() { F_LOG; if(mVideoRecEnabled == true) { mVideoRecEnabled = false; for(int index = 0;index release(mCam_buff[index]); LOGV("mCam_buff[%d]->data = 0x%x !",index,mCam_buff[index]->data); } } } status_t CallbackNotifier::storeMetaDataInBuffers(bool enable) { /* Return INVALID_OPERATION means HAL does not support metadata. So HAL will * return actual frame data with CAMERA_MSG_VIDEO_FRAME. Return * INVALID_OPERATION to mean metadata is not supported. */ return UNKNOWN_ERROR; } /**************************************************************************** * Public API ***************************************************************************/ void CallbackNotifier::cleanupCBNotifier() { if (mSavePictureThread != NULL) { mSavePictureThread->stopThread(); pthread_cond_signal(&mSavePictureCond); pthread_cond_signal(&mPictureFdCond); pthread_mutex_lock(&mSavePictureMutex); if (!mSaveThreadExited) { pthread_cond_wait(&mSavePictureCond, &mSavePictureMutex); } pthread_mutex_unlock(&mSavePictureMutex); mSavePictureThread.clear(); mSavePictureThread = 0; pthread_mutex_destroy(&mSavePictureMutex); pthread_cond_destroy(&mSavePictureCond); } pthread_mutex_destroy(&mPictureFdMutex); pthread_cond_destroy(&mPictureFdCond); Mutex::Autolock locker(&mObjectLock); mMessageEnabler = 0; mNotifyCB = NULL; mDataCB = NULL; mDataCBTimestamp = NULL; mGetMemoryCB = NULL; mCallbackCookie = NULL; mVideoRecEnabled = false; mJpegQuality = 90; mJpegRotate = 0; mPictureWidth = 640; mPictureHeight = 480; mThumbWidth = 0; mThumbHeight = 0; mGpsLatitude = 0.0; mGpsLongitude = 0.0; mGpsAltitude = 0.0; mGpsTimestamp = 0; mFocalLength = 0.0; mWhiteBalance = 0; if (mBufferList != NULL) { delete mBufferList; mBufferList = NULL; } } void CallbackNotifier::onNextFrameAvailable(buffer_handle_t* handlebuffer, const void* frame,int index) { if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME)) { onNextFrameHW(handlebuffer,frame,index); } if (isMessageEnabled(CAMERA_MSG_PREVIEW_FRAME)) { onNextFrameSW(frame); } } bool CallbackNotifier::takePicture(const void* frame, void *memOpsS,bool is_continuous) { F_LOG; buffer_node * pNode = NULL; V4L2BUF_t * pbuf = (V4L2BUF_t *)frame; void * pOutBuf = NULL; int bufSize = 0; int src_format = 0; unsigned long src_addr_phy = 0; unsigned long src_addr_vir = 0; int src_width = 0; int src_height = 0; RECT_t src_crop; DBG_TIME_BEGIN("CallbackNotifier taking picture", 0); if ((pbuf->isThumbAvailable == 1) && (pbuf->thumbUsedForPhoto == 1)) { src_format = pbuf->thumbFormat; src_addr_phy = pbuf->thumbAddrPhyY; src_addr_vir = pbuf->thumbAddrVirY; src_width = pbuf->thumbWidth; src_height = pbuf->thumbHeight; memcpy((void*)&src_crop, (void*)&pbuf->thumb_crop_rect, sizeof(RECT_t)); } else { src_format = pbuf->format; src_addr_phy = pbuf->addrPhyY; src_addr_vir = pbuf->addrVirY; src_width = pbuf->width; src_height = pbuf->height; memcpy((void*)&src_crop, (void*)&pbuf->crop_rect, sizeof(RECT_t)); } JPEG_ENC_t jpeg_enc; memset(&jpeg_enc, 0, sizeof(jpeg_enc)); jpeg_enc.addrY = src_addr_phy; jpeg_enc.addrC = src_addr_phy + ALIGN_16B(src_width) * src_height; jpeg_enc.src_w = src_width; jpeg_enc.src_h = src_height; jpeg_enc.pic_w = mPictureWidth; jpeg_enc.pic_h = mPictureHeight; jpeg_enc.colorFormat = (src_format == V4L2_PIX_FMT_NV21) ? JPEG_COLOR_YUV420_NV21 : JPEG_COLOR_YUV420_NV12; jpeg_enc.quality = mJpegQuality; jpeg_enc.rotate = mJpegRotate; getCurrentDateTime(); strcpy(jpeg_enc.CameraMake, mExifMake); strcpy(jpeg_enc.CameraModel, mExifModel); strcpy(jpeg_enc.DateTime, mDateTime); jpeg_enc.thumbWidth = mThumbWidth; jpeg_enc.thumbHeight = mThumbHeight; jpeg_enc.whitebalance = mWhiteBalance; jpeg_enc.focal_length = mFocalLength; if (0 != strlen(mGpsMethod)) { jpeg_enc.enable_gps = 1; jpeg_enc.gps_latitude = mGpsLatitude; jpeg_enc.gps_longitude = mGpsLongitude; jpeg_enc.gps_altitude = mGpsAltitude; jpeg_enc.gps_timestamp = mGpsTimestamp; strcpy(jpeg_enc.gps_processing_method, mGpsMethod); //memset(mGpsMethod, 0, sizeof(mGpsMethod)); } else { jpeg_enc.enable_gps = 0; } if ((src_crop.width != jpeg_enc.src_w) || (src_crop.height != jpeg_enc.src_h)) { jpeg_enc.enable_crop = 1; jpeg_enc.crop_x = src_crop.left; jpeg_enc.crop_y = src_crop.top; jpeg_enc.crop_w = src_crop.width; jpeg_enc.crop_h = src_crop.height; } else { jpeg_enc.enable_crop = 0; } LOGD("addrY: %x, src: %dx%d, pic: %dx%d, quality: %d, rotate: %d, Gps method: %s,\ thumbW: %d, thumbH: %d, thubmFactor: %d, crop: [%d, %d, %d, %d]", jpeg_enc.addrY, jpeg_enc.src_w, jpeg_enc.src_h, jpeg_enc.pic_w, jpeg_enc.pic_h, jpeg_enc.quality, jpeg_enc.rotate, jpeg_enc.gps_processing_method, jpeg_enc.thumbWidth, jpeg_enc.thumbHeight, jpeg_enc.scale_factor, jpeg_enc.crop_x, jpeg_enc.crop_y, jpeg_enc.crop_w, jpeg_enc.crop_h); pNode = mBufferList->allocBuffer(-1, mPictureWidth * mPictureHeight); if (pNode == NULL) { LOGE("malloc picture node failed"); return false; } pOutBuf = pNode->data; if (pOutBuf == NULL) { LOGE("malloc picture memory failed"); return false; } JpegEncInfo sjpegInfo; EXIFInfo exifInfo; memset(&sjpegInfo, 0, sizeof(JpegEncInfo)); memset(&exifInfo, 0, sizeof(EXIFInfo)); sjpegInfo.sBaseInfo.nStride = src_width; sjpegInfo.sBaseInfo.nInputWidth = src_width; sjpegInfo.sBaseInfo.nInputHeight = src_height; sjpegInfo.sBaseInfo.nDstWidth = mPictureWidth; sjpegInfo.sBaseInfo.nDstHeight = mPictureHeight; sjpegInfo.sBaseInfo.memops = (ScMemOpsS*)memOpsS; sjpegInfo.pAddrPhyY = (unsigned char*)src_addr_phy; sjpegInfo.pAddrPhyC = (unsigned char*)src_addr_phy + ALIGN_16B(src_width) * src_height; sjpegInfo.sBaseInfo.eInputFormat = (src_format == V4L2_PIX_FMT_NV21) ? VENC_PIXEL_YVU420SP: VENC_PIXEL_YUV420SP; sjpegInfo.quality = mJpegQuality; exifInfo.Orientation = mJpegRotate; sjpegInfo.nShareBufFd = pbuf->nShareBufFd; if ((src_crop.width != sjpegInfo.sBaseInfo.nInputWidth) || (src_crop.height != sjpegInfo.sBaseInfo.nInputHeight)) { sjpegInfo.bEnableCorp = 1; sjpegInfo.sCropInfo.nLeft = src_crop.left; sjpegInfo.sCropInfo.nTop = src_crop.top; sjpegInfo.sCropInfo.nWidth = src_crop.width; sjpegInfo.sCropInfo.nHeight = src_crop.height; } else { sjpegInfo.bEnableCorp = 0; } exifInfo.ThumbWidth = mThumbWidth; exifInfo.ThumbHeight = mThumbHeight; LOGD("addrY: %x, src: %dx%d, pic: %dx%d, quality: %d, rotate: %d,\ thumbW: %d, thumbH: %d,EnableCorp: %d,crop: [%d, %d, %d, %d],share_fd:%d", sjpegInfo.pAddrPhyY, sjpegInfo.sBaseInfo.nInputWidth, sjpegInfo.sBaseInfo.nInputHeight, sjpegInfo.sBaseInfo.nDstWidth, sjpegInfo.sBaseInfo.nDstHeight, sjpegInfo.quality, exifInfo.Orientation, exifInfo.ThumbWidth, exifInfo.ThumbHeight, sjpegInfo.bEnableCorp, sjpegInfo.sCropInfo.nLeft, sjpegInfo.sCropInfo.nTop, sjpegInfo.sCropInfo.nWidth, sjpegInfo.sCropInfo.nHeight,sjpegInfo.nShareBufFd); strcpy((char*)exifInfo.CameraMake, mExifMake); strcpy((char*)exifInfo.CameraModel, mExifModel); strcpy((char*)exifInfo.DateTime, mDateTime); LOGD("mGpsMethod:%s,mGpsLatitude:%lf,mGpsLongitude:%lf,mGpsAltitude:%lf,mGpsTimestamp:%ld", \ mGpsMethod, mGpsLatitude, mGpsLongitude, mGpsAltitude, mGpsTimestamp); if (0 != strlen(mGpsMethod)){ strcpy((char*)exifInfo.gpsProcessingMethod,mGpsMethod); exifInfo.enableGpsInfo = 1; exifInfo.gps_latitude = mGpsLatitude; exifInfo.gps_longitude = mGpsLongitude; exifInfo.gps_altitude = mGpsAltitude; exifInfo.gps_timestamp = mGpsTimestamp; memset(mGpsMethod, 0, sizeof(mGpsMethod)); } else exifInfo.enableGpsInfo = 0; exifInfo.ExposureTime.num = mExposureTime.num; exifInfo.ExposureTime.den = mExposureTime.den; exifInfo.FNumber.num = mFNumber.num; exifInfo.FNumber.den = mFNumber.den; exifInfo.ISOSpeed = mISOSpeed; exifInfo.ExposureBiasValue.num= mExposureBiasValue.num; exifInfo.ExposureBiasValue.den= mExposureBiasValue.den; exifInfo.MeteringMode = mMeteringMode; exifInfo.FlashUsed = mFlashUsed;; exifInfo.FocalLength.num = mFocalLength_r.num; exifInfo.FocalLength.den = mFocalLength_r.den; exifInfo.DigitalZoomRatio.num = mDigitalZoomRatio.num; exifInfo.DigitalZoomRatio.den = mDigitalZoomRatio.den; exifInfo.WhiteBalance = mWhiteBalance; exifInfo.ExposureMode = mExposureMode; int ret = AWJpecEnc(&sjpegInfo,&exifInfo,pOutBuf,&bufSize); //int64_t lasttime = systemTime(); if (ret < 0) { LOGE("JpegEnc failed"); return false; } //LOGV("hw enc time: %lld(ms), size: %d", (systemTime() - lasttime)/1000000, bufSize); DBG_TIME_DIFF("enc"); if (is_continuous) { pNode->id = mSavePictureCnt; pNode->size = bufSize; mBufferList->push(pNode); // cb number of pictures if (isMessageEnabled(CAMERA_MSG_CONTINUOUSSNAP)) { mNotifyCB(CAMERA_MSG_CONTINUOUSSNAP, mSavePictureCnt, 0, mCallbackCookie); } pthread_cond_signal(&mSavePictureCond); mSavePictureCnt++; } else { if ((strlen(mSnapPath) > 0)) { camera_memory_t* cb_buff; strcpy(pNode->priv, mSnapPath); pNode->id = -1; pNode->size = bufSize; mBufferList->push(pNode); mNotifyCB(CAMERA_MSG_SNAP, 0, 0, mCallbackCookie); pthread_cond_signal(&mSavePictureCond); } else { camera_memory_t* jpeg_buff = mGetMemoryCB(-1, bufSize, 1, mCallbackCookie); if (NULL != jpeg_buff && NULL != jpeg_buff->data) { memcpy(jpeg_buff->data, (uint8_t *)pOutBuf, bufSize); mDataCB(CAMERA_MSG_COMPRESSED_IMAGE, jpeg_buff, 0, NULL, mCallbackCookie); jpeg_buff->release(jpeg_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_COMPRESSED_IMAGE", __FUNCTION__); } mBufferList->releaseBuffer(pNode); } } DBG_TIME_DIFF("photo end"); LOGV("taking photo end"); return true; } void CallbackNotifier::onNextFrameHW(buffer_handle_t* handlebuffer,const void* frame,int index) { F_LOG; VideoNativeHandleMetadata mVideoNativeMetadata; V4L2BUF_t * pbuf = (V4L2BUF_t*)frame; mVideoNativeMetadata.eType = kMetadataBufferTypeNativeHandleSource; mVideoNativeMetadata.pHandle = (native_handle_t *)(*handlebuffer); if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled()) { if (NULL != mCam_buff[index] && NULL != mCam_buff[index]->data) { pbuf->refMutex.lock(); pbuf->refCnt++; pbuf->refMutex.unlock(); LOGV("index = %d ,mCam_buff[index]->data = 0x%x,pbuf->refCnt = %d",index,mCam_buff[index]->data,pbuf->refCnt); memcpy(mCam_buff[index]->data, &mVideoNativeMetadata, sizeof(VideoNativeHandleMetadata)); LOGV("CallbackNotifier::onNextFrameHW index = %d,mVideoNativeMetadata.pHandle = 0x%x,mCam_buff[%d]->data = 0x%x", index, mVideoNativeMetadata.pHandle, index, mCam_buff[index]->data); mDataCBTimestamp(pbuf->timeStamp, CAMERA_MSG_VIDEO_FRAME, mCam_buff[index], 0, mCallbackCookie); } else { LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__); } } F_LOG; } void CallbackNotifier::onNextFrameSW(const void* frame) { V4L2BUF_t * pbuf = (V4L2BUF_t*)frame; int framesize =0; int src_format = 0; unsigned long src_addr_phy = 0; unsigned long src_addr_vir = 0; int src_width = 0; int src_height = 0; RECT_t src_crop; if ((pbuf->isThumbAvailable == 1) && (pbuf->thumbUsedForPreview == 1)) { src_format = pbuf->thumbFormat; src_addr_phy = pbuf->thumbAddrPhyY; src_addr_vir = pbuf->thumbAddrVirY; src_width = pbuf->thumbWidth; src_height = pbuf->thumbHeight; memcpy((void*)&src_crop, (void*)&pbuf->thumb_crop_rect, sizeof(RECT_t)); } else { src_format = pbuf->format; src_addr_phy = pbuf->addrPhyY; src_addr_vir = pbuf->addrVirY; src_width = pbuf->width; src_height = pbuf->height; memcpy((void*)&src_crop, (void*)&pbuf->crop_rect, sizeof(RECT_t)); } framesize = ALIGN_16B(src_width) * src_height * 3/2; if (isMessageEnabled(CAMERA_MSG_VIDEO_FRAME) && isVideoRecordingEnabled()) { camera_memory_t* cam_buff = mGetMemoryCB(-1, framesize, 1, mCallbackCookie); if (NULL != cam_buff && NULL != cam_buff->data) { memcpy(cam_buff->data, (void *)src_addr_vir, framesize); mDataCBTimestamp(pbuf->timeStamp, CAMERA_MSG_VIDEO_FRAME, cam_buff, 0, mCallbackCookie); cam_buff->release(cam_buff); // star add } else { LOGE("%s: Memory failure in CAMERA_MSG_VIDEO_FRAME", __FUNCTION__); } } if (isMessageEnabled(CAMERA_MSG_PREVIEW_FRAME)) { bool isYV12 = false; if (src_format == V4L2_PIX_FMT_YUV420 ) { LOGV("src format is YUV420"); isYV12 = true; } if (src_format == V4L2_PIX_FMT_YVU420) { LOGV("src format is YVU420"); isYV12 = true; } if (strcmp(mCallingProcessName, "com.android.facelock") == 0) { camera_memory_t* cam_buff = mGetMemoryCB(-1, 160 * 120 * 3 / 2, 1, mCallbackCookie); if (NULL != cam_buff && NULL != cam_buff->data) { yuv420spDownScale((void*)src_addr_vir, cam_buff->data, ALIGN_16B(src_width), src_height, 160, 120); mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCallbackCookie); cam_buff->release(cam_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__); } } else if ((mCBWidth % 32 != 0) && isYV12) { // add for cts verify camera formats 176x144 YV12 int w = mCBWidth; int h = mCBHeight; int yStride = ALIGN_16B(w); int uvStride = ALIGN_16B(w >> 1); int ySize = yStride * h; int uvSize = uvStride * h / 2; int reqBufSize = ySize+ uvSize*2; LOGV("ystride : %d, uvstride : %d, size : %d ",yStride,uvStride,reqBufSize); camera_memory_t* cam_buff = mGetMemoryCB(-1, reqBufSize, 1, mCallbackCookie); if (NULL != cam_buff && NULL != cam_buff->data) { yuv420pDownScale_align((void*)src_addr_vir,cam_buff->data, ALIGN_16B(src_width), src_height,w,h,yStride,uvStride); mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCallbackCookie); cam_buff->release(cam_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__); } } else { camera_memory_t* cam_buff = mGetMemoryCB(-1, mCBWidth * mCBHeight * 3 / 2, 1, mCallbackCookie); if (NULL != cam_buff && NULL != cam_buff->data) { if ( src_width % mCBWidth == 0 && src_height % mCBHeight == 0) yuv420spDownScale((void*)src_addr_vir, cam_buff->data, ALIGN_16B(src_width), src_height, mCBWidth, mCBHeight); else yuv420spDown_noneScale((void*)src_addr_vir, cam_buff->data, ALIGN_16B(src_width), src_height, mCBWidth, mCBHeight); if (src_format == V4L2_PIX_FMT_NV12) { // NV12 <--> NV21 /*formatToNV21(cam_buff->data, cam_buff->data, mCBWidth, mCBHeight, ALIGN_16B(mCBWidth), 0, 2, ALIGN_16B(mCBWidth) * mCBHeight * 3/2, src_format);*/ } mDataCB(CAMERA_MSG_PREVIEW_FRAME, cam_buff, 0, NULL, mCallbackCookie); cam_buff->release(cam_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__); } } } } status_t CallbackNotifier::autoFocusMsg(bool success) { if (isMessageEnabled(CAMERA_MSG_FOCUS)) { mNotifyCB(CAMERA_MSG_FOCUS, success, 0, mCallbackCookie); } return NO_ERROR; } status_t CallbackNotifier::autoFocusContinuousMsg(bool success) { if (isMessageEnabled(CAMERA_MSG_FOCUS_MOVE)) { // in continuous focus mode // true for starting focus, false for focus ok mNotifyCB(CAMERA_MSG_FOCUS_MOVE, success, 0, mCallbackCookie); } return NO_ERROR; } status_t CallbackNotifier::faceDetectionMsg(camera_frame_metadata_t *face) { if (isMessageEnabled(CAMERA_MSG_PREVIEW_METADATA)) { camera_memory_t *cam_buff = mGetMemoryCB(-1, 1, 1, mCallbackCookie); mDataCB(CAMERA_MSG_PREVIEW_METADATA, cam_buff, 0, face, mCallbackCookie); cam_buff->release(cam_buff); } return NO_ERROR; } status_t CallbackNotifier::smartDetectionMsg(int32_t type) { if (isSmartMessageEnabled(CAMERA_SMART_MSG_STATUS)) { mNotifyCB(CAMERA_SMART_MSG_STATUS, type, 0, mCallbackCookie); } return NO_ERROR; } void CallbackNotifier::notifyPictureMsg(const void* frame) { F_LOG; V4L2BUF_t * pbuf = (V4L2BUF_t*)frame; int framesize = pbuf->width * pbuf->height * 3/2; // shutter msg if (isMessageEnabled(CAMERA_MSG_SHUTTER)) { F_LOG; mNotifyCB(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie); } // raw image msg if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE)) { camera_memory_t *dummyRaw = mGetMemoryCB(-1, 1, 1, mCallbackCookie); if ( NULL == dummyRaw ) { LOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__); return; } mDataCB(CAMERA_MSG_RAW_IMAGE, dummyRaw, 0, NULL, mCallbackCookie); dummyRaw->release(dummyRaw); } else if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE_NOTIFY)) { mNotifyCB(CAMERA_MSG_RAW_IMAGE_NOTIFY, 0, 0, mCallbackCookie); } // postview msg if (0 && isMessageEnabled(CAMERA_MSG_POSTVIEW_FRAME) ) { F_LOG; camera_memory_t* cam_buff = mGetMemoryCB(-1, framesize, 1, mCallbackCookie); if (NULL != cam_buff && NULL != cam_buff->data) { memset(cam_buff->data, 0xff, framesize); mDataCB(CAMERA_MSG_POSTVIEW_FRAME, cam_buff, 0, NULL, mCallbackCookie); cam_buff->release(cam_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_PREVIEW_FRAME", __FUNCTION__); return; } } } void CallbackNotifier::startContinuousPicture() { F_LOG; // mSavePictureCnt = 0; } void CallbackNotifier::stopContinuousPicture() { // do nothing } void CallbackNotifier::setContinuousPictureCnt(int cnt) { mSavePictureMax = cnt; } void CallbackNotifier::setFd(int fd) { if (mIsSinglePicture) { pthread_mutex_lock(&mPictureFdMutex); mFd = fd; pthread_cond_signal(&mPictureFdCond); pthread_mutex_unlock(&mPictureFdMutex); } else { pthread_mutex_lock(&mPictureFdMutex); mContinuousFd[(mContinuousFdIndex++)%10] = fd; pthread_cond_signal(&mPictureFdCond); pthread_mutex_unlock(&mPictureFdMutex); } } bool CallbackNotifier::savePictureThread() { int wait_cnt = 5; int wait_time = 3; // 3s * 5 = 15s if (mIsSinglePicture) { pthread_mutex_lock(&mSavePictureMutex); if (mSavePictureThread->getThreadStatus() == THREAD_STATE_EXIT) { mSaveThreadExited = true; pthread_mutex_unlock(&mSavePictureMutex); pthread_cond_signal(&mSavePictureCond); LOGD("savePictureThread exit, line: %d", __LINE__); return false; } if (mBufferList->isListEmpty()) { LOGV("wait for picture to save"); pthread_cond_wait(&mSavePictureCond, &mSavePictureMutex); pthread_mutex_unlock(&mSavePictureMutex); return true; } pthread_mutex_unlock(&mSavePictureMutex); } else { if (mBufferList->isListEmpty()) { pthread_mutex_lock(&mSavePictureMutex); if (mSavePictureThread->getThreadStatus() == THREAD_STATE_EXIT) { mSaveThreadExited = true; pthread_mutex_unlock(&mSavePictureMutex); pthread_cond_signal(&mSavePictureCond); LOGD("savePictureThread exit, line: %d", __LINE__); return false; } LOGV("wait for picture to save"); pthread_cond_wait(&mSavePictureCond, &mSavePictureMutex); pthread_mutex_unlock(&mSavePictureMutex); return true; } } ALOGV("%d items left in the picture list.", mBufferList->getItemCnt()); DBG_TIME_BEGIN("save picture", 0); char fname[128]; FILE *pf = NULL; buffer_node * pNode = mBufferList->pop(); if (pNode == NULL) { LOGE("list head is null"); goto SAVE_PICTURE_END; } if (mIsSinglePicture) { // callback fd camera_memory_t* cb_buff; if (pNode->id >= 0) { sprintf(pNode->priv, "%s%03d.jpg", mFolderPath, pNode->id); } cb_buff = mGetMemoryCB(-1, strlen(pNode->priv), 1, mCallbackCookie); if (NULL != cb_buff && NULL != cb_buff->data) { memcpy(cb_buff->data, (uint8_t *)pNode->priv, strlen(pNode->priv)); mDataCB(CAMERA_MSG_SNAP_FD, cb_buff, 0, NULL, mCallbackCookie); cb_buff->release(cb_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_SNAP_FD", __FUNCTION__); goto SAVE_PICTURE_END; } // wait fd while(wait_cnt-- >= 0) { pthread_mutex_lock(&mPictureFdMutex); if (mFd <= 0) { struct timespec timeout; timeout.tv_sec=time(0) + wait_time; // 3s timeout timeout.tv_nsec = 0; int ret = pthread_cond_timedwait(&mPictureFdCond, &mPictureFdMutex, &timeout); if (ret == ETIMEDOUT) { LOGW("wait fd timeout"); pthread_mutex_unlock(&mPictureFdMutex); pthread_mutex_lock(&mSavePictureMutex); if (mSavePictureThread->getThreadStatus() == THREAD_STATE_EXIT) { mSaveThreadExited = true; pthread_mutex_unlock(&mSavePictureMutex); pthread_cond_signal(&mSavePictureCond); LOGD("savePictureThread exit, line: %d", __LINE__); return false; } pthread_mutex_unlock(&mSavePictureMutex); continue; } } pNode->fd = mFd; mFd = 0; pthread_mutex_unlock(&mPictureFdMutex); break; } if (wait_cnt < 0 || pNode->fd <= 0) { LOGE("single picture wait fd failed"); goto SAVE_PICTURE_END; } } else { // continuous picture wait fd pthread_mutex_lock(&mPictureFdMutex); if (mContinuousFd[pNode->id] <= 0) { struct timespec timeout; timeout.tv_sec=time(0) + 3; // 3s timeout timeout.tv_nsec = 0; int ret = pthread_cond_timedwait(&mPictureFdCond, &mPictureFdMutex, &timeout); if (ret == ETIMEDOUT) { LOGW("wait fd timeout"); pthread_mutex_unlock(&mPictureFdMutex); goto SAVE_PICTURE_END; } } pNode->fd = mContinuousFd[pNode->id]; mContinuousFd[pNode->id] = 0; pthread_mutex_unlock(&mPictureFdMutex); if (pNode->fd <= 0) { LOGD("savePictureThread exit, line: %d", __LINE__); goto SAVE_PICTURE_END; } } // write if (pNode->id >= 0) { if(pNode->fd > 0) { int err = ::write(pNode->fd, (uint8_t *)pNode->data, pNode->size); if(err == -1) { LOGE("write failed: %s", strerror(errno)); ::close(pNode->fd); goto SAVE_PICTURE_END; } ::close(pNode->fd); if (isMessageEnabled(CAMERA_MSG_CONTINUOUSSNAP)) { mNotifyCB(CAMERA_MSG_CONTINUOUSSNAP, (pNode->id + 1000), 0, mCallbackCookie); } } else { sprintf(fname, "%s%03d.jpg", mFolderPath, pNode->id); pf = fopen(fname, "wb+"); if (pf != NULL) { LOGV("open %s ok", fname); fwrite((uint8_t *)pNode->data, pNode->size, 1, pf); fflush(pf); fclose(pf); } else { LOGE("open %s failed, %s", fname, strerror(errno)); goto SAVE_PICTURE_END; } } } else { if(pNode->fd > 0) { int err = ::write(pNode->fd, (uint8_t *)pNode->data, pNode->size); if(err == -1) { LOGE("write failed: %s", strerror(errno)); ::close(pNode->fd); goto SAVE_PICTURE_END; } ::close(pNode->fd); } else { strcpy(fname, pNode->priv); pf = fopen(fname, "wb+"); if (pf != NULL) { LOGV("open %s ok", fname); fwrite((uint8_t *)pNode->data, pNode->size, 1, pf); fflush(pf); fclose(pf); } else { LOGE("open %s failed, %s", fname, strerror(errno)); goto SAVE_PICTURE_END; } } } DBG_TIME_DIFF("write file"); if (pNode->id < 0) { camera_memory_t* cb_buff; cb_buff = mGetMemoryCB(-1, strlen(pNode->priv), 1, mCallbackCookie); if (NULL != cb_buff && NULL != cb_buff->data) { memcpy(cb_buff->data, (uint8_t *)pNode->priv, strlen(pNode->priv)); mDataCB(CAMERA_MSG_SNAP_THUMB, cb_buff, 0, NULL, mCallbackCookie); cb_buff->release(cb_buff); } else { LOGE("%s: Memory failure in CAMERA_MSG_SNAP_THUMB", __FUNCTION__); } } SAVE_PICTURE_END: if (pNode != NULL) { mBufferList->releaseBuffer(pNode); } return true; } void CallbackNotifier::getCurrentDateTime() { time_t t; struct tm *tm_t; time(&t); tm_t = localtime(&t); sprintf(mDateTime, "%4d:%02d:%02d %02d:%02d:%02d", tm_t->tm_year+1900, tm_t->tm_mon+1, tm_t->tm_mday, tm_t->tm_hour, tm_t->tm_min, tm_t->tm_sec); } void CallbackNotifier::onCameraDeviceError(int err) { if (isMessageEnabled(CAMERA_MSG_ERROR) && mNotifyCB != NULL) { mNotifyCB(CAMERA_MSG_ERROR, err, 0, mCallbackCookie); } } void CallbackNotifier::setExifInfo(struct isp_exif_attribute exifinfo,int zoom_ratio,int exposure_bias) { mExposureTime.num = exifinfo.exposure_time.numerator; mExposureTime.den = exifinfo.exposure_time.denominator; mFNumber.num = exifinfo.fnumber; //eg:FNum=2.2, aperture = 220, --> num = 220,den = 100 mFNumber.den = 100; mISOSpeed = exifinfo.iso_speed; mExposureBiasValue.num = exposure_bias; mExposureBiasValue.den = 1; mMeteringMode = 1; mFlashUsed = exifinfo.flash_fire; mFocalLength_r.num = exifinfo.focal_length; mFocalLength_r.den = 100; mDigitalZoomRatio.num = zoom_ratio; mDigitalZoomRatio.den = 100; mExposureMode = 0; LOGD("exif_attri fnumber: %d",mFNumber.num); LOGD("exif_attri exposure_time: %d %d",mExposureTime.num,mExposureTime.den); LOGD("exif_attri iso_speed: %d",mISOSpeed); LOGD("exif_attri focal_length: %d",mFocalLength_r.num); LOGD("exif_attri flash_fire: %d",mFlashUsed); LOGD("exif_attri mDigitalZoomRatio: %d",mDigitalZoomRatio); LOGD("exif_attri exposure_bias: %d",mExposureBiasValue.num); } }; /* namespace android */