camera小结

 
今年这两个月,一直都在搞camera。android的camera模块应该是比较熟悉了,刚好项目搞完,这里做一下总结。
 
camera是相机或平板必备的一个功能模块,拍照,录像确实很实用。
android 的 camera 分驱动层,HAL层,APP层。
底层一般都用V4L2封装,这样HAL可以通过V4L2标准接口对底层进行调用,读取数据。然后传给APP。
 
USB接口的camera module 一般都会支持UVC标准,UVC- USB Video Class。这种模块一般都由一个感光sensor + controller 组成。 这个controller 一般都会自带firmware。
 
拍照和录像里面有很多parameter setting. white balance, color effect, picture quality, video quality 等等。 这些都可以通过V4L2的标准IOCTL接口实现。
 
previewthread() 这个线程最重要,所有的功能都围绕这个线程工作。
 
camera模块不算太难,也不深,感觉还是挺简单的。这是我做android的第一个模块,下个项目要搞PMIC了,这模块会比较难,也比较深,涉及东西很多,搞懂了应该就成牛人了~

take picture 过程分析

这两天一直在调拍照,由于之前拍照照片的格式只支持VGA以下的,我拿我的pad一看,居然可以支持5M和1.3M,也就是前后摄像头的最大分辨率。这让我想到肯定是软件没做好,有待改善,然后这两天有空,就调了调。终于调出来了,一直卡在死锁状态。
由于软件功底不够,对于锁,没什么概念,还好最后还是搞出来了,过程真是痛苦啊。。


流程如下:
首先cameraservice 会调用  takepicture()。

[cpp] view plain copy print ?
  1. status_t CameraHardwareStub::takePicture()  
  2. {  
  3.     disableMsgType(CAMERA_MSG_PREVIEW_FRAME);  
  4.     if (createThread(beginPictureThread, this) == false)  
  5.         return UNKNOWN_ERROR;  
  6.     return NO_ERROR;  
  7. }  
[cpp] view plain copy print ?
  1. /*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)  
  2. {  
  3.     CameraHardwareStub *c = (CameraHardwareStub *)cookie;  
  4.     return c->pictureThread();  
  5. }  
[cpp] view plain copy print ?
  1. int CameraHardwareStub::pictureThread()  
  2. {  
  3.     int picture_width, picture_height;  
  4.     mParameters.getPictureSize(&picture_width, &picture_height);  
  5.     LOGD("picture size=%dx%d", picture_width, picture_height);  
  6.   
  7.     if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {  
  8.         LOGE("Take Picture COMPRESSED IMAGE");  
  9.   
  10.         /* 
  11.          * The takePicture() function called by the CameraService 
  12.          * must return synchronously without attempting to wait 
  13.          * for any locks, to prevent circular deadlocking in 
  14.          * attempting to call CameraService callbacks to deliver 
  15.          * frames. This includes waiting for the preview thread 
  16.          * to finish cleanly. So stopping the preview thread 
  17.          * is done in this separate pictureThread 
  18.          */  
  19.   
  20.         sp<PreviewThread> previewThread;  
  21.   
  22.         {  
  23.             Mutex::Autolock lock(mLock);  
  24.             previewThread = mPreviewThread;  
  25.         }  
  26.   
  27.         if (previewThread != 0) {  
  28.             previewThread->requestExitAndWait();  
  29.             Mutex::Autolock lock(mLock);  
  30.             mPreviewThread.clear();  
  31.         }  
  32.           
  33.         mFakeCamera->Uninit();  
  34.         mFakeCamera->StopStreaming(); //卸载掉preview 内存。   
  35.           
  36.         {  
  37.             mPictureLock.lock();  
  38.             mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mFakeCamera->GrabJpegFrame(picture_width, picture_height), mCallbackCookie);  
  39.             mPictureLock.unlock();  
  40.         }  
  41.     }  
  42.     return NO_ERROR;  
  43. }  
GrabJpegFrame 会具体执行拍照功能。

