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