Android S5PV210 cameraHAL 录像功能分析

来源:互联网 发布:windows 10 version 编辑:程序博客网 时间:2024/05/20 08:28

/**********************************************************************************

转自:http://blog.csdn.net/kickxxx/article/details/7793843

关键字:SecCameraHWInterface

***********************************************************************************/

Camera系统进行视频录制的过程,涉及到camera driver,camera HAL,camera Service,camera Java 几层

camera 录像功能一般是和preview功能同时进行的,samsung HAL的录像线程是借助preview线程来实现的,在这个线程中FIMC0获取preview使用的原始数据,同时FIMC2获取录像需要的原始数据,这里之所以使用两个FIMC获取数据,我想是因为preview和录像需要的原始数据是有差异的,而S5PV210恰好又支持两个fimc控制器同时输出一个sensor的BT656信号。


libcamera/SecCameraHWInterface.cpp

[cpp] view plaincopy
  1. 802 status_t CameraHardwareSec::startRecording()  
  2. 803 {  
  3. 804     LOGV("%s :", __func__);  
  4. 805   
  5. 806     if (mRecordRunning == false) {  
  6. 807         if (mSecCamera->startRecord() < 0) {  
  7. 808             LOGE("ERR(%s):Fail on mSecCamera->startRecord()", __func__);  
  8. 809             // sw5771.park : temporary fix  
  9. 810             //               with HDMI, fimc2 is conflict...  
  10. 811 #ifdef BOARD_USES_HDMI  
  11. 812 #else  
  12. 813             return UNKNOWN_ERROR;  
  13. 814 #endif  
  14. 815         }  
  15. 816         mRecordRunning = true;  
  16. 817     }  
  17. 818     return NO_ERROR;  
  18. 819 }  

807 mSecCamera->startRecord 设置并启动recording对应的fimc控制器

816 设置启动标志,previewThread线程中会通过mRecordRunning判断是否需要录像处理


libcamera/SecCamera.cpp:SecCamera::startRecord()

[cpp] view plaincopy
  1. 1084 int SecCamera::startRecord(void)  
  2. 1085 {  
  3. 1086     int ret, i;  
  4. 1087   
  5. 1088     LOGV("%s :", __func__);  
  6. 1089   
  7. 1090     // aleady started  
  8. 1091     if (m_flag_record_start > 0) {  
  9. 1092         LOGE("ERR(%s):Recording was already started\n", __func__);  
  10. 1093         return 0;  
  11. 1094     }  
  12. 1095   
  13. 1096     if (m_cam_fd2 <= 0) {  
  14. 1097         LOGE("ERR(%s):Camera was closed\n", __func__);  
  15. 1098         return -1;  
  16. 1099     }  
  17. 1100   
  18. 1101     /* enum_fmt, s_fmt sample */  
  19. 1102     ret = fimc_v4l2_enum_fmt(m_cam_fd2, V4L2_PIX_FMT_NV12T);  
  20. 1103     CHECK(ret);  
  21. 1104   
  22. 1105     LOGI("%s: m_recording_width = %d, m_recording_height = %d\n",  
  23. 1106          __func__, m_recording_width, m_recording_height);  
  24. 1107   
  25. 1108     ret = fimc_v4l2_s_fmt(m_cam_fd2, m_recording_width, m_recording_height,  
  26. 1109                           V4L2_PIX_FMT_NV12T, 0);  
  27. 1110     CHECK(ret);  
  28. 1111   
  29. 1112     ret = fimc_v4l2_reqbufs(m_cam_fd2, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS);  
  30. 1113     CHECK(ret);  
  31. 1114   
  32. 1115     ret = this->m_setCameraAngle(m_cam_fd2);  
  33. 1116     CHECK(ret);  
  34. 1117   
  35. 1118     /* start with all buffers in queue */  
  36. 1119     for (i = 0; i < MAX_BUFFERS; i++) {  
  37. 1120         ret = fimc_v4l2_qbuf(m_cam_fd2, i);  
  38. 1121         CHECK(ret);  
  39. 1122     }  
  40. 1123   
  41. 1124     ret = fimc_v4l2_streamon(m_cam_fd2);  
  42. 1125     CHECK(ret);  
  43. 1126   
  44. 1127     // Get and throw away the first frame since it is often garbled.  
  45. 1128     memset(&m_events_c2, 0, sizeof(m_events_c2));  
  46. 1129     m_events_c2.fd = m_cam_fd2;  
  47. 1130     m_events_c2.events = POLLIN | POLLERR;  
  48. 1131     ret = fimc_poll(&m_events_c2);  
  49. 1132     CHECK(ret);  
  50. 1133   
  51. 1134     m_flag_record_start = 1;  
  52. 1135   
  53. 1136     LOGE("(%s): end\n", __func__);  
  54. 1137     return 0;  
  55. 1138 }  

