Dump 线程和一键删除YUV数据及图像旋转

1.2016 年末-2017年初太闲,没啥项目,一年到头就一个项目,到5/6月份实在太闲,所以瞎想有哪些修改点

2.高通 dump 用在预览线程实在是太卡,所以一直想着怎么优化,不然有时候太卡都没法重现问题

3.测试的时候经常找特定环境,不方便连接电脑 adb shell rm  /data/misc/camera/*

4.以前遇到QQ视频有的项目预览倒转的问题,想着能不能在HAL层做个旋转,终于有时间,移植网上一个代码(不过对某些size存在bug,不解)



头文件及初始化相关需要做的(包括一键删除 及加 dump 线程):

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

diff --git a/HAL/QCamera2HWI.h b/HAL/QCamera2HWI.h
index df10cc8..2fc5ca3 100644
--- a/HAL/QCamera2HWI.h
+++ b/HAL/QCamera2HWI.h
@@ -323,6 +323,13 @@ typedef struct {
     uint32_t                 frame_index;  // frame index for the buffer
 } qcamera_callback_argm_t;
 
+typedef struct {
+    QCameraStream *stream;
+    mm_camera_buf_def_t *frame;
+    uint32_t dump_type;
+    cam_dimension_t dim;
+} qcamera_dumpdata_t; // 增加一个 dump 结构体, 包括当前数据流,当前帧,数据类型,长宽
+
 class QCameraCbNotifier {
 public:
@@ -433,6 +440,9 @@ public:
                                    cam_pp_offline_src_config_t *config);
     static int prepare_preview(struct camera_device *);
     static int prepare_snapshot(struct camera_device *device);
+    static void *dumpPreviewFrameToFile_thread(void *data);           // dump 预览数据流线程
+    static void *dumpSnapshotFrameToFile_thread(void *data);          // dump 拍照数据流线程
+    static void *oneKeyDeleteFiles_thread(void *data);                // 一键删除 dump 文件线程
 
 public:
     QCamera2HardwareInterface(uint32_t cameraId);
@@ -490,7 +500,13 @@ public:
             mm_jpeg_mpo_ops_t *mpo_ops, uint32_t *pJpegClientHandle);
     uint32_t getCameraId() { return mCameraId; };
     void getParams(QCameraParameters **pParm) {*pParm = &mParameters;};
+    void dumpThreadexit(int);                                         // dump 线程退出及相关资源释放函数
+    void oneKeyDeleteFiles(void);                                     // 一键删除实现函数                                        
+    void oneKeyDeleteFilesThreadexit(void);	                       // 一键删除线程退出
+    void dfs_remove_files(int delnum);                                // 用dfs 实现一键删除
 private:
+    int streamDataCBdump(int );
+    int processDumpDataNotify(qcamera_dumpdata_t *dumpdata,int type);
     int setPreviewWindow(struct preview_stream_ops *window);
     int setCallBacks(
         camera_notify_callback notify_cb,
@@ -785,8 +801,8 @@ private:
     QCameraPostProcessor m_postprocessor; // post processor
     QCameraThermalAdapter &m_thermalAdapter;
     QCameraCbNotifier m_cbNotifier;
-    pthread_mutex_t m_lock;
-    pthread_cond_t m_cond;
+    pthread_mutex_t m_lock,m_previewlock,m_snapshotlock,m_zsllock,m_delLock;  // 增加锁
+    pthread_cond_t m_cond,m_previewcond,m_snapshotcond,m_zslcond,m_delcond;
     api_result_list *m_apiResultList;
     QCameraMemoryPool m_memoryPool;
 
@@ -1264,6 +1280,16 @@ private:
  //   void setHighBrightnessModeOfLCD(int on, char *prevHBM, char *prevAutoHBM);
 #endif
+    QCameraQueue     mDataQ;
+    qcamera_dumpdata_t previewdata,yuvshotdata,rawshotdata;                   //需要dump 的对象实体
+    QCameraCmdThread mProcTh,mPreviewProcTh,mSnapshotProcTh,mOnekeyDelProcTh; //线程实例
+    bool mbSnapshotThreadActive,mbPreviewThreadActive;
+
+public :
+    QCameraQueue mPreviewDataQ,mSnapshotDataQ;                               // 通过队列实现缓冲
+    bool mOneKeyThreadActive;                                                // 线程状态标记
+    int yuvnum;
+	
 };
 
 }; // namespace qcamera


锁的初始化及释放 (创建实体时初始化,析构对象时释放):

diff --git a/HAL/QCamera2HWI.cpp b/HAL/QCamera2HWI.cpp
index 10fc2ec..29f248e 100644
--- a/HAL/QCamera2HWI.cpp
+++ b/HAL/QCamera2HWI.cpp
@@ -50,6 +50,10 @@
 #include "QCamera2HWI.h"
 #include "QCameraMem.h"
 
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/types.h>
+
 #include <fcntl.h>
 #include <ctype.h>
@@ -1968,6 +1972,14 @@ QCamera2HardwareInterface::QCamera2HardwareInterface(uint32_t cameraId)
 
     pthread_mutex_init(&m_lock, NULL);
     pthread_cond_init(&m_cond, NULL);
+    pthread_cond_init(&m_delcond, NULL);
+    pthread_mutex_init(&m_delLock, NULL);
+    pthread_cond_init(&m_previewcond, NULL);
+    pthread_mutex_init(&m_previewlock, NULL);
+    pthread_cond_init(&m_snapshotcond, NULL);
+    pthread_mutex_init(&m_snapshotlock, NULL);
+    pthread_cond_init(&m_zslcond, NULL);
+    pthread_mutex_init(&m_zsllock, NULL);
 
     m_apiResultList = NULL;
 
@@ -2112,6 +2124,14 @@ QCamera2HardwareInterface::~QCamera2HardwareInterface()
     pthread_mutex_destroy(&m_parm_lock);
     pthread_mutex_destroy(&m_int_lock);
     pthread_cond_destroy(&m_int_cond);
+    pthread_mutex_destroy(&m_delLock);
+    pthread_cond_destroy(&m_delcond);
+    pthread_mutex_destroy(&m_previewlock);
+    pthread_cond_destroy(&m_previewcond);				
+    pthread_mutex_destroy(&m_snapshotlock);
+    pthread_cond_destroy(&m_snapshotcond);
+    pthread_mutex_destroy(&m_zsllock);
+    pthread_cond_destroy(&m_zslcond);
     pthread_mutex_destroy(&mGrallocLock);
     pthread_mutex_destroy(&m_tBurstSavingLock);
@@ -2199,6 +2219,134 @@ int QCamera2HardwareInterface::openCamera(struct hw_device_t **hw_device)
     return rc;
 }


1.一键删除实现

>> 删除实现函数

+#define _REMOVE_FILES_IN_FOLDER_  0
+#define _S_IFDIR  0040000
+void QCamera2HardwareInterface::dfs_remove_files( int delnum){
+	struct stat fileStat;
+	int filenum = 0;
+	char path[20] = "/data/misc/camera/";
+	DIR *cur_dir ;
+	struct dirent *dptr = NULL;
+	
+	if((stat(path,&fileStat) == 0) && (fileStat.st_mode & _S_IFDIR))
+		ALOGE("ssxxx path %s existence \n",path);
+	else 
+	{
+		ALOGE("ssxxx there is no such a file , return \n");
+		return ;
+	}
+	if(chdir(path) == -1){
+		ALOGE("No file found and access error\n");
+		return ;
+	}
+
+	if(!(cur_dir = opendir("."))){
+		ALOGE("ssxxx open dir return: \n");
+		return;	
+	}
+
+	while ((dptr= readdir(cur_dir)) != NULL && (filenum < delnum || delnum == _REMOVE_FILES_IN_FOLDER_))
+	{
+		stat(dptr->d_name, &fileStat);
+		ALOGE("ssxxx read dir: %s  delnum = %d \n",dptr->d_name,delnum);
+		if(strncmp(dptr->d_name,".",1 ) == 0  || strncmp(dptr->d_name,"c",1) == 0 || strncmp(dptr->d_name,"f",1) == 0 )
+			continue;
+		if(S_ISDIR(fileStat.st_mode))
+		{
+			chdir(dptr->d_name);
+			ALOGE("ssxxx go sub dir %s: \n",dptr->d_name);
+			dfs_remove_files(delnum);
+			chdir("..");
+		}
+		filenum++;
+		ALOGE("ssxxx remove file %s:  num:%d  yuvnum:%d \n",dptr->d_name,filenum,yuvnum);
+		remove(dptr->d_name);	
+	}
+	closedir(cur_dir);
+}
+

>> 收到删除命令,将当前数据删除,仅仅保留最后 10 帧(当前 dump 的帧数由HAL成员变量 [ pme->yuvnum ] 控制,防止问题突然重现数据又全删了 嘿嘿)
 

+void *QCamera2HardwareInterface::oneKeyDeleteFiles_thread(void *data)
+{
+	int ret;
+	int running = 1;
+	long filehdl;
+	int filenum = 0;
+	camera_cmd_type_t cmd ;
+	
+	QCamera2HardwareInterface  *pme = reinterpret_cast <QCamera2HardwareInterface *> (data);
+	QCameraCmdThread *cmdThread = &pme->mOnekeyDelProcTh;
+        cmdThread->setName("CAM_oneKeydelThread");
+			
+	do{
+	    char value[PROPERTY_VALUE_MAX];
+    	    property_get("persist.camera.deldump", value, "0");
+    	    uint32_t enabled = (uint32_t) atoi(value);
+			
+	    do {
+	        ALOGE("%s: ssxxx before wait cmd %d process id : %d   thread_id : %d  yuvnum = %d", __func__, cmd,getpid(),gettid(),pme->yuvnum);	
+                ret = cam_sem_wait(&cmdThread->cmd_sem);
+                if (ret != 0 && errno != EINVAL) {
+                    ALOGE("%s: ssxxx cam_sem_wait error (%s)", __func__, strerror(errno));
+                    return NULL;
+                }
+	        ALOGE("%s: ssxxx after wait cmd %d process id : %d   thread_id : %d yuvnum = %d ", __func__, cmd,getpid(),gettid(),pme->yuvnum);	
+	    } while (ret != 0);
+            cmd = cmdThread->getCmd();
+            switch (cmd) {
+	    case CAMERA_CMD_TYPE_DO_NEXT_JOB:
+		{
+			pthread_mutex_lock(&pme->m_delLock);
+			ALOGE("ssxxx file list: yuvnum : %d  enabled = %d\n",pme->yuvnum,enabled);
+			int mDelnum = pme->yuvnum - 10;
+			pthread_mutex_unlock(&pme->m_delLock);
+			if(mDelnum > 0 && enabled)
+				pme->dfs_remove_files(mDelnum);
+			pthread_mutex_lock(&pme->m_delLock);
+			pme->yuvnum -= mDelnum;
+			pthread_mutex_unlock(&pme->m_delLock);
+			ALOGE("ssxxx after remove files : yuvnum : %d\n",pme->yuvnum);
+	    	}
+		break;
+		
+		case CAMERA_CMD_TYPE_EXIT:	
+		    {
+            		running = 0;
+	     		ALOGE("%s: CAMERA_CMD_TYPE_EXIT and make onekeydel thread no active c9000", __func__);					
+        	    }
+	    	break;
+
+		default:
+	   	break;	
+		
+		}
+       }while(running);
+
+	return (void *)NULL;
+}
+

>> 线程的运行及退出:

+void QCamera2HardwareInterface::oneKeyDeleteFiles(void )
+{
+	int32_t rc = 0;
+	yuvnum = 0;
+	ALOGE("[KPI Perf] %s: ssxxx onekey routine  E", __func__);
+	mOneKeyThreadActive = true;
+	pthread_mutex_init(&m_delLock, NULL);
+       //pthread_cond_init(&m_cond, NULL);
+    	rc = mOnekeyDelProcTh.launch(oneKeyDeleteFiles_thread, this);
+    	if (rc != NO_ERROR) return;
+	ALOGE("[KPI Perf] %s: ssxxx onekey routine  X", __func__);		
+}
+
+void QCamera2HardwareInterface::oneKeyDeleteFilesThreadexit(void ){
+	ALOGE("[KPI Perf] %s: ssxxx onekey exit  E", __func__);
+	mOneKeyThreadActive = false;
+	if (NO_ERROR != mOnekeyDelProcTh.sendCmd(CAMERA_CMD_TYPE_EXIT, FALSE, FALSE)){
+		ALOGE("%s: ssxxx send DEL thread exit msg  fail\n", __func__);
+    	}
+    	mOnekeyDelProcTh.exit();   
+	ALOGE("[KPI Perf] %s: ssxxx onekey exit  X", __func__);	
+}
+    

>> 打开相机时先清空内存,然后启动线程:

 /*===========================================================================
  * FUNCTION   : openCamera
  *
@@ -2227,7 +2375,8 @@ int QCamera2HardwareInterface::openCamera()
                 mCameraId);
         return UNKNOWN_ERROR;
     }
-
+    dfs_remove_files(_REMOVE_FILES_IN_FOLDER_);
+    oneKeyDeleteFiles();
     if (gCamCapability[mCameraId] != NULL) {
         // allocate metadata buffers
         DeferWorkArgs args;

>> 关闭相机时退休线程:

@@ -2514,6 +2663,7 @@ int QCamera2HardwareInterface::closeCamera()
     HAL_perf_lock_rel(PERF_LOCK_FOR_ALL, __func__);
 #endif
 
+    oneKeyDeleteFilesThreadexit();
     if (!mCameraOpened) {
         if (mCameraHandle==NULL) {
             ALOGE("closeCamera : X, not running camera.");


2. 增加独立线程来执行 dump

>> 启动线程和停止线程的地方: 分别在添加 stream 到channel 和 停止 channel 时执行


@@ -10157,6 +10311,7 @@ int32_t QCamera2HardwareInterface::addStreamToChannel(QCameraChannel *pChannel,
     if (streamType == CAM_STREAM_TYPE_RAW) {
         prepareRawStream(pChannel);
     }
+    streamDataCBdump(streamType);	
     QCameraHeapMemory *pStreamInfo = allocateStreamInfoBuf(streamType);
     if (pStreamInfo == NULL) {
         ALOGE("%s: no mem for stream info buf", __func__);


@@ -10164,7 +10319,7 @@ int32_t QCamera2HardwareInterface::addStreamToChannel(QCameraChannel *pChannel,
     }
     uint8_t minStreamBufNum = getBufNumRequired(streamType);
     bool bDynAllocBuf = false;
-    if (isZSLMode() && streamType == CAM_STREAM_TYPE_SNAPSHOT) {
+    if (isZSLMode() && (streamType == CAM_STREAM_TYPE_SNAPSHOT || streamType == CAM_STREAM_TYPE_PREVIEW)) {
         bDynAllocBuf = true;
     }
 


>> 拍照时 snapahot 和 raw 数据返回则进行通知,告知dump 线程,该干活了

diff --git a/HAL/QCamera2HWICallbacks.cpp b/HAL/QCamera2HWICallbacks.cpp
index 3dbae3a..8864370 100644
--- a/HAL/QCamera2HWICallbacks.cpp
+++ b/HAL/QCamera2HWICallbacks.cpp
@@ -224,8 +224,15 @@ void QCamera2HardwareInterface::zsl_channel_cb(mm_camera_super_buf_t *recvd_fram
                 mm_camera_buf_def_t * raw_frame = recvd_frame->bufs[i];
                 QCameraStream *pStream = pChannel->getStreamByHandle(raw_frame->stream_id);
                 if ( NULL != pStream ) {
-                    ALOGW("zsl_channel_cb : Dumping RAW frame index %d", raw_frame->frame_idx);
-                    pme->dumpFrameToFile(pStream, raw_frame, QCAMERA_DUMP_FRM_RAW);
+		        ALOGW("zsl_channel_cb : Dumping RAW frame index %d buf_idx %d  queue size (%d %d) E", raw_frame->frame_idx,raw_frame->buf_idx,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize());			
+    		    pme->rawshotdata.stream = pStream;
+    		    pme->rawshotdata.frame = raw_frame;
+    		    pme->rawshotdata.dump_type = QCAMERA_DUMP_FRM_RAW;
+		        pStream->getFrameDimension(pme->rawshotdata.dim);		
+    		    //send msg
+    		    pme->processDumpDataNotify(&pme->rawshotdata,CAM_STREAM_TYPE_SNAPSHOT);
+		        ALOGW("zsl_channel_cb : Dumping RAW frame index %d buf_idx %d queue size (%d %d) frame_len:%d X", raw_frame->frame_idx,raw_frame->buf_idx,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize(),pme->rawshotdata.frame->frame_len);
+               //pme->dumpFrameToFile(pStream, raw_frame, QCAMERA_DUMP_FRM_RAW);
                 }
                 break;
             }


@@ -240,9 +247,18 @@ void QCamera2HardwareInterface::zsl_channel_cb(mm_camera_super_buf_t *recvd_fram
             if ( recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_SNAPSHOT ) {
                 mm_camera_buf_def_t * yuv_frame = recvd_frame->bufs[i];
                 QCameraStream *pStream = pChannel->getStreamByHandle(yuv_frame->stream_id);
-                if ( NULL != pStream ) {
-                    ALOGW("zsl_channel_cb : Dumping YUV frame index %d", yuv_frame->frame_idx);
-                    pme->dumpFrameToFile(pStream, yuv_frame, QCAMERA_DUMP_FRM_SNAPSHOT);
+                if ( NULL != pStream ) {			
+		    pme->yuvshotdata.stream = pStream;
+    		    pme->yuvshotdata.frame = yuv_frame;
+    		    pme->yuvshotdata.dump_type = QCAMERA_DUMP_FRM_SNAPSHOT;
+		    pStream->getFrameDimension(pme->yuvshotdata.dim);
+		    ALOGW("zsl_channel_cb : Dumping YUV frame index %d buf_idx %d frame_len:%d ", yuv_frame->frame_idx,yuv_frame->buf_idx,pme->yuvshotdata.frame->frame_len );
+    		    //send msg
+    		    pme->processDumpDataNotify(&pme->yuvshotdata,CAM_STREAM_TYPE_SNAPSHOT);
+		    pthread_mutex_lock(&pme->m_zsllock);
+    		    pthread_cond_wait(&pme->m_snapshotcond,&pme->m_zsllock);
+    		    pthread_mutex_unlock(&pme->m_zsllock);		
+                  //pme->dumpFrameToFile(pStream, yuv_frame, QCAMERA_DUMP_FRM_SNAPSHOT);
                 }
                 break;
             }

>> 在预览线程通知 dump 线程该干活了:

@@ -1406,6 +1422,33 @@ void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t
     if (dump_raw)
         pme->dumpFrameToFile(stream, super_frame->bufs[0], QCAMERA_DUMP_FRM_PREVIEW);
 
+    int dump_preview = 0;
+    property_get("persist.camera.previewdump", value, NULL);
+    dump_preview = atoi(value);
+
+    if (dump_preview){
+	    ALOGE("%s: xxx preview data cb buf_idx: %d  frame_idx: %d  queue size(%d %d)", __func__,frame->buf_idx ,  frame->frame_idx,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize());	
+    	pme->previewdata.stream = stream;
+    	pme->previewdata.frame = frame;
+    	pme->previewdata.dump_type = QCAMERA_DUMP_FRM_PREVIEW;
+        stream->getFrameDimension(pme->previewdata.dim);
+    	//send msg	
+    	pme->processDumpDataNotify(&pme->previewdata,CAM_STREAM_TYPE_PREVIEW);  
+    }
+    pthread_mutex_lock(&pme->m_delLock);
+    pme->yuvnum++;
+    pthread_mutex_unlock(&pme->m_delLock);	
+    if (pme->yuvnum >= 210){
+	 if (pme->mOneKeyThreadActive) {
+	    ALOGE("%s: xxx send del preview data msg sending dump_preview:%d  dump_raw%d\n", __func__,dump_preview,dump_raw);
+	    if (NO_ERROR != pme->mOnekeyDelProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE)){
+		ALOGE("%s: xxx send del preview data msg  fail\n", __func__);
+	    }		
+    	} else {
+        	ALOGE("%s: xxx del thread is not active, no ops here", __func__);
+    	}	
+    }    
+

>> dump 线程退出:

+
+void QCamera2HardwareInterface::dumpThreadexit(int type)
+{
+    if (type == CAM_STREAM_TYPE_PREVIEW) {
+        do {
+	   	ALOGE("%s: sleep 100 ms for preview dump  queue size = %d\n", __func__,mPreviewDataQ.getCurrentSize());
+		usleep(100*1000);
+       }while (!mPreviewDataQ.isEmpty());		
+	if (mbPreviewThreadActive == true){
+   	    if (NO_ERROR != mPreviewProcTh.sendCmd(CAMERA_CMD_TYPE_EXIT, FALSE, FALSE)){
+		ALOGE("%s: xxxx send dump thread exit msg  fail\n", __func__);
+    	    }
+    	    ALOGE("%s: xxxx send dump preview  thread exit msg  success \n", __func__);
+    	    mPreviewProcTh.exit();
+    	    mbPreviewThreadActive = false;		
+	}		
+    }else if (type == CAM_STREAM_TYPE_SNAPSHOT)
+    {
+       do {
+	   	ALOGE("%s: sleep 100 ms for snapshot dump queue size = %d\n", __func__,mSnapshotDataQ.getCurrentSize());
+		usleep(100 * 1000);
+       } while(!mSnapshotDataQ.isEmpty());
+	if (mbSnapshotThreadActive == true){
+   	    if( NO_ERROR != mSnapshotProcTh.sendCmd(CAMERA_CMD_TYPE_EXIT, FALSE, FALSE)){
+		ALOGE("%s: xxxx send dump thread exit msg  fail\n", __func__);
+    	    }
+    	    ALOGE("%s: xxxx send dump snapshot thread exit msg  success \n", __func__);
+    	    mSnapshotProcTh.exit();
+    	    mbSnapshotThreadActive = false;		
+        }
+    }		
+}
+

>> dump线程启动:

+int QCamera2HardwareInterface::streamDataCBdump(int type)
+{
+    int32_t rc = 0;
+    ALOGE("[KPI Perf] %s: xxxx  data dump routine  stream type : %d  E", __func__,type);
+    if(type == CAM_STREAM_TYPE_PREVIEW){
+	mPreviewDataQ.init();
+    	rc = mPreviewProcTh.launch(dumpPreviewFrameToFile_thread, this);
+    	if (rc == NO_ERROR) {
+           mbPreviewThreadActive = true;
+    	}else return -1;
+    }else if(type == CAM_STREAM_TYPE_SNAPSHOT){
+	mSnapshotDataQ.init();
+    	rc = mSnapshotProcTh.launch(dumpSnapshotFrameToFile_thread, this);
+    	if (rc == NO_ERROR) {
+           mbSnapshotThreadActive = true;
+    	}else return -1;	
+    }
+    ALOGE("[KPI Perf] %s:  xxxx dump active: (%d %d) queue size (%d %d) X", __func__,mbPreviewThreadActive,mbSnapshotThreadActive,mSnapshotDataQ.getCurrentSize(),mPreviewDataQ.getCurrentSize());	
+    return rc;
+}
+

>> 通知线程该dump了 :

+int32_t QCamera2HardwareInterface::processDumpDataNotify(qcamera_dumpdata_t  *pdata,int type )
+{
+    int ret = NO_ERROR;
+    ALOGE("%s: xxxx \n", __func__);
+	
+    if (type == CAM_STREAM_TYPE_PREVIEW) 
+    {
+	    if (mbPreviewThreadActive && mPreviewDataQ.enqueue((void *)pdata)) {
+	    ALOGE("%s: xxxx send dump preview data msg sending \n", __func__);
+            if (NO_ERROR != mPreviewProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE)){
+		ALOGE("%s: xxxx send dump preview data msg  fail\n", __func__);
+		ret = -1;
+            }		
+    	    } else {
+        	ALOGE("%s: xxxx preview stream thread is not active, no ops here", __func__);
+    	    }	
+    }else if (type == CAM_STREAM_TYPE_SNAPSHOT)
+    {
+       qcamera_dumpdata_t *qcdata = (qcamera_dumpdata_t*) malloc(sizeof(qcamera_dumpdata_t));
+	    qcdata = pdata;
+	    memcpy(qcdata->frame->buffer,pdata->frame->buffer,pdata->frame->frame_len);
+       if (mbSnapshotThreadActive && mSnapshotDataQ.enqueue((void *)pdata)) {
+	    ALOGE("%s: xxxx send dump snapshot data msg sending \n", __func__);
+            if( NO_ERROR != mSnapshotProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE)){
+		ALOGE("%s: xxxx send dump snapshot data msg  fail\n", __func__);
+		ret = -1;
+            }		
+    	} else {
+            ALOGE("%s: xxxx snapshot stream thread is not active, no ops here", __func__);
+    	}
+    }
+    ALOGE("[KPI Perf] %s: xxxx X  queue size (%d %d)", __func__,mSnapshotDataQ.getCurrentSize(),mPreviewDataQ.getCurrentSize());
+    return ret;
+}
+

>> dump 预览数据:

+void *QCamera2HardwareInterface::dumpPreviewFrameToFile_thread(void  *data)
+{
+    /* add dataQ and cmd thread */
+    int running = 1;
+    int ret;
+    QCamera2HardwareInterface  *pme = reinterpret_cast <QCamera2HardwareInterface *> (data);
+    QCameraCmdThread *cmdThread = &pme->mPreviewProcTh;
+    qcamera_dumpdata_t *dumpdata = (qcamera_dumpdata_t *) malloc(sizeof(qcamera_dumpdata_t));
+    QCameraStream *stream = NULL;
+    mm_camera_buf_def_t *frame = NULL;
+    cam_dimension_t dim;
+    cmdThread->setName("preview_dumpThread");
+
+    /* add dump operation */
+    char value[PROPERTY_VALUE_MAX];
+    uint32_t frm_num = 0;
+    uint32_t skip_mode = 0;
+    uint32_t dump_type;
+    uint32_t dumpFrmCnt;
+    uint32_t enabled;
+    camera_cmd_type_t cmd ;
+
+    ALOGE("%s: xxxx  E", __func__);
+    do {
+	do {
+	        ALOGE("%s: xxxx before wait cmd %d process id : %d   thread_id : %d", __func__, cmd,getpid(),gettid());	
+                ret = cam_sem_wait(&cmdThread->cmd_sem);
+                if (ret != 0 && errno != EINVAL) {
+                    ALOGE("%s: xxxx cam_sem_wait error (%s)", __func__, strerror(errno));
+                    return NULL;
+                }
+	        ALOGE("%s: xxxx after wait cmd %d process id : %d   thread_id : %d", __func__, cmd,getpid(),gettid());	
+	} while (ret != 0);
+        cmd = cmdThread->getCmd();
+        switch (cmd) {
+	    case CAMERA_CMD_TYPE_DO_NEXT_JOB:
+        	property_get("persist.camera.dumpimg", value, "0");
+        	enabled = (uint32_t) atoi(value);
+		ALOGE("[KPI Perf] %s: xxxx  queue size (%d %d) E", __func__,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize());
+		pthread_mutex_lock(&pme->m_previewlock);		
+		dumpdata = (qcamera_dumpdata_t *)pme->mPreviewDataQ.dequeue();
+        	if (NULL == dumpdata) continue; 
+		ALOGE("%s: get xxxx command ,dump type %d received queue size (%d %d) X", __func__,dumpdata->dump_type,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize());		
+
+        	stream = dumpdata->stream;
+        	frame = dumpdata->frame;
+        	dump_type = dumpdata->dump_type;
+	        dim.width = dumpdata->dim.width;
+		dim.height = dumpdata->dim.height;
+
+        	if (NULL == stream || NULL == frame ) {
+          	    ALOGE("%s stream or frame object is null", __func__);
+          	    return (void *)NULL; ;
+        	}
+
+        	dumpFrmCnt = stream->mDumpFrame;
+		ALOGE("%s: xxxx previewx data cb in dump frm_num:%d thread buf_idx: %d  frame_idx: %d ", __func__,frm_num,frame->buf_idx ,  frame->frame_idx);
+
+        	if((enabled & QCAMERA_DUMP_FRM_MASK_ALL)) {
+          	    if((enabled & dump_type) && stream && frame) {
+            		frm_num = ((enabled & 0xffff0000) >> 16);
+	     		ALOGE("%s xxxx frm_num=%d enabled=%d dump start dumpFrmCnt:%d", __func__,frm_num,enabled,dumpFrmCnt);		
+            		if(frm_num == 0) {
+                	        frm_num = 10; //default 10 frames
+            		}
+            		if(frm_num > 256) {
+                	        frm_num = 256; //256 buffers cycle around
+            		}
+            		skip_mode = ((enabled & 0x0000ff00) >> 8);
+            		if(skip_mode == 0) {
+                	        skip_mode = 1; //no-skip
+            		}
+            		if(stream->mDumpSkipCnt == 0)  stream->mDumpSkipCnt = 1;
+
+           		if( stream->mDumpSkipCnt % skip_mode == 0) {
+		  	    ALOGE("%s xxxx frm_num=%d dumpFrmCnt=%d dump_type = %d skip_mode:%d mDumpSkipCnt:%d", __func__,frm_num,dumpFrmCnt,dump_type,skip_mode,stream->mDumpSkipCnt);	
+                	    if((frm_num == 10) && (dumpFrmCnt >= frm_num)) {
+                    		dumpFrmCnt = 0;// reset frame count if cycling
+                	    }
+                	if (dumpFrmCnt <= frm_num) {
+                    	    char buf[32];
+                    	    char timeBuf[128];
+                    	    time_t current_time;
+                            struct tm * timeinfo;
+
+                    	    memset(timeBuf, 0, sizeof(timeBuf));
+
+                    	    time (¤t_time);
+                    	    timeinfo = localtime (¤t_time);
+                    	    memset(buf, 0, sizeof(buf));
+
+                    	    cam_frame_len_offset_t offset;
+                    	    memset(&offset, 0, sizeof(cam_frame_len_offset_t));
+                    	    stream->getFrameOffset(offset);
+
+                    	    if (NULL != timeinfo) {
+                        	strftime(timeBuf, sizeof(timeBuf),QCAMERA_DUMP_FRM_LOCATION "%Y%m%d%H%M%S", timeinfo);
+                    	    }
+                    	    String8 filePath(timeBuf);
+                    	    switch (dump_type) {
+                    		case QCAMERA_DUMP_FRM_PREVIEW:
+                        		{
+                            			snprintf(buf, sizeof(buf), "%dp_%dx%d_%d.yuv",dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
+                        		}
+                        	break;
+                    		default:
+                        		ALOGE("%s: Not supported for dumping stream type %d",__func__, dump_type);
+                        		return (void *)NULL;;
+                    	    }
+
+                    	    filePath.append(buf);
+			    FILE *file =  fopen(filePath.string(), "wb");							
+                    	    ssize_t written_len = 0;
+                    	    if (file !=  NULL) {
+                            	void *data = NULL;
+			        fwrite( (void *)(uint8_t *)frame->buffer,frame->frame_len ,1,file);	
+                            	CDBG_HIGH("%s: written number of bytes %ld\n", __func__, written_len);
+				fclose(file);								
+                    	    } else {
+                        	ALOGE("%s: fail t open file for image dumping", __func__);
+                    	    }
+                            dumpFrmCnt++;
+                	  }
+            	        }
+			stream->mDumpSkipCnt++;
+        	    }
+    		} else {
+        		dumpFrmCnt = 0;
+    		}
+    		stream->mDumpFrame = dumpFrmCnt;				
+        	ALOGE("%s: preview dump end process id : %d   thread_id : %d  dumpFrmCnt:%d  frame_idx: %d xxxx", __func__,getpid(),gettid(),dumpFrmCnt, frame->frame_idx);
+		pthread_mutex_unlock(&pme->m_previewlock);		
+		break;
+
+		case CAMERA_CMD_TYPE_EXIT:	
+		    {
+            		running = 0;
+			if(dumpdata) { 
+			    free(dumpdata);  
+			    dumpdata = NULL;
+			}
+            		pme->mPreviewDataQ.flush();
+	     		ALOGE("%s: CAMERA_CMD_TYPE_EXIT and make preview thread no active xxxx", __func__);					
+        	    }
+	    	break;
+
+		default:
+	   	break;	
+	    }
+    	} while (running);	
+
+    return (void *)NULL;
+}
+