[cpp] view plain copy print ?
  1. sp<IMemory> V4L2Camera::GrabJpegFrame (int pic_width, int pic_height)  
  2. {  
  3.     FILE *output;  
  4.     FILE *input;  
  5.     int fileSize;  
  6.     int ret, i;  
  7.   
  8.     int w, h;  
  9.     struct v4l2_buffer v4l2_buf_picture;  
  10.     struct v4l2_format format;  
  11.     struct v4l2_streamparm parm;  
  12.     struct v4l2_requestbuffers reqbuf;  
  13.     sp<MemoryHeapBase> rawPictureHeap;  
  14.     sp<MemoryHeapBase> mjpegPictureHeap;  
  15.     sp<MemoryBase> jpegMemBase;  
  16.   
  17.     /* VIDIOC_S_FMT */  
  18.     memset(&format, 0, sizeof(format));  
  19.     format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  20.     format.fmt.pix.width = pic_width;  
  21.     format.fmt.pix.height = pic_height;  
  22.     format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;  
  23.     if (ioctl(fd, VIDIOC_S_FMT, &format) < 0)  
  24.     {  
  25.         LOGE("Error: VIDIOC_S_FMT");  
  26.         goto done;  
  27.     }  
  28.   
  29.     /* VIDIOC_S_PARM */  
  30.     memset(&parm, 0, sizeof(parm));  
  31.     parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  32.     parm.parm.capture.timeperframe.numerator = 2;  
  33.     parm.parm.capture.timeperframe.denominator = 15;  
  34.     if (ioctl(fd, VIDIOC_S_PARM, &parm) < 0)  
  35.     {  
  36.         LOGE("Error: VIDIOC_S_PARM");  
  37.         goto done;  
  38.     }  
  39.   
  40.     /* VIDIOC_REQBUFS */  
  41.     memset(&reqbuf, 0, sizeof(reqbuf));  
  42.     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  43.     reqbuf.memory = V4L2_MEMORY_MMAP;  
  44.     reqbuf.count = 1;  
  45.     if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0)  
  46.     {  
  47.         LOGE ("Error: VIDIOC_REQBUFS");  
  48.         goto done;  
  49.     }  
  50.   
  51.     memset(&v4l2_buf_picture, 0, sizeof(v4l2_buf_picture));  
  52.     v4l2_buf_picture.index = 0;  
  53.     v4l2_buf_picture.type = reqbuf.type;  
  54.     if (ioctl(fd, VIDIOC_QUERYBUF, &v4l2_buf_picture) < 0)  
  55.     {  
  56.         LOGE("Error: VIDIOC_QUERYBUF");  
  57.         goto done;  
  58.     }  
  59.   
  60.     /* use MemoryHeapBase to do mmap */  
  61.     rawPictureHeap = new MemoryHeapBase(fd,  
  62.             v4l2_buf_picture.length, 0, v4l2_buf_picture.m.offset);  
  63.     if (rawPictureHeap == NULL)  
  64.     {  
  65.         LOGE("Error: Cannot create rawPictureHeap");  
  66.         goto done;  
  67.     }  
  68.   
  69.     /* VIDIOC_QBUF */  
  70.     if (ioctl(fd, VIDIOC_QBUF, &v4l2_buf_picture) < 0)  
  71.     {  
  72.         LOGE("Error: VIDIOC_QBUF");  
  73.     }  
  74.     StartStreaming();  
  75.   
  76.     for(i = 0; i < PICTURE_FRAME_GRAB_COUNT; i++){  
  77.         /* get one frame from camera */  
  78.         if (ioctl(fd, VIDIOC_DQBUF, &v4l2_buf_picture) < 0){  
  79.             LOGE("Error: VIDIOC_DQBUF");  
  80.             goto done;  
  81.         }  
  82.         if((ioctl(fd, VIDIOC_QBUF, &v4l2_buf_picture)) < 0){  
  83.             LOGE("Error: VIDIOC_QBUF = %d:%d", ret, errno);  
  84.         }  
  85.         usleep(50*1000);  
  86.     }  
  87.       
  88.     output = fopen("/data/tmp.jpg""wb");  
  89.   
  90.     if (output == NULL) {  
  91.         LOGE("GrabJpegFrame: Ouput file == NULL");  
  92.         return NULL;  
  93.     }  
  94.   
  95.     fileSize = saveYUYVtoJPEG((unsigned char *)rawPictureHeap->getBase(), pic_width, pic_height, output, 85);  
  96.   
  97.     fclose(output);  
  98.   
  99.     input = fopen("/data/tmp.jpg""rb");  
  100.   
  101.     if (input == NULL)  
  102.         LOGE("GrabJpegFrame: Input file == NULL");  
  103.     else {  
  104.         mjpegPictureHeap = new MemoryHeapBase(fileSize);  
  105.         jpegMemBase = new MemoryBase(mjpegPictureHeap, 0, fileSize);  
  106.   
  107.         fread((uint8_t *)mjpegPictureHeap->base(), 1, fileSize, input);  
  108.         fclose(input);  
  109.   
  110.         rawPictureHeap.clear();  
  111.         StopStreaming();  
  112.         return jpegMemBase;  
  113.     }  
  114.   
  115. done:  
  116.     rawPictureHeap.clear();  
  117.     StopStreaming();  
  118.     return NULL;  
  119. }  
  120.   
  121. int V4L2Camera::saveYUYVtoJPEG (unsigned char *inputBuffer, int width, int height, FILE *file, int quality)  
  122. {  
  123.     struct jpeg_compress_struct cinfo;  
  124.     struct jpeg_error_mgr jerr;  
  125.     JSAMPROW row_pointer[1];  
  126.     unsigned char *line_buffer, *yuyv;  
  127.     int z;  
  128.     int fileSize;  
  129.   
  130.     line_buffer = (unsigned char *) calloc (width * 3, 1);  
  131.     yuyv = inputBuffer;  
  132.   
  133.     cinfo.err = jpeg_std_error (&jerr);  
  134.     jpeg_create_compress (&cinfo);  
  135.     jpeg_stdio_dest (&cinfo, file);  
  136.   
  137.     LOGI("JPEG PICTURE WIDTH AND HEIGHT: %dx%d", width, height);  
  138.   
  139.     cinfo.image_width = width;  
  140.     cinfo.image_height = height;  
  141.     cinfo.input_components = 3;  
  142.     cinfo.in_color_space = JCS_RGB;  
  143.   
  144.     jpeg_set_defaults (&cinfo);  
  145.     jpeg_set_quality (&cinfo, quality, TRUE);  
  146.   
  147.     jpeg_start_compress (&cinfo, TRUE);  
  148.   
  149.     z = 0;  
  150.     while (cinfo.next_scanline < cinfo.image_height) {  
  151.         int x;  
  152.         unsigned char *ptr = line_buffer;  
  153.   
  154.         for (x = 0; x < width; x++) {  
  155.             int r, g, b;  
  156.             int y, u, v;  
  157.   
  158.             if (!z)  
  159.                 y = yuyv[0] << 8;  
  160.             else  
  161.                 y = yuyv[2] << 8;  
  162.   
  163.             u = yuyv[1] - 128;  
  164.             v = yuyv[3] - 128;  
  165.   
  166.             r = (y + (359 * v)) >> 8;  
  167.             g = (y - (88 * u) - (183 * v)) >> 8;  
  168.             b = (y + (454 * u)) >> 8;  
  169.   
  170.             *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);  
  171.             *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);  
  172.             *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);  
  173.   
  174.             if (z++) {  
  175.                 z = 0;  
  176.                 yuyv += 4;  
  177.             }  
  178.         }  
  179.   
  180.         row_pointer[0] = line_buffer;  
  181.         jpeg_write_scanlines (&cinfo, row_pointer, 1);  
  182.     }  
  183.   
  184.     jpeg_finish_compress (&cinfo);  
  185.     fileSize = ftell(file);  
  186.     jpeg_destroy_compress (&cinfo);  
  187.   
  188.     free (line_buffer);  
  189.   
  190.     return fileSize;  
  191. }  