1102 检查设备是否支持NV12T格式,这里使用的是m_cam_fd2,对应着FIMC2控制器

接下来的流程类似于普通拍照时camera设备的初始化流程

1108 ~ 1109 设置录像的宽度,高度和格式

1112 申请拍照用的queue buffer

1118 ~ 1112 把这些buffer加入等待队列

1124 启动FIMC2的capture stream on 模式,FIMC2开始抓取数据,FIMC2每获取一帧数据都会唤醒调用fimc_poll阻塞的进程

1128 ~ 1132 等待第一帧的到来,并且忽略掉,因为第一帧的数据经常错乱


[cpp] view plaincopy
  1. 821 void CameraHardwareSec::stopRecording()  
  2. 822 {  
  3. 823     LOGV("%s :", __func__);  
  4. 824   
  5. 825     if (mRecordRunning == true) {  
  6. 826         if (mSecCamera->stopRecord() < 0) {  
  7. 827             LOGE("ERR(%s):Fail on mSecCamera->stopRecord()", __func__);  
  8. 828             return;  
  9. 829         }  
  10. 830         mRecordRunning = false;  
  11. 831     }  
  12. 832 }  

826 停止FIMC2设备的capture stream

830 mRecordRunning = false,会停止previewThread中针对record的处理


[cpp] view plaincopy
  1. 841 void CameraHardwareSec::releaseRecordingFrame(const sp<IMemory>& mem)  
  2. 842 {  
  3. 843     ssize_t offset;  
  4. 844     sp<IMemoryHeap> heap = mem->getMemory(&offset, NULL);  
  5. 845     struct ADDRS *addrs = (struct ADDRS *)((uint8_t *)heap->base() + offset);  
  6. 846  
  7. 847     mSecCamera->releaseRecordFrame(addrs->buf_idx);  
  8. 848 }  

buffer数据要传送给上层处理,在上层处理完之前,驱动层和HAL不能修改这个buffer,直到上层应用调用releaseRecordingFrame接口释放buffer

847 mSecCamera->releaseRecordFrame会把addrs->buf_idx对应的buffer加到队列中