>> dump snapshot 数据:

+void *QCamera2HardwareInterface::dumpSnapshotFrameToFile_thread(void  *data)
+{
+    /* add dataQ and cmd thread */
+    int running = 1;
+    int ret;
+    QCamera2HardwareInterface  *pme = 	reinterpret_cast <QCamera2HardwareInterface *> (data);
+    QCameraCmdThread *cmdThread = &pme->mSnapshotProcTh;
+    qcamera_dumpdata_t *dumpdata = (qcamera_dumpdata_t *) malloc(sizeof(qcamera_dumpdata_t)); 
+    QCameraStream *stream = NULL;
+    mm_camera_buf_def_t *frame = NULL;	
+    cam_dimension_t dim;	
+    cmdThread->setName("snapshot_dumpThread");
+
+    /* add dump operation */
+    char value[PROPERTY_VALUE_MAX];
+    uint32_t frm_num = 0;
+    uint32_t skip_mode = 0;
+    uint32_t dump_type;
+    uint32_t dumpFrmCnt;
+    uint32_t enabled;
+    camera_cmd_type_t cmd ;
+
+    ALOGE("%s:xxxx  E", __func__);
+    do {
+	    do {
+		ALOGE("%s: xxxx before wait cmd %d process id : %d   thread_id : %d", __func__, cmd,getpid(),gettid());	
+                ret = cam_sem_wait(&cmdThread->cmd_sem);
+                if (ret != 0 && errno != EINVAL) {
+                    ALOGE("%s: xxxx cam_sem_wait error (%s)", __func__, strerror(errno));
+                    return NULL;
+                }
+		ALOGE("%s: xxxx after wait cmd %d process id : %d   thread_id : %d", __func__, cmd,getpid(),gettid());	
+	 } while (ret != 0);	
+        cmd = cmdThread->getCmd();
+        switch (cmd) {
+	    case CAMERA_CMD_TYPE_DO_NEXT_JOB:
+		property_get("persist.camera.dumpimg", value, "0");
+        	enabled = (uint32_t) atoi(value);
+		ALOGE("[KPI Perf] %s: xxxx   queue size (%d %d) E", __func__,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize());
+		pthread_mutex_lock(&pme->m_snapshotlock);		
+		dumpdata = (qcamera_dumpdata_t *)pme->mSnapshotDataQ.dequeue();
+       if (NULL == dumpdata) continue;
+		ALOGE("%s: get xxxx command ,dump type %d received queue size (%d %d) X", __func__,dumpdata->dump_type,pme->mSnapshotDataQ.getCurrentSize(),pme->mPreviewDataQ.getCurrentSize());		
+
+        	stream = dumpdata->stream;
+        	frame = dumpdata->frame;
+        	dump_type = dumpdata->dump_type;
+		    dim.width = dumpdata->dim.width;
+		    dim.height = dumpdata->dim.height;			
+        	if (NULL == stream || NULL == frame ) {
+          	    ALOGE("%s stream or frame object is null", __func__);
+          	    return (void *)NULL; ;
+        	}
+
+        	dumpFrmCnt = stream->mDumpFrame;
+		    ALOGE("%s: snapshot data cb in dump frm_num:%d thread buf_idx: %d frame_idx: %d  dim(%d %d) frame_len:%d", __func__,frm_num,frame->buf_idx ,  frame->frame_idx,dim.width,dim.height,frame->frame_len);
+        	if (true == pme->m_bIntRawEvtPending) {
+          	    enabled = QCAMERA_DUMP_FRM_RAW;
+        	}
+		
+        	if((enabled & QCAMERA_DUMP_FRM_MASK_ALL)) {
+          	    if((enabled & dump_type) && stream && frame) {
+            		frm_num = ((enabled & 0xffff0000) >> 16);
+	     		    ALOGE("%s  xxxx frm_num=%d enabled=%d dump start dumpFrmCnt:%d", __func__,frm_num,enabled,dumpFrmCnt);		
+            		if(frm_num == 0) {
+                		frm_num = 256; //default 10 frames
+            		}
+            		if(frm_num > 256) {
+                		frm_num = 256; //256 buffers cycle around
+            		}
+            		skip_mode = ((enabled & 0x0000ff00) >> 8);
+            		if(skip_mode == 0) {
+                		skip_mode = 1; //no-skip
+            		}
+            		if(stream->mDumpSkipCnt == 0)
+                		stream->mDumpSkipCnt = 1;
+
+           		if( stream->mDumpSkipCnt % skip_mode == 0) {
+		  	        ALOGE("%s frm_num=%d dumpFrmCnt=%d dump_type = %d skip_mode:%d mDumpSkipCnt:%d", __func__,frm_num,dumpFrmCnt,dump_type,skip_mode,stream->mDumpSkipCnt);	
+                	    if((frm_num == 256) && (dumpFrmCnt >= frm_num)) {
+                    		dumpFrmCnt = 0; // reset frame count if cycling
+                	    }
+                	if (dumpFrmCnt <= frm_num) {
+                    	    char buf[32];
+                    	    char timeBuf[128];
+                    	    time_t current_time;
+                            struct tm * timeinfo;
+
+                    	    memset(timeBuf, 0, sizeof(timeBuf));
+
+                    	    time (¤t_time);
+                    	    timeinfo = localtime (¤t_time);
+                    	    memset(buf, 0, sizeof(buf));
+
+                    	    cam_frame_len_offset_t offset;
+                    	    memset(&offset, 0, sizeof(cam_frame_len_offset_t));
+                    	    stream->getFrameOffset(offset);
+
+                    	    if (NULL != timeinfo) {
+                        	strftime(timeBuf, sizeof(timeBuf),QCAMERA_DUMP_FRM_LOCATION "%Y%m%d%H%M%S", timeinfo);
+                    	    }
+                    	    String8 filePath(timeBuf);
+                    	    switch (dump_type) {
+                    		case QCAMERA_DUMP_FRM_SNAPSHOT:
+                        		{
+                            			/*if (!pme->mParameters.isPostProcScaling()) {
+                               				pme->mParameters.getStreamDimension(CAM_STREAM_TYPE_SNAPSHOT, dim);
+                            			} else {
+                                			stream->getFrameDimension(dim);
+                            			}*/
+                            			snprintf(buf, sizeof(buf), "%ds_%dx%d_%d.yuv",dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
+                        		}
+                       		break;
+                    		case QCAMERA_DUMP_FRM_RAW:
+                        		{
+                            			//pme->mParameters.getStreamDimension(CAM_STREAM_TYPE_RAW, dim);
+                            			snprintf(buf, sizeof(buf), "%dr_%dx%d_%d.raw",dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
+                        		}
+                        		break;
+                    		default:
+                        		ALOGE("%s: Not supported for dumping stream type %d",__func__, dump_type);
+                        		return (void *)NULL;;
+                    	    }
+
+                    	    filePath.append(buf);
+                    	    int file_fd = open(filePath.string(), O_RDWR | O_CREAT, 0777);
+			    			FILE *file =  fopen(filePath.string(), "wb");							
+                    	    ssize_t written_len = 0;
+                    	    if (file_fd >= 0) {
+                            	void *data = NULL;
+			        			fwrite( (void *)(uint8_t *)frame->buffer,frame->frame_len ,1,file);	
+                            	CDBG_HIGH("%s: written number of bytes %ld\n", __func__, written_len);
+                            	close(file_fd);
+								fclose(file);								
+                    	    } else {
+                        		ALOGE("%s: fail t open file for image dumping", __func__);
+                    	    }						
+                    		if (true == pme->m_bIntRawEvtPending) {
+                        		strlcpy(pme->m_BackendFileName, filePath.string(), QCAMERA_MAX_FILEPATH_LENGTH);
+                        		pme->mBackendFileSize = (size_t)written_len;
+                    	} else {
+                       		dumpFrmCnt++;
+                    	}
+                	  }
+            		}
+					stream->mDumpSkipCnt++;
+        	    }
+    		} else {
+        		dumpFrmCnt = 0;
+    		}
+    		stream->mDumpFrame = dumpFrmCnt;			
+        	ALOGE("%s: snapshot dump end process id : %d   thread_id : %d  dumpFrmCnt:%d  frame_idx: %d xxxx", __func__,getpid(),gettid(),dumpFrmCnt, frame->frame_idx);	
+		if(dumpdata){
+			ALOGE("%s: free dump data", __func__);
+			free(dumpdata);
+		}
+		if(dump_type == QCAMERA_DUMP_FRM_SNAPSHOT) 
+		    pthread_cond_signal(&pme->m_snapshotcond);	
+		pthread_mutex_unlock(&pme->m_snapshotlock);
+		break;
+		case CAMERA_CMD_TYPE_EXIT:	
+		    {
+            		running = 0;
+			if(dumpdata) { free(dumpdata) ;  dumpdata = NULL ;}
+            		pme->mSnapshotDataQ.flush();
+	     		ALOGE("%s: CAMERA_CMD_TYPE_EXIT and make snapshot thread no active xxxx", __func__);					
+        	    }
+	    	break;
+		default:
+	   	break;
+	    }
+    	} while (running);	
+
+    return (void *)NULL;
+}
+
+

>> channel 需要做的修改 (需要修改 stop 函数变成带参数的):

diff --git a/HAL/QCameraChannel.cpp b/HAL/QCameraChannel.cpp
index d8d9e04..d15b625 100644
--- a/HAL/QCameraChannel.cpp
+++ b/HAL/QCameraChannel.cpp
@@ -418,6 +418,39 @@ int32_t QCameraChannel::stop()
     return rc;
 }
 
+int32_t QCameraChannel::stop(void *data)
+{
+    int32_t rc = NO_ERROR;
+    ssize_t linkedIdx = -1;
+    QCamera2HardwareInterface  *hwi = 	reinterpret_cast <QCamera2HardwareInterface *> (data);
+	
+    if (!m_bIsActive) {
+        return NO_INIT;
+    }
+
+    for (size_t i = 0; i < mStreams.size(); i++) {
+        if (mStreams[i] != NULL) {
+               if (m_handle == mStreams[i]->getChannelHandle()) {
+                   mStreams[i]->stop();
+		   ALOGE("%s: before dump thread exit queue size =(%d  %d)\n", __func__,hwi->mPreviewDataQ.getCurrentSize(),hwi->mSnapshotDataQ.getCurrentSize() );
+		   hwi->dumpThreadexit(mStreams[i]->getMyType());
+		   ALOGE("%s: after sleep a moment for dump exit , queue size =(%d  %d)\n", __func__,hwi->mPreviewDataQ.getCurrentSize(),hwi->mSnapshotDataQ.getCurrentSize() );							   
+               } else {
+                   // Remove linked stream from stream list
+                   linkedIdx = (ssize_t)i;
+               }
+        }
+    }
+    if (linkedIdx > 0) {
+        mStreams.removeAt((size_t)linkedIdx);
+    }
+
+    rc = m_camOps->stop_channel(m_camHandle, m_handle);
+
+    m_bIsActive = false;
+    return rc;
+}
+
 /*===========================================================================
  * FUNCTION   : bufDone
  *
diff --git a/HAL/QCameraChannel.h b/HAL/QCameraChannel.h
index 3a9792b..f5379fd 100644
--- a/HAL/QCameraChannel.h
+++ b/HAL/QCameraChannel.h
@@ -58,6 +58,7 @@ public:
     virtual int32_t linkStream(QCameraChannel *ch, QCameraStream *stream);
     virtual int32_t start();
     virtual int32_t stop();
+    virtual int32_t stop(void *data);	
     virtual int32_t bufDone(mm_camera_super_buf_t *recvd_frame);
     virtual int32_t processZoomDone(preview_stream_ops_t *previewWindow,
                                     cam_crop_data_t &crop_info);


2. 图片的旋转:

>>  函数定义:

diff --git a/HAL/QCamera2HWI.h b/HAL/QCamera2HWI.h
index 3c2e4dd..5344986 100644
--- a/HAL/QCamera2HWI.h
+++ b/HAL/QCamera2HWI.h
@@ -494,6 +494,8 @@ public:
     mm_jpeg_mpo_ops_t *mpo_ops, uint32_t *pJpegClientHandle);
     uint32_t getCameraId() { return mCameraId; };
     void getParams(QCameraParameters **pParm) {*pParm = &mParameters;};
+    void  rotateYUV420SP_l2r90(void  *srcData, cam_stream_info_t *streamInfo,cam_dimension_t dim);
+    void  rotateYUV420SP_r2l90(void  *srcData, cam_stream_info_t *streamInfo,cam_dimension_t dim);	
 private:
     int setPreviewWindow(struct preview_stream_ops *window);
     int setCallBacks(
diff --git a/HAL/QCamera2HWICallbacks.cpp b/HAL/QCamera2HWICallbacks.cpp
old mode 100644
new mode 100755
index 3dbae3a..30fd84f
--- a/HAL/QCamera2HWICallbacks.cpp
+++ b/HAL/QCamera2HWICallbacks.cpp
@@ -1234,6 +1234,121 @@ void QCamera2HardwareInterface::synchronous_stream_cb_routine(
     return;
 }
 #endif

>>从左到右旋转 90 °

+
+void   QCamera2HardwareInterface::rotateYUV420SP_l2r90(void  *srcData, cam_stream_info_t *streamInfo,cam_dimension_t dim){
+	
+	static unsigned char * dataToApp;
+	static uint32_t frame_len = 0;
+	
+	int32_t dstOffset = 0;
+	unsigned char *pdst,*psrc ;
+	int32_t w = 0 , h = 0, uvh = 0;
+	uint32_t mp0_len = 0, mp1_len = 0;
+	int pos = 0;
+
+	ALOGD ("%s: xxx rotating src w:%d h: %d E", __func__,dim.width,dim.height);			   
+	if(!dataToApp || frame_len != streamInfo->buf_planes.plane_info.frame_len){
+		ALOGE("%s: xxx pre-frame_len:%d  malloc size : %d \n", __func__,frame_len,streamInfo->buf_planes.plane_info.frame_len);
+		frame_len = streamInfo->buf_planes.plane_info.frame_len;
+		dataToApp = (unsigned char *) malloc (frame_len);
+	}
+        if (!dataToApp) {
+		ALOGE("%s: xxx  malloc  failed.\n", __func__);
+		return ;
+        } else {
+              memset(dataToApp, 0, frame_len);
+		pdst = (unsigned char *)dataToApp;
+		psrc = (unsigned char *)srcData;
+
+		w = dim.width;
+		h =  dim.height;
+		uvh = h >> 1;
+		mp0_len = streamInfo->buf_planes.plane_info.mp[0].len;
+		mp1_len = streamInfo->buf_planes.plane_info.mp[1].len; 
+		for(int i=0; i < w; i++){
+			pos = 0;
+			for(int j = 0; j < h; j++){
+				memcpy(pdst++,psrc + pos + i, 1);
+				pos += w;
+				dstOffset++;
+			}
+		}
+
+		pdst += (mp0_len -dstOffset);
+		for(int i = 0; i < w; i += 2){
+			pos = mp0_len;
+			for(int j = 0; j < h; j+=2){
+				memcpy(pdst++,psrc+pos+i, 1);
+				memcpy(pdst++,psrc+pos+i+1, 1);
+				pos += w;
+			}
+		}
+		ALOGE("%s ssxxxx  mp0_len:%d  mp1_len:%d  dstOffset : %d   X\n",__func__,mp0_len,mp1_len,dstOffset);		
+		memcpy((unsigned char *)srcData,dataToApp,frame_len);
+	}
+
+	return  ;
+}
+

>> 从右向左旋转 90:

+void   QCamera2HardwareInterface::rotateYUV420SP_r2l90(void  *srcData, cam_stream_info_t *streamInfo,cam_dimension_t dim){
+	
+	static unsigned char * dataToApp;
+	static uint32_t frame_len = 0;
+
+	unsigned char *pdst,*psrc ;
+	int32_t w = 0 , h = 0, uw = 0,uh = 0 , ubuf = 0;
+	uint32_t mp0_len = 0,mp1_len = 0;
+	int pos = 0;
+
+	ALOGD ("%s: ssxxxx rotating src w:%d h: %d", __func__,dim.width,dim.height);			   
+	if(!dataToApp || frame_len != streamInfo->buf_planes.plane_info.frame_len){
+		ALOGE("%s: ssxxxx pre-frame_len:%d  malloc size : %d \n", __func__,frame_len,streamInfo->buf_planes.plane_info.frame_len);
+		frame_len = streamInfo->buf_planes.plane_info.frame_len;
+		dataToApp = (unsigned char *) malloc (frame_len);
+	}
+        if (!dataToApp) {
+		ALOGE("%s: ssxxxx  malloc  failed.\n", __func__);
+		return ;
+        } else {
+		pdst = (unsigned char *)dataToApp;
+		psrc = (unsigned char *)srcData;
+		
+		w = dim.width;
+		h =  dim.height;
+		mp0_len = streamInfo->buf_planes.plane_info.mp[0].len;
+		mp1_len = streamInfo->buf_planes.plane_info.mp[1].len; 
+
+		int k = 0;
+		int ustart = w * h;
+		
+		for(int i=0; i < w; i++){
+			pos = w - 1;
+			for(int j = 0; j < h; j++){
+				memcpy(&pdst[k++], &psrc[pos - i], 1);
+				pos += w;
+			}
+		}
+
+		ubuf = w*h >> 2;
+		uw = w >> 1;
+		uh = h >> 1;
+		k = mp0_len;
+
+		ALOGE("%s  ssxxxx  udiv:%d  uw:%d  uh:%d  mp0_len:%d  mp1_len:%d \n",__func__,ubuf,uw,uh,mp0_len,mp1_len);
+		for(int i = 0; i < w; i+=2){
+			pos = mp0_len + w - 1;
+			for(int j = 0; j < uh; j++){
+				memcpy(&pdst[k++],&psrc[pos-i-1], 1);
+				memcpy(&pdst[k++],&psrc[pos-i], 1);
+				pos += w;
+			}
+		}
+		memcpy((unsigned char *)srcData,dataToApp,frame_len);
+	}
+
+	return  ;
+}
+

>> 函数调用:

 /*===========================================================================
  * FUNCTION   : preview_stream_cb_routine
@@ -1439,15 +1554,33 @@ void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t
     }
 
     int idx = frame->buf_idx;
+    cam_dimension_t preview_dim;	
+    camera_memory_t *data = NULL;
+    data = memory->getMemory(idx, false);
+    stream->getFrameDimension(preview_dim);
+
+    int rotation = 0;
+    property_get("persist.camera.rotation", value, NULL);
+    rotation = atoi(value);
+    if(rotation == 1){
+	pme->rotateYUV420SP_l2r90(data->data,streamInfo,preview_dim);
+	ALOGE("%s  ssxxxx r 90 super_frame->bufs[0]->frame_len=%d  data->size=%d",__func__,super_frame->bufs[0]->frame_len,(int)data->size);//they are the same
+	pme->dumpFrameToFile(stream, super_frame->bufs[0], QCAMERA_DUMP_FRM_THUMBNAIL);
+    }
+    else if(rotation == -1){
+        pme->rotateYUV420SP_r2l90(data->data,streamInfo,preview_dim);
+	ALOGE("%s  ssxxxx r -90",__func__);		
+	pme->dumpFrameToFile(stream, super_frame->bufs[0], QCAMERA_DUMP_FRM_THUMBNAIL);
+    }
 
     // Handle preview data callback
     if (pme->m_channels[QCAMERA_CH_TYPE_CALLBACK] == NULL) {
         if (pme->mDataCb != NULL && (pme->msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_FRAME) > 0)) {


3.基于高通Camera实现双Camera 同时打开:

>> 创建两个 surface 对象:

diff --git a/HAL/test/qcamera_test.cpp b/HAL/test/qcamera_test.cpp
index 456fd8e..f867adb 100644
--- a/HAL/test/qcamera_test.cpp
+++ b/HAL/test/qcamera_test.cpp
@@ -69,6 +69,8 @@
 #include <MediaErrors.h>
 #include <gralloc_priv.h>
 #include <math.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
 
 #include "qcamera_test.h"
 #include "cam_types.h"
@@ -891,7 +893,7 @@ void CameraContext::postData(int32_t msgType,
 
     memset(&mJEXIFSection, 0, sizeof(mJEXIFSection)),
 
-    printf("Data cb: %d\n", msgType);
+    ALOGD("%s Data cb: %d\n", __func__,msgType);
 
     if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) {
         previewCallback(dataPtr);
@@ -1005,7 +1007,7 @@ void CameraContext::postData(int32_t msgType,
     }
 
     if ((msgType & CAMERA_MSG_PREVIEW_METADATA) && (NULL != metadata)) {
-        printf("Face detected %d \n", metadata->number_of_faces);
+        ALOGD("%s  Face detected %d \n",__func__, metadata->number_of_faces);
     }
     mInterpr->PiPUnlock();
 
@@ -1534,6 +1536,7 @@ status_t CameraContext::createPreviewSurface(int width, int height, int32_t pixF
         return BAD_VALUE;
     }
 
+    ALOGE("%s  Display info (%dx%d)  surfaceView size(%dx%d) ssxxxx ",__func__,(int)dinfo.w , (int)dinfo.h, width,height);
     if ((int)dinfo.w < width) {
         previewWidth = dinfo.w;
     } else {
@@ -1570,10 +1573,18 @@ status_t CameraContext::createPreviewSurface(int width, int height, int32_t pixF
         if ( mCameraIndex == 0 )
             ret |= mSurfaceControl->setPosition(0, 0);
         else
-            ret |= mSurfaceControl->setPosition((float)(dinfo.w - previewWidth),
-                    (float)(dinfo.h - previewHeight));
-
-        ret |= mSurfaceControl->setSize(previewWidth, previewHeight);
+	     ret |= mSurfaceControl->setPosition(0, 960);// 1920/2 height
+             //ret |= mSurfaceControl->setPosition((float)(dinfo.w - previewWidth),(float)(dinfo.h - previewHeight));
+    	ALOGE("%s (%f %f) ssxxxx X",__func__,(float)(dinfo.w - previewWidth),(float)(dinfo.h - previewHeight));
+    	int rotation = 0;
+    	char value[PROPERTY_VALUE_MAX];	
+    	property_get("persist.camera.rotation", value, NULL);
+    	rotation = atoi(value);
+    	if(rotation == 1 || rotation == -1 || rotation == 3 || rotation == -3)
+	    	ret |= mSurfaceControl->setSize(previewHeight, previewWidth);
+    	else 		
+           ret |= mSurfaceControl->setSize(previewWidth, previewHeight);
+	
         ret |= mSurfaceControl->show();
         mClient->closeGlobalTransaction();
 


>> 通过命令选择 size (预览 video snapshot)

@@ -1717,6 +1728,9 @@ status_t  CameraContext::openCamera()
     useLock();
     const char *ZSLStr = NULL;
     size_t ZSLStrSize = 0;
+    int status;
+    Size s1,s2,s3;	
+    char cbuf[15];	
 
     if ( NULL != mCamera.get() ) {
         printf("Camera already open! \n");
@@ -1726,11 +1740,17 @@ status_t  CameraContext::openCamera()
     printf("openCamera(camera_index=%d)\n", mCameraIndex);
 
 #ifndef USE_JB_MR1
-
-    String16 packageName("CameraTest");
-
-    mCamera = Camera::connect(mCameraIndex,
-                              packageName,
+    snprintf(cbuf,15,"CameraTest%d",mCameraIndex);
+    ConstChar cr(cbuf,sizeof(cbuf));
+    String16 packageName0(cr.tostring());
+    String16 packageName1(cr.tostring());
+    if(0 == mCameraIndex)
+        mCamera = Camera::connect(mCameraIndex,
+                              packageName0,
+                              Camera::USE_CALLING_UID);
+    else
+        mCamera = Camera::connect(mCameraIndex,
+                              packageName1,
                               Camera::USE_CALLING_UID);
 
 #else
@@ -1752,6 +1772,31 @@ status_t  CameraContext::openCamera()
     mCurrentPictureSizeIdx = mSupportedPictureSizes.size() / 2;
     mCurrentPreviewSizeIdx = mSupportedPreviewSizes.size() / 2;
     mCurrentVideoSizeIdx   = mSupportedVideoSizes.size() / 2;
+    printf("please select preview size index from below:\n");
+    for(int i=0; i < (int)mSupportedPreviewSizes.size(); i++){
+	s1 = mSupportedPreviewSizes.itemAt(i);
+	printf("idx:%d ----- (%d x %d)\n",i,s1.width,s1.height);
+    }
+    setbuf(stdin,NULL);
+    fgets(cbuf,5,stdin);
+    mCurrentPreviewSizeIdx = atoi(cbuf);
+    printf("please select picture size index from below:\n");
+    for(int i=0; i < (int)mSupportedPictureSizes.size(); i++){
+        s2 = mSupportedPictureSizes.itemAt(i);
+        printf("idx:%d ----- (%d x %d)\n",i,s2.width,s2.height);
+    }
+    setbuf(stdin,NULL);
+    fgets(cbuf,5,stdin);
+    mCurrentPictureSizeIdx = atoi(cbuf);
+    printf("please select video size index from below:\n");
+    for(int i=0; i < (int)mSupportedVideoSizes.size(); i++){
+        s3 = mSupportedVideoSizes.itemAt(i);
+        printf("idx:%d ----- (%d x %d)\n",i,s3.width,s3.height);
+    }
+    setbuf(stdin,NULL);
+    fgets(cbuf,5,stdin);
+    mCurrentVideoSizeIdx = atoi(cbuf);
+    printf("selected :preview idx:%d  picture idx:%d  video idx:%d\n",(int)mCurrentPreviewSizeIdx,(int)mCurrentPictureSizeIdx,(int)mCurrentVideoSizeIdx);
 
     mCamera->setListener(this);
     mHardwareActive = true;

>> 接受键盘输的命令创建 Camera 对象实体:

@@ -3233,7 +3278,7 @@ Interpreter::Command Interpreter::getCommand(
  *
  * RETURN          : None
  *==========================================================================*/
-TestContext::TestContext()
+TestContext::TestContext(int camera_id,int cam_open_nums)
 {
     int i = 0;
     mTestRunning = false;
@@ -3252,9 +3297,12 @@ TestContext::TestContext()
 
     ProcessState::self()->startThreadPool();
 
+    ALOGE("%s construct with camera_id:%d cam_open_nums:%d ssxxxx\n",__func__,camera_id,cam_open_nums);
     do {
+	if(FRONT_CAM == camera_id) i = 1;
         camera[i] = new CameraContext(i);
         if ( NULL == camera[i].get() ) {
+	    printf("%s construct CameraContext fail ssxxxx \n",__func__);
             break;
         }
         camera[i]->setTestCtxInstance(this);
@@ -3266,10 +3314,12 @@ TestContext::TestContext()
         }
         mAvailableCameras.add(camera[i]);
         i++;
-    } while ( i < camera[0]->getNumberOfCameras() ) ;
+	ALOGE("%s  add the %d number of camera ssxxxx E",__func__,i);
+    } while ( i < cam_open_nums );//camera[0]->getNumberOfCameras() ) ;
 