下面这个函数,可以查询摄像头模块支持哪些照片的尺寸:
[cpp] view plain copy print ?
  1. String8 V4L2Camera::GetSupportPictureSize(int fd, int pixelformat, int &w, int &h)  
  2. {  
  3.     LOGD("%s", __func__);  
  4.     String8 size_list;  
  5.     struct v4l2_frmsizeenum framesize_enum;  
  6.     memset(&framesize_enum, 0, sizeof(framesize_enum));  
  7.     framesize_enum.index = 0;  
  8.     framesize_enum.pixel_format = pixelformat;  
  9.     int ret = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize_enum);  
  10.     if (ret < 0) {  
  11.         LOGE("Error: VIDIOC_ENUM_FRAMESIZES - %s", strerror(errno));  
  12.         return size_list;  
  13.     }  
  14.     switch(framesize_enum.type)  
  15.     {  
  16.         case V4L2_FRMSIZE_TYPE_DISCRETE:  
  17.             do {  
  18.             if (framesize_enum.index) {  
  19.                 w = framesize_enum.discrete.width;  
  20.                 h = framesize_enum.discrete.height;  
  21.             }  
  22.             size_list.appendFormat(  
  23.                     framesize_enum.index ? ",%dx%d" : "%dx%d",  
  24.                     framesize_enum.discrete.width,  
  25.                     framesize_enum.discrete.height);  
  26.             framesize_enum.index++;  
  27.             ret = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize_enum);  
  28.         } while (ret >= 0);  
  29.         LOGD("Supported sizes string: %s", size_list.string());  
  30.         break;  
  31.         case V4L2_FRMSIZE_TYPE_STEPWISE:  
  32.         case V4L2_FRMSIZE_TYPE_CONTINUOUS:  
  33.             LOGD("STEPWISE/CONTINUOUS ignored: %dx%d-%dx%d/%dx%d",  
  34.                 framesize_enum.stepwise.min_width,  
  35.                 framesize_enum.stepwise.min_height,  
  36.                 framesize_enum.stepwise.max_width,  
  37.                 framesize_enum.stepwise.max_height,  
  38.                 framesize_enum.stepwise.step_width,  
  39.                 framesize_enum.stepwise.step_height);  
  40.             break;  
  41.         default:  
  42.            LOGE("Unknown format type: %d!!!", framesize_enum.type);  
  43.     }  
  44.     return size_list;  