[cpp] view plaincopy
  1.  542 int CameraHardwareSec::previewThread()  
  2.  543 {  
  3.  544     int index;  
  4.  545     nsecs_t timestamp;  
  5.  546     unsigned int phyYAddr;  
  6.  547     unsigned int phyCAddr;  
  7.  548     struct ADDRS *addrs;  
  8.  549   
  9.  550     index = mSecCamera->getPreview();  
  10.  551     if (index < 0) {  
  11.  552         LOGE("ERR(%s):Fail on SecCamera->getPreview()", __func__);  
  12.  553         return UNKNOWN_ERROR;  
  13.  554     }  
  14.  555     mSkipFrameLock.lock();  
  15.  556     if (mSkipFrame > 0) {  
  16.  557         mSkipFrame--;  
  17.  558         mSkipFrameLock.unlock();  
  18.  559         return NO_ERROR;  
  19.  560     }  
  20.  561     mSkipFrameLock.unlock();  
  21.  562     gInterlace++;  
  22.  563     //if (gInterlace % 8) {  
  23.  564     //  return NO_ERROR;  
  24.  565     //}  
  25.  566   
  26.  567     timestamp = systemTime(SYSTEM_TIME_MONOTONIC);  
  27.  568   
  28.  569     phyYAddr = mSecCamera->getPhyAddrY(index);  
  29.  570     phyCAddr = mSecCamera->getPhyAddrC(index);  
  30.  571   
  31.  572     if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) {  
  32.  573         LOGE("ERR(%s):Fail on SecCamera getPhyAddr Y addr = %0x C addr = %0x", __func__, phyYAddr, phyCAddr);  
  33.  574         return UNKNOWN_ERROR;  
  34.  575      }  
  35.  576  
  36.  577     int width, height, frame_size, offset;  
  37.  578   
  38.  579     mSecCamera->getPreviewSize(&width, &height, &frame_size);  
  39.  580   
  40.  581     offset = (frame_size + mSizeOfADDRS) * index;  
  41.  582     sp<MemoryBase> buffer = new MemoryBase(mPreviewHeap, offset, frame_size);  
  42.  583   
  43.  584     memcpy(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size    ), &phyYAddr, 4);  
  44.  585     memcpy(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size + 4), &phyCAddr, 4);  
  45.  586   
  46.  587 #if defined(BOARD_USES_OVERLAY)  
  47.  588     if (mUseOverlay) {  
  48.  589         int ret;  
  49.  590         overlay_buffer_t overlay_buffer;  
  50.  591   
  51.  592         mOverlayBufferIdx ^= 1;  
  52.  593         memcpy(static_cast<unsigned char*>(mPreviewHeap->base()) + offset + frame_size + sizeof(phyYAddr) + sizeof(phyCA     ddr),  
  53.  594                 &mOverlayBufferIdx, sizeof(mOverlayBufferIdx));  
  54.  595   
  55.  596         ret = mOverlay->queueBuffer((void*)(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size)))     ;  
  56.  597   
  57.  598         if (ret == -1 ) {  
  58.  599             LOGE("ERR(%s):overlay queueBuffer fail", __func__);  
  59.  600         } else if (ret != ALL_BUFFERS_FLUSHED) {  
  60.  601             ret = mOverlay->dequeueBuffer(&overlay_buffer);  
  61.  602             if (ret == -1) {  
  62.  603                 LOGE("ERR(%s):overlay dequeueBuffer fail", __func__);  
  63.  604             }  
  64.  605          }  
  65.  606      }  
  66.  607 #endif  
  67.  608       
  68.  609     // Notify the client of a new frame.  
  69.  610     if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) {  
  70.  611         mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);  
  71.  612     }     
  72.  613       
  73.  614     if (mRecordRunning == true) {  
  74.  615         // sw5771.park : temporary fix  
  75.  616         //               with HDMI, fimc2 is conflict...  
  76.  617 #ifdef BOARD_USES_HDMI  
  77.  618         int preview_index = index;  
  78.  619           
  79.  620         index = mSecCamera->getRecordFrame();  
  80.  621         if (index < 0) {  
  81.  622             LOGE("ERR(%s):Fail on SecCamera->getRecordFrame()", __func__);  
  82.  623             index = preview_index;  
  83.  624             //return UNKNOWN_ERROR;  
  84.  625         } else {  
  85.  626             phyYAddr = mSecCamera->getRecPhyAddrY(index);  
  86.  627             phyCAddr = mSecCamera->getRecPhyAddrC(index);  
  87.  628         }  
  88.  629 #else  
  89.  630         index = mSecCamera->getRecordFrame();  
  90.  631         if (index < 0) {  
  91.  632             LOGE("ERR(%s):Fail on SecCamera->getRecordFrame()", __func__);  
  92.  633             return UNKNOWN_ERROR;  
  93.  634         }  
  94.  635   
  95.  636         phyYAddr = mSecCamera->getRecPhyAddrY(index);  
  96.  637         phyCAddr = mSecCamera->getRecPhyAddrC(index);  
  97.  638 #endif  
  98.  639   
  99.  640         if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) {  
  100.  641             LOGE("ERR(%s):Fail on SecCamera getRectPhyAddr Y addr = %0x C addr = %0x", __func__, phyYAddr, phyCAddr);  
  101.  642             return UNKNOWN_ERROR;  
  102.  643         }  
  103.  644   
  104.  645         addrs = (struct ADDRS *)mRecordHeap->base();  
  105.  646   
  106.  647         sp<MemoryBase> buffer = new MemoryBase(mRecordHeap, mSizeOfADDRS * index, mSizeOfADDRS);  
  107.  648         addrs[index].addr_y = phyYAddr;  
  108.  649         addrs[index].addr_cbcr = phyCAddr;  
  109.  650         addrs[index].buf_idx = index;  
  110.  651   
  111.  652         // Notify the client of a new frame.  
  112.  653         if (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) {  
  113.  654             mDataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, buffer, mCallbackCookie);  
  114.  655         } else {  
  115.  656             mSecCamera->releaseRecordFrame(index);  
  116.  657         }  
  117.  658     }  
  118.  659   
  119.  660     return NO_ERROR;  
  120.  661 }  

614 ~ 658是和record相关的代码

630 获取record frame,getRecordFrame()会阻塞在FIMC2设备节点的poll函数上,直到有可用数据,返回值index是可用buffer的索引

636 ~ 637 获取buffer对应的物理地址,这里不太明白为什么录像要获取物理地址,也许是传给上层后视频编码过程能够处理物理地址吧

653  上层如果需要处理数据那么就要设置 mMsgEnable为CAMERA_MSG_VIDEO_FRAME,这样HAL层就会通过mDataCbTimestamp上传数据,上层处理完后要负责调用releaseRecordFrame接口释放buffer

656 上层不做处理,那么直接释放buffer(重新入队),不过实在想像不出有什么场景会不做处理


三星S5PV210由于硬件的特殊性,因此可以在preview中启动两个camera capture stream,并且两个FIMC控制器fimc1 fime2从同一个camera sensor获取数据,这两份数据一份用来preview,另外一份用来recording,而其他平台的preview 和recording一般都是共享同一份raw数据。


原创粉丝点击