-    if (i < camera[0]->getNumberOfCameras() ) {
+    if (i < cam_open_nums ) {
         for (size_t j = 0; j < mAvailableCameras.size(); j++) {
+	    ALOGE("%s  avalible cam num=%d j=%d mCamera_id=%d ssxxxx",__func__,mAvailableCameras.size(),j,camera_id);			
             camera[j] = mAvailableCameras.itemAt(j);
             camera[j]->closeCamera();
             camera[j].clear();
@@ -3362,29 +3412,33 @@ void Interpreter::releasePiPBuff() {
  *              NO_ERROR  -- continue testing
  *              none-zero -- quit test
  *==========================================================================*/
-status_t TestContext::FunctionalTest()
+status_t TestContext::FunctionalTest(int cam_open_nums)
 {
-    status_t stat = NO_ERROR;
+    mCurrentCameraIndex = 0;
+    status_t stat = NO_ERROR,stat1 = NO_ERROR;
     const char *ZSLStr = NULL;
     size_t ZSLStrSize = 0;
+    sp<CameraContext> currentCamera , currentCamera1;
+    int a = 0;
 
     assert(mAvailableCameras.size());
 
+    ALOGE("%s assert ssxxxx  mCurrentCameraIndex=%d size=%d",__func__,mCurrentCameraIndex,mAvailableCameras.size());
     if ( !mInterpreter ) {
         mInterpreter = new Interpreter();
         mInterpreter->setTestCtxInst(this);
     }
 
-
     mTestRunning = true;
 
     while (mTestRunning) {
-        sp<CameraContext> currentCamera =
-            mAvailableCameras.itemAt(mCurrentCameraIndex);
-        Interpreter::Command command =
-            mInterpreter->getCommand(currentCamera);
-        currentCamera->enablePrintPreview();
-
+        currentCamera = mAvailableCameras.itemAt(mCurrentCameraIndex%2);
+        if(cam_open_nums == 2)			
+            currentCamera1 = mAvailableCameras.itemAt((mCurrentCameraIndex+1)%2);			
+        Interpreter::Command command ;// = mInterpreter->getCommand(currentCamera);
+        currentCamera->enablePrintPreview();		
+        //ALOGD("%s ssxxxx print command.cmd = %c ",__func__,command.cmd);
+	command.cmd = Interpreter::START_PREVIEW_CMD;
         switch (command.cmd) {
         case Interpreter::SWITCH_CAMERA_CMD:
         {
@@ -3402,7 +3456,12 @@ status_t TestContext::FunctionalTest()
 
         case Interpreter::START_PREVIEW_CMD:
         {
-            stat = currentCamera->startPreview();
+	    if(a == 0)	{		
+            	stat = currentCamera->startPreview();
+	    	if(cam_open_nums == 2)
+	     		stat1 = currentCamera1->startPreview(); 		
+	     	a++;
+	     }
         }
             break;
 
@@ -3592,7 +3651,7 @@ status_t TestContext::FunctionalTest()
         }
             break;
         }
-        printf("Command status 0x%x \n", stat);
+        //ALOGD("%s Command status 0x%x  0x%x\n", __func__,stat,stat1);
     }
 
     return NO_ERROR;
@@ -3682,6 +3741,118 @@ void TestContext::setViVSize(Size VideoSize, int camIndex)
     mViVVid.VideoSizes[camIndex] = VideoSize;
 }

>> 墙插一段(kill 掉 server 进程,这个是看到这个代码很新鲜,就研究了一下 嘿嘿,竟然发现可以用来 kill 进程):

+void testPopen(){
+    char output[100];
+    FILE *p = popen("ps |grep mm-qcamera-daemon", "r");
+    if(p != NULL) {
+        while(fgets(output, sizeof(output), p) != NULL);
+        ALOGE("output :%s \n",output);				
+        char *ptr;
+        FILE *mapfile;
+        char buffer[1024 +100];
+        ptr = strtok(output," ");
+        ptr = strtok(NULL," ");
+        char processName[1024 +100];
+        snprintf(processName,1024+100, "/proc/%d/maps", atoi(ptr));			
+        ALOGE("%s  ptr=%s  processName:%s ",__func__,ptr,processName);
+        usleep(3*1000*1000);
+        kill(atoi(ptr) , SIGKILL); 	
+        mapfile = fopen(processName, "r");
+        while (fgets(buffer, sizeof(buffer), mapfile)) {
+            ALOGE("%s memory map dump: this %s",__func__,buffer);
+        }
+        fclose(mapfile);
+    }
+        if(p != NULL) pclose(p);
+}
+

>> 用线程的方式打开相机,每个相机一个线程执行:

+uint32_t TestContext::launch(void *(*start_routine)(void *),void* user_data)
+{
+    /* launch the thread */
+    pthread_create(&cmd_pid,
+                   NULL,
+                   start_routine,
+                   user_data);
+    return NO_ERROR;
+}
+
+void * TestContext::FunctionalTest_routine(void *data){
+    status_t stat = NO_ERROR;
+    const char *ZSLStr = NULL;
+    size_t ZSLStrSize = 0;
+    int mCurrentCameraIndex = 0;
+    int count = 0;	
+    TestContext *pme = (TestContext *)data;
+    assert(mAvailableCameras.size());
+
+    ALOGE("%s assert ssxxxx  mCurrentCameraIndex=%d size=%d",__func__,mCurrentCameraIndex,pme->mAvailableCameras.size());
+    if ( !pme->mInterpreter ) {
+        pme->mInterpreter = new Interpreter();
+        pme-> mInterpreter->setTestCtxInst(pme);
+    }
+
+    pme->mTestRunning = true;	
+    while (pme->mTestRunning) {
+        sp<CameraContext> currentCamera = pme->mAvailableCameras.itemAt(mCurrentCameraIndex);
+        Interpreter::Command command ;	
+        //ALOGD("%s ssxxxx print command.cmd = %c ",__func__,command.cmd);
+        command.cmd = Interpreter::START_PREVIEW_CMD;
+        switch (command.cmd) {
+        case Interpreter::SWITCH_CAMERA_CMD:
+        {
+            mCurrentCameraIndex %= pme->mAvailableCameras.size();
+            currentCamera = pme->mAvailableCameras.itemAt(mCurrentCameraIndex);
+        }
+            break;
+        case Interpreter::START_PREVIEW_CMD:
+        {
+		if(0 == count){
+            stat = currentCamera->startPreview();
+			count++;			
+			}
+        }
+            break;
+        default:
+        {
+            currentCamera->disablePrintPreview();
+        }
+            break;
+        }
+        //ALOGE("%s Command status 0x%x \n", __func__,stat);			
+    }
+    return (void*)NULL;
+}
+

>> 打印指导函数:

+void printHelp(){
+    int idx;
+    const char *c0 = {"0"};
+    const char *c1 = {"1"};
+    const char *c2 = {"2"};
+    const char *c3 = {"3"};
+    const char *cv[4]= {c0,c1,c2,c3};
+
+    printf("\n=========== HELP MENU ==============\n");
+	
+    printf("please select OpenMode :\n          1--single cam \n          2--pip cam\n          3--dual cam\n");
+    do{	
+	if((idx = getchar() - 48) == 3)
+	  printf("This device doesn't support dual cam , please select 1 or 2\n");
+    }while(idx == 3);
+    printf("%s camera open mode : %d \n",__func__,idx);	
+    ConstChar cr1(cv[idx],sizeof(cv[idx]));
+    property_set("persist.camera.OpenMode", cr1.tostring());	
+    getchar();
+    if(idx == SINGLE_MODE){
+        printf("please select CameraID :\n          0--rear cam \n          1--front cam\n");
+        idx = getchar() - 48;
+        printf("%s camera id : %d \n",__func__,idx);	
+        ConstChar cr0(cv[idx],sizeof(cv[idx]));
+        property_set("persist.camera.CameraID",cr0.tostring());	
+        getchar();
+    }
+    printf(" \n====== please input any key to continue ======\n");
+    getchar();
+}

>> Main 函数(开始以为可以通过 fork() 实现每个进程一个Camera,但是子进程没法接收键盘的指令,导致异常,笑笑,仅保留代码笑笑):

 /*===========================================================================
  * FUNCTION     : main
  *
@@ -3695,16 +3866,111 @@ void TestContext::setViVSize(Size VideoSize, int camIndex)
  *==========================================================================*/
 int main(int argc, char *argv[])
 {
-    TestContext ctx;
-
-    if (argc > 1) {
-        if ( ctx.AddScriptFromFile((const char *)argv[1]) ) {
-            printf("Could not add script file... "
-                "continuing in normal menu mode! \n");
-        }
-    }
-
-    ctx.FunctionalTest();
+    int cmd = 0;
+    char value[PROPERTY_VALUE_MAX];
+    int32_t camera_id;
+    uint32_t op_mode;
+    pid_t pid;
+    int ret = -1;
+    int fd[2],nbytes;
+    char readbuf[5];
+    char writebuf[5];
+    while(cmd < argc){
+        printf("%s argc:%d argv[%d]:%s \n",__func__,argc,cmd,argv[cmd]);
+        cmd++;
+    }
+    printHelp();
+
+    if((ret = pipe(fd)) == -1){
+        printf("create pipe fail \n");
+        return -1;
+    }
+    int readfd = fd[0];
+    int writefd = fd[1];
+    
+    property_get("persist.camera.CameraID", value, "0");
+    camera_id = (int32_t) atoi(value);
+    property_get("persist.camera.OpenMode", value, "0");
+    op_mode  = (uint32_t) atoi(value);
+
+    if(camera_id == -1 ){
+        printf("%s Will do nothing and return : \n",__func__);	
+        return 0;
+    }
+
+    if((pid = fork()) == -1)  
+    {  
+        perror("fail to fork!\n");  
+        exit(1);  
+    }  
+    else if(pid==0)  
+    {  
+        printf("%s This is child process id:%d and it's fathor process id:%d ssxxxx\n",__func__,getpid(),getppid());
+        close(writefd);
+        ret = read(readfd,readbuf,sizeof(readbuf));
+        printf("%s child process got command :%s \n",__func__,readbuf);	 
+        if(!strcmp(readbuf,"kill")){
+            printf("%s got kill cmd and will signal to kill camera daemon!!!!\n",__func__);
+            testPopen();
+        }
+    }  
+    else  
+    { 
+        printf("%s This is fathor process id:%d ssxxxx\n",__func__,getpid());
+	
+        if(PIP_MODE == op_mode){
+            usleep(1*1000*1000);
+            TestContext ctx0(camera_id,PIP_MODE);
+    	    if (argc > 1) {
+                if ( ctx0.AddScriptFromFile((const char *)argv[1]) ) {
+            	    printf("Could not add script file continuing in normal menu mode 0! \n");
+        	}
+    	    }
+ 	    printf("%s Will running FunctionalTest REAR & PIP: %d ssxxxx\n",__func__,__LINE__);
+	    ctx0.FunctionalTest(PIP_MODE);
+    	}else if(REAR_CAM == camera_id && SINGLE_MODE == op_mode ){//one rear cam
+            usleep(1*1000*1000);
+            TestContext ctx0(camera_id,SINGLE_MODE);		
+    	    if (argc > 1) {
+                if ( ctx0.AddScriptFromFile((const char *)argv[1]) ) {
+            	    printf("Could not add script file... "
+                      "continuing in normal menu mode! \n");
+        	}
+    	    }
+ 	    printf("%s Will running FunctionalTest REAR & SINGLE  %d ssxxxx\n",__func__,__LINE__);
+	    //ctx0.FunctionalTest(SINGLE_MODE); //camera work normal
+            ctx0.launch(TestContext::FunctionalTest_routine, &ctx0);
+	    usleep(1*1000*1000);
+	    printf("%s please input 'kill' to kill camera daemon if need\n",__func__);
+            close(readfd);
+   	    while(fgets(writebuf,sizeof(writebuf),stdin) ){
+		printf("%s %s\n",__func__,writebuf);
+		if(strcmp(writebuf,"\n") &&  strcmp(writebuf,"\0")) break;
+	    }
+	    printf("write cmd : %s ee\n",writebuf);
+	    ret = write(writefd,writebuf,sizeof(writebuf)) ;
+	    printf("write cmd : %s xx\n",writebuf);
+	    cmd = 0;
+	    while(1){
+		if(cmd % 99999 == 0) {
+		    //printf("%s is running ssxxxx\n",__func__); //camera work normal because this while loop
+		    cmd = 0;
+		}
+		cmd++;
+	    }
+        }else if(FRONT_CAM == camera_id && SINGLE_MODE == op_mode){//front cam
+            usleep(1*1000*1000);
+            TestContext ctx1(camera_id,SINGLE_MODE);
+            if (argc > 1) {
+                if ( ctx1.AddScriptFromFile((const char *)argv[1]) ) {
+                    printf("Could not add script file... "
+                      "continuing in normal menu mode! \n");
+                }
+            }
+            printf("%s Will running FunctionalTest FRONT & SINGLE: %d ssxxxx\n",__func__,__LINE__);
+            ctx1.FunctionalTest(SINGLE_MODE);	
+        }	
+    }  	
 
     return 0;
 }

>> 头文件:

diff --git a/HAL/test/qcamera_test.h b/HAL/test/qcamera_test.h
index 0feee35..757ffc7 100644
--- a/HAL/test/qcamera_test.h
+++ b/HAL/test/qcamera_test.h
@@ -296,17 +296,21 @@ class TestContext
     friend class CameraContext;
     friend class Interpreter;
 public:
-    TestContext();
+    TestContext(int camera_id,int cam_open_nums);
     ~TestContext();
 
     size_t GetCamerasNum();
-    status_t FunctionalTest();
+    status_t FunctionalTest(int cam_open_nums);
     status_t AddScriptFromFile(const char *scriptFile);
     void setViVSize(Size VideoSize, int camIndex);
     void PiPLock();
     void PiPUnlock();
     void ViVLock();
     void ViVUnlock();
+    uint32_t  launch(void *(*start_routine)(void *),
+                                 void* user_data);
+    pthread_t cmd_pid;
+    static void * FunctionalTest_routine(void *data);
 
 private:
     sp<CameraContext> camera[MAX_CAM_INSTANCES];
@@ -356,6 +360,37 @@ private:
     ViVBuff_t mViVBuff;
 };
 
-}; //namespace qcamera
+typedef enum camera_open_mode{
+    SINGLE_MODE = 1,
+    PIP_MODE,		
+    DUAL_MODE,
+}camera_open_mode_t;
+
+typedef enum camera_id{
+    REAR_CAM = 0,
+    FRONT_CAM,
+}camera_id_t;
+
+class ConstChar {
+    public:
+	ConstChar(const char *data,int size){
+	    char * tchar  =new char[size];
+	    strncpy(tchar,data,size);
+	    m_data = tchar;
+	}
+	virtual ~ConstChar(){
+	    printf("%s destructed!\n",__func__);
+	    if(m_data){	
+	      delete m_data;
+	      m_data = NULL;
+	    }
+	}		
+	const char * tostring(){
+	    return m_data;
+	}
+    private:
+	const char *m_data;
 
+};
+}; //namespace qcamera




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值