CameraHal.h:
- classCameraHal:publicCameraHardwareInterface{
- public:
- virtualsp<IMemoryHeap>getPreviewHeap()const;
- virtualsp<IMemoryHeap>getRawHeap()const;
- virtualvoidsetCallbacks(notify_callbacknotify_cb,
- data_callbackdata_cb,
- data_callback_timestampdata_cb_timestamp,
- void*user);
- virtualvoidenableMsgType(int32_tmsgType);
- virtualvoiddisableMsgType(int32_tmsgType);
- virtualboolmsgTypeEnabled(int32_tmsgType);
- virtualbooluseOverlay(){returntrue;}
- virtualstatus_tsetOverlay(constsp<Overlay>&overlay);
- virtualstatus_tstartPreview();
- virtualvoidstopPreview();
- virtualboolpreviewEnabled();
- virtualstatus_tstartRecording();
- virtualvoidstopRecording();
- virtualboolrecordingEnabled();
- virtualvoidreleaseRecordingFrame(constsp<IMemory>&mem);
- virtualstatus_tautoFocus();
- virtualstatus_tcancelAutoFocus();
- virtualstatus_ttakePicture();
- virtualstatus_tcancelPicture();
- virtualstatus_tdump(intfd,constVector<String16>&args)const;
- virtualstatus_tsetParameters(constCameraParameters¶ms);
- virtualCameraParametersgetParameters()const;
- virtualstatus_tsendCommand(int32_tcommand,int32_targ1,
- int32_targ2);
- virtualvoidrelease();
- CAMERA_HAL_ERR_RETsetCaptureDevice(sp<CaptureDeviceInterface>capturedevice);
- CAMERA_HAL_ERR_RETsetPostProcessDevice(sp<PostProcessDeviceInterface>postprocessdevice);
- CAMERA_HAL_ERR_RETsetJpegEncoder(sp<JpegEncoderInterface>jpegencoder);
- CAMERA_HAL_ERR_RETInit();
- voidsetPreviewRotate(CAMERA_PREVIEW_ROTATEpreviewRotate);
- CameraHal();
- virtual~CameraHal();
- private:
- //私有的成员太多就不列了
- };
getPreiwHeap: 获取preview data所在的内存地址。
这里有个类MemroyHeapBase,它是Android搞的一套基于Binder机制的对内存操作的类。用于创建共享内存。
- sp<IMemoryHeap>CameraHal::getPreviewHeap()const
- {
- CAMERA_HAL_LOG_FUNC;
- returnmPreviewHeap;
- }
mPreviewHeap 初始化:
- status_tCameraHal::PreparePreviwBuf()
- {
- CAMERA_HAL_LOG_FUNC;
- status_tret=NO_ERROR;
- unsignedinti=0;
- //templyhardcodehere
- if(mTakePicFlag==0){
- if(V4L2_PIX_FMT_NV12)
- mPreviewFrameSize=mCaptureDeviceCfg.width*mCaptureDeviceCfg.height*3/2;
- else
- mPreviewFrameSize=mCaptureDeviceCfg.width*mCaptureDeviceCfg.height*2;//获取preview帧大小
- //nowthepreviewfmtissupposedtobeYUV420SP,so,itisnowhardcodehere
- mPreviewHeap.clear();
- for(i=0;i<mPreviewHeapBufNum;i++)
- mPreviewBuffers[i].clear();
- mPreviewHeap=newMemoryHeapBase(mPreviewFrameSize*mPreviewHeapBufNum);
- if(mPreviewHeap==NULL)
- returnNO_MEMORY;
- for(i=0;i<mPreviewHeapBufNum;i++)
- mPreviewBuffers[i]=newMemoryBase(mPreviewHeap,mPreviewFrameSize*i,mPreviewFrameSize);
- }
- /*allocatethebufferforIPUprocess*/
- if(mPPDeviceNeed||mPPDeviceNeedForPic){
- mPmemAllocator=newPmemAllocator(mPPbufNum,mCaptureFrameSize);
- if(mPmemAllocator==NULL||mPmemAllocator->err_ret<0){
- returnNO_MEMORY;
- }
- for(i=0;i<mPPbufNum;i++){
- if(mPmemAllocator->allocate(&(mPPbuf[i]),mCaptureFrameSize)<0){
- returnNO_MEMORY;
- }
- }
- }
- returnret;
- }
- sp<IMemoryHeap>CameraHal::getRawHeap()const
- {
- returnNULL;
- }
- voidCameraHal::setCallbacks(notify_callbacknotify_cb,
- data_callbackdata_cb,
- data_callback_timestampdata_cb_timestamp,
- void*user)
- {
- Mutex::Autolocklock(mLock);
- mNotifyCb=notify_cb;
- mDataCb=data_cb;
- mDataCbTimestamp=data_cb_timestamp;
- mCallbackCookie=user;
- }
- /*
- 注册callback函数,callback的作用是在进行某些操作是可以返回相关的数据,例如takePicture时:
- 调用mDataCb(CAMERA_MSG_COMPRESSED_IMAGE,JpegMemBase,mCallbackCookie);则是告诉上层应用现在返回压缩好的jpeg数据(数据在JpegMemBase中)
- 但其实mx53的preiw是用overlay做,data_cb在preiw是没用
- */
virtual void enableMsgType(int32_t msgType);
virtual void disableMsgType(int32_t msgType);
virtual bool msgTypeEnabled(int32_t msgType);
这三个函数是设定在按下快门或对焦好或拍好照等之后要不要把相关的信息告诉上层(调用相关的callback)
virtual bool useOverlay() { return true; }
virtual status_t setOverlay(const sp<Overlay> &overlay);
使用overlay, overlay的概念? 太多内容了,简单地说就是把camera的数据直接写到framebuffer 而不经过android层,这在preview中很有用
这里有编博文可以参考http://zhougaofeng.ixiezi.com/2009/12/02/android-camera-preview-and-take-picture-with-v4l2/
virtual status_t startPreview();
看名称就知道是开始preview:
主要实现:
- status_tCameraHal::CameraHALStartPreview()
- {
- CAMERA_HAL_LOG_FUNC;
- status_tret=NO_ERROR;
- intmax_fps,min_fps;
- //一些基本参数,大小,旋转,名字(因为可能有多个camera)
- mParameters.getPreviewSize((int*)&(mCaptureDeviceCfg.width),(int*)&(mCaptureDeviceCfg.height));
- mCaptureDeviceCfg.fmt=mPreviewCapturedFormat;
- mCaptureDeviceCfg.rotate=(SENSOR_PREVIEW_ROTATE)mPreviewRotate;
- mCaptureDeviceCfg.tv.numerator=1;
- mCaptureDevice->GetDevName(mCameraSensorName);
- //camera有uvc和csi两种,具体是什么有什么区别我还真不知道
- if(strstr(mCameraSensorName,"uvc")==NULL){
- //accordingtogoogle'sdocgetPreviewFrameRate&getPreviewFpsRangeshouldsupportboth.
- //soherejustawalkaround,iftheappsettheframeRate,willfollowthisframerate.
- if(mParameters.getPreviewFrameRate()>=15)
- mCaptureDeviceCfg.tv.denominator=mParameters.getPreviewFrameRate();
- else{
- mParameters.getPreviewFpsRange(&min_fps,&max_fps);
- CAMERA_HAL_LOG_INFO("###startthecapturethefpsis%d###",max_fps);
- mCaptureDeviceCfg.tv.denominator=max_fps/1000;
- }
- }else{
- mCaptureDeviceCfg.tv.denominator=15;
- }
- mCaptureBufNum=PREVIEW_CAPTURE_BUFFER_NUM;
- mPPbufNum=POST_PROCESS_BUFFER_NUM;
- mTakePicFlag=false;
- //上一篇博文(驱动部分)有提到camerav4l2的使用
- if((ret=PrepareCaptureDevices())<0){
- CAMERA_HAL_ERR("PrepareCaptureDeviceserror");
- returnret;
- }
- if(mPPDeviceNeed){
- //预处理?不清楚。
- if((ret=PreparePostProssDevice())<0){
- CAMERA_HAL_ERR("PreparePostProssDeviceerror");
- returnret;
- }
- }
- if((ret=PreparePreviwBuf())<0){
- CAMERA_HAL_ERR("PreparePreviwBuferror");
- returnret;
- }
- //注册一下锁变量,主要是为了overlay和capture不冲突
- if((ret=PreparePreviwMisc())<0){
- CAMERA_HAL_ERR("PreparePreviwMiscerror");
- returnret;
- }
- //
- if((ret=CameraHALPreviewStart())<0){
- CAMERA_HAL_ERR("CameraHALPreviewStarterror");
- returnret;
- }
- returnret;
- }
- status_tCameraHal::CameraHALPreviewStart()
- {
- CAMERA_HAL_LOG_FUNC;
- status_tret=NO_ERROR;
- if(mCaptureDevice->DevStart()<0)//就是ioctl(mCameraDevice,VIDIOC_STREAMON,&type),此处fslmx53支持同时打开overlay和capture
- returnINVALID_OPERATION;
- mCaptureFrameThread=newCaptureFrameThread(this);
- mPreviewShowFrameThread=newPreviewShowFrameThread(this);
- mEncodeFrameThread=newEncodeFrameThread(this);
- if(mPPDeviceNeed){
- mPostProcessThread=newPostProcessThread(this);
- if(mPostProcessThread==NULL)
- returnUNKNOWN_ERROR;
- }
- if(mCaptureFrameThread==NULL||
- mPreviewShowFrameThread==NULL||
- mEncodeFrameThread==NULL){
- returnUNKNOWN_ERROR;
- }
- mPreviewRunning=true;
- returnret;
- }
- //上面函数的4条thread,其中postprocessthread没看不明白是做什么的(自动对焦?),下面稍微解析一下capture和showthread
- intCameraHal::captureframeThread()
- {
- CAMERA_HAL_LOG_FUNC;
- unsignedintDeqBufIdx=0;
- structtimespects;
- do{
- clock_gettime(CLOCK_REALTIME,&ts);
- ts.tv_nsec+=100000;//100ms
- }while(mPreviewRunning&&!error_status&&(sem_timedwait(&avab_dequeue_frame,&ts)!=0));
- //因为是几条thread一起工作,当然要做同步啦,其中avab_dequeue_frame就要去DevQueue之后才avaliable
- if(!mPreviewRunning||error_status)
- returnUNKNOWN_ERROR;
- mCaptureDevice->DevDequeue(&DeqBufIdx);//这个当然就是capture一帧数据到buffer中以备后用
- nCameraBuffersQueued--;
- buffer_index_maps[dequeue_head]=DeqBufIdx;//PrepareCaptureDevices时会query几个buffer,这里记住他的index
- dequeue_head++;
- dequeue_head%=mCaptureBufNum;
- //下面是同步的东西,没什么好说的。
- if(!mPPDeviceNeed){
- sem_post(&avab_show_frame);
- sem_post(&avab_enc_frame);
- }else{
- sem_post(&avab_pp_in_frame);
- }
- returnNO_ERROR;
- }
- intCameraHal::previewshowFrameThread()
- {
- CAMERA_HAL_LOG_FUNC;
- structtimespects;
- intdisplay_index=0;
- DMA_BUFFERInBuf;
- intqueue_back_index=0;
- do{
- clock_gettime(CLOCK_REALTIME,&ts);
- ts.tv_nsec+=100000;//100ms
- }while(!error_status&&mPreviewRunning&&(sem_timedwait(&avab_show_frame,&ts)!=0));
- if((mPreviewRunning==0)||error_status)
- returnUNKNOWN_ERROR;
- if(!mPPDeviceNeed){
- display_index=buffer_index_maps[display_head];
- InBuf=mCaptureBuffers[display_index];
- display_head++;
- display_head%=mCaptureBufNum;
- }else{
- display_index=display_head;
- InBuf=mPPbuf[display_index];
- display_head++;
- display_head%=mPPbufNum;
- }
- if(mMsgEnabled&CAMERA_MSG_PREVIEW_FRAME){
- convertNV12toYUV420SP((uint8_t*)(InBuf.virt_start),
- (uint8_t*)(mPreviewBuffers[preview_heap_buf_head]->pointer()),mCaptureDeviceCfg.width,mCaptureDeviceCfg.height);
- mDataCb(CAMERA_MSG_PREVIEW_FRAME,mPreviewBuffers[preview_heap_buf_head],mCallbackCookie);
- preview_heap_buf_head++;
- preview_heap_buf_head%=mPreviewHeapBufNum;
- }
- pthread_mutex_lock(&mOverlayMutex);
- if(mOverlay!=0){
- InBuf是从capture中QueueBuffer来的,放进了overlay之后怎么做其实没有看懂,fsl这方面写得很复杂,只知道它初始化时就分配了共享内存
- //ctx->data_shared,然后把buffer的地址传进去data_shared->queued_bufs[data_shared->queued_tail]=phy_addr,而有个很纠结的事情
- //是,它只调用了queueBuffer而没有调用DqueueBuffer,overlay中有一条专门的thread去处理queueBuffer后的数据。
- if(mOverlay->queueBuffer((overlay_buffer_t)InBuf.phy_offset)<0){
- CAMERA_HAL_ERR("queueBufferfailed.Maybebcosstreamwasnotturnedonyet.");
- }
- if(is_first_buffer){
- is_first_buffer=0;
- last_display_index=display_index;
- pthread_mutex_unlock(&mOverlayMutex);
- gotoshow_out;
- }
- }
- if(!mPPDeviceNeed){
- if(mOverlay!=0){
- queue_back_index=last_display_index;
- }else{
- queue_back_index=display_index;
- }
- }
- pthread_mutex_unlock(&mOverlayMutex);
- do{
- clock_gettime(CLOCK_REALTIME,&ts);
- ts.tv_nsec+=200000;//100ms
- }while((sem_timedwait(&avab_enc_frame_finish,&ts)!=0)&&!error_status&&mPreviewRunning);
- if(!mPPDeviceNeed){
- //queuethev4l2bufback
- if(mCaptureDevice->DevQueue(queue_back_index)<0){
- CAMERA_HAL_ERR("TheCapturedevicequeuebuferror!!!!");
- returnINVALID_OPERATION;
- }
- last_display_index=display_index;
- nCameraBuffersQueued++;
- sem_post(&avab_dequeue_frame);
- }else{
- sem_post(&avab_pp_out_frame);
- }
- show_out:
- returnNO_ERROR;
- }