allwinner_a64/android/hardware/aw/camera/CallbackNotifier.cpp
2018-08-08 17:00:29 +08:00

1543 lines
49 KiB
C++
Executable file

#include "CameraDebug.h"
#if DBG_CALLBACK
#define LOG_NDEBUG 0
#endif
#define LOG_TAG "CallbackNotifier"
#include <cutils/log.h>
#include <cutils/properties.h>
#include <HardwareAPI.h>
#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 <NB_BUFFER; index++)
{
mCam_buff[index] = mGetMemoryCB(-1, sizeof(VideoNativeHandleMetadata), 1, mCallbackCookie);
LOGV("mCam_buff[%d]->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 <NB_BUFFER; index++)
{
mCam_buff[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 */