camera recording流程

分类: Camera 140人阅读 评论(0) 收藏 举报

开始app调用到cameraservices

[cpp] view plain copy print ?
  1. // start recording mode   
  2.   
  3. status_t CameraService::Client::startRecording() {  
  4.     LOG1("startRecording (pid %d)", getCallingPid());  
  5.     return startCameraMode(CAMERA_RECORDING_MODE);  
  6. }  
  7.   
  8. // start preview or recording   
  9.   
  10. status_t CameraService::Client::startCameraMode(camera_mode mode) {  
  11.     LOG1("startCameraMode(%d)", mode);  
  12.     Mutex::Autolock lock(mLock);  
  13.     status_t result = checkPidAndHardware();  
  14.     if (result != NO_ERROR) return result;  
  15.   
  16.     switch(mode) {  
  17.         case CAMERA_PREVIEW_MODE:  
  18.             if (mSurface == 0) {  
  19.                 LOG1("mSurface is not set yet.");  
  20.                 // still able to start preview in this case.   
  21.   
  22.             }  
  23.             return startPreviewMode();  
  24.         case CAMERA_RECORDING_MODE:  
  25.             if (mSurface == 0) {  
  26.                 LOGE("mSurface must be set before startRecordingMode.");  
  27.                 return INVALID_OPERATION;  
  28.             }  
  29.             return startRecordingMode();  
  30.         default:  
  31.             return UNKNOWN_ERROR;  
  32.     }  
  33. }  

[cpp] view plain copy print ?
  1. status_t CameraService::Client::startRecordingMode() {  
  2.     LOG1("startRecordingMode");  
  3.     status_t result = NO_ERROR;  
  4.   
  5.     // if recording has been enabled, nothing needs to be done   
  6.   
  7.     if (mHardware->recordingEnabled()) {  
  8.         return NO_ERROR;  
  9.     }  
  10.   
  11.     // if preview has not been started, start preview first   
  12.   
  13.     if (!mHardware->previewEnabled()) {  
  14.         result = startPreviewMode();  
  15.         if (result != NO_ERROR) {  
  16.             return result;  
  17.         }  
  18.     }  
  19.   
  20.     // start recording mode   
  21.   
  22.     enableMsgType(CAMERA_MSG_VIDEO_FRAME);  
  23.     mCameraService->playSound(SOUND_RECORDING);  
  24.     result = mHardware->startRecording();  //调用hal recording.   
  25.     if (result != NO_ERROR) {  
  26.         LOGE("mHardware->startRecording() failed with status %d", result);  
  27.     }  
  28.     return result;  
  29. }  
调用HAL 层的 previewthread 线程:
[cpp] view plain copy print ?
  1. if (mRecordRunning == true && mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) {  
  2. 263 yuyv422_to_yuv420sp((unsigned char *)rawFramePointer,  
  3. 264 (unsigned char *)mRecordingHeap->getBase(),  
  4. 265 preview_width, preview_height);  
  5. 266 LOGE(" ------- mRecordRunning --------");  
  6. 267 mDataCbTimestamp(systemTime(SYSTEM_TIME_MONOTONIC), CAMERA_MSG_VIDEO_FRAME, mRecordingBuffer, mCallbackCookie);  
  7. 268 }  
使用回调函数: 回调到cameraservices .

[cpp] view plain copy print ?
  1. void CameraService::Client::dataCallbackTimestamp(nsecs_t timestamp,  
  2.         int32_t msgType, const sp<IMemory>& dataPtr, void* user) {  
  3.     LOG2("dataCallbackTimestamp(%d)", msgType);  
  4.   
  5.     sp<Client> client = getClientFromCookie(user);  
  6.     if (client == 0) return;  
  7.     if (!client->lockIfMessageWanted(msgType)) return;  
  8.   
  9.     if (dataPtr == 0) {  
  10.         LOGE("Null data returned in data with timestamp callback");  
  11.         client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);  
  12.         return;  
  13.     }  
  14.   
  15.     client->handleGenericDataTimestamp(timestamp, msgType, dataPtr);  
  16. }  
数据传给 client->handleGenericDataTimestamp(timestamp, msgType, dataPtr)
[cpp] view plain copy print ?
  1. void CameraService::Client::handleGenericDataTimestamp(nsecs_t timestamp,  
  2.     int32_t msgType, const sp<IMemory>& dataPtr) {  
  3.     sp<ICameraClient> c = mCameraClient;  
  4.     mLock.unlock();  
  5.     if (c != 0) {  
  6.         c->dataCallbackTimestamp(timestamp, msgType, dataPtr);  
  7.     }  
  8. }  
传给 frameworks/base/libs/camera/Camera.cpp
[cpp] view plain copy print ?
  1. // callback from camera service when timestamped frame is ready   
  2.   
  3. void Camera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)  
  4. {  
  5.     sp<CameraListener> listener;  
  6.     {  
  7.         Mutex::Autolock _l(mLock);  
  8.         listener = mListener;  
  9.     }  
  10.     if (listener != NULL) {  
  11.         listener->postDataTimestamp(timestamp, msgType, dataPtr);  
  12.     }  
  13. }  
调用到 frameworks/base/media/libstagefright/CameraSource.cpp
frameworks/base/libs/camera/ICameraClient.cpp

 

你可能感兴趣的:(Camera)