Android S5PV210 cameraHAL 录像功能分析

来源:互联网 发布:淘宝网电子琴价格 编辑:程序博客网 时间:2024/05/09 09:47

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

 802 status_t CameraHardwareSec::startRecording() 803 { 804     LOGV("%s :", __func__); 805  806     if (mRecordRunning == false) { 807         if (mSecCamera->startRecord() < 0) { 808             LOGE("ERR(%s):Fail on mSecCamera->startRecord()", __func__); 809             // sw5771.park : temporary fix 810             //               with HDMI, fimc2 is conflict... 811 #ifdef BOARD_USES_HDMI 812 #else 813             return UNKNOWN_ERROR; 814 #endif 815         } 816         mRecordRunning = true; 817     } 818     return NO_ERROR; 819 }

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

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


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

1084 int SecCamera::startRecord(void)1085 {1086     int ret, i;1087 1088     LOGV("%s :", __func__);1089 1090     // aleady started1091     if (m_flag_record_start > 0) {1092         LOGE("ERR(%s):Recording was already started\n", __func__);1093         return 0;1094     }1095 1096     if (m_cam_fd2 <= 0) {1097         LOGE("ERR(%s):Camera was closed\n", __func__);1098         return -1;1099     }1100 1101     /* enum_fmt, s_fmt sample */1102     ret = fimc_v4l2_enum_fmt(m_cam_fd2, V4L2_PIX_FMT_NV12T);1103     CHECK(ret);1104 1105     LOGI("%s: m_recording_width = %d, m_recording_height = %d\n",1106          __func__, m_recording_width, m_recording_height);1107 1108     ret = fimc_v4l2_s_fmt(m_cam_fd2, m_recording_width, m_recording_height,1109                           V4L2_PIX_FMT_NV12T, 0);1110     CHECK(ret);1111 1112     ret = fimc_v4l2_reqbufs(m_cam_fd2, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS);1113     CHECK(ret);1114 1115     ret = this->m_setCameraAngle(m_cam_fd2);1116     CHECK(ret);1117 1118     /* start with all buffers in queue */1119     for (i = 0; i < MAX_BUFFERS; i++) {1120         ret = fimc_v4l2_qbuf(m_cam_fd2, i);1121         CHECK(ret);1122     }1123 1124     ret = fimc_v4l2_streamon(m_cam_fd2);1125     CHECK(ret);1126 1127     // Get and throw away the first frame since it is often garbled.1128     memset(&m_events_c2, 0, sizeof(m_events_c2));1129     m_events_c2.fd = m_cam_fd2;1130     m_events_c2.events = POLLIN | POLLERR;1131     ret = fimc_poll(&m_events_c2);1132     CHECK(ret);1133 1134     m_flag_record_start = 1;1135 1136     LOGE("(%s): end\n", __func__);1137     return 0;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 等待第一帧的到来,并且忽略掉,因为第一帧的数据经常错乱


 821 void CameraHardwareSec::stopRecording() 822 { 823     LOGV("%s :", __func__); 824  825     if (mRecordRunning == true) { 826         if (mSecCamera->stopRecord() < 0) { 827             LOGE("ERR(%s):Fail on mSecCamera->stopRecord()", __func__); 828             return; 829         } 830         mRecordRunning = false; 831     } 832 }

826 停止FIMC2设备的capture stream

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


 841 void CameraHardwareSec::releaseRecordingFrame(const sp<IMemory>& mem) 842 { 843     ssize_t offset; 844     sp<IMemoryHeap> heap = mem->getMemory(&offset, NULL); 845     struct ADDRS *addrs = (struct ADDRS *)((uint8_t *)heap->base() + offset); 846 847     mSecCamera->releaseRecordFrame(addrs->buf_idx); 848 }

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

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

 542 int CameraHardwareSec::previewThread() 543 { 544     int index; 545     nsecs_t timestamp; 546     unsigned int phyYAddr; 547     unsigned int phyCAddr; 548     struct ADDRS *addrs; 549  550     index = mSecCamera->getPreview(); 551     if (index < 0) { 552         LOGE("ERR(%s):Fail on SecCamera->getPreview()", __func__); 553         return UNKNOWN_ERROR; 554     } 555     mSkipFrameLock.lock(); 556     if (mSkipFrame > 0) { 557         mSkipFrame--; 558         mSkipFrameLock.unlock(); 559         return NO_ERROR; 560     } 561     mSkipFrameLock.unlock(); 562     gInterlace++; 563     //if (gInterlace % 8) { 564     //  return NO_ERROR; 565     //} 566  567     timestamp = systemTime(SYSTEM_TIME_MONOTONIC); 568  569     phyYAddr = mSecCamera->getPhyAddrY(index); 570     phyCAddr = mSecCamera->getPhyAddrC(index); 571  572     if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) { 573         LOGE("ERR(%s):Fail on SecCamera getPhyAddr Y addr = %0x C addr = %0x", __func__, phyYAddr, phyCAddr); 574         return UNKNOWN_ERROR; 575      } 576 577     int width, height, frame_size, offset; 578  579     mSecCamera->getPreviewSize(&width, &height, &frame_size); 580  581     offset = (frame_size + mSizeOfADDRS) * index; 582     sp<MemoryBase> buffer = new MemoryBase(mPreviewHeap, offset, frame_size); 583  584     memcpy(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size    ), &phyYAddr, 4); 585     memcpy(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size + 4), &phyCAddr, 4); 586  587 #if defined(BOARD_USES_OVERLAY) 588     if (mUseOverlay) { 589         int ret; 590         overlay_buffer_t overlay_buffer; 591  592         mOverlayBufferIdx ^= 1; 593         memcpy(static_cast<unsigned char*>(mPreviewHeap->base()) + offset + frame_size + sizeof(phyYAddr) + sizeof(phyCA     ddr), 594                 &mOverlayBufferIdx, sizeof(mOverlayBufferIdx)); 595  596         ret = mOverlay->queueBuffer((void*)(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size)))     ; 597  598         if (ret == -1 ) { 599             LOGE("ERR(%s):overlay queueBuffer fail", __func__); 600         } else if (ret != ALL_BUFFERS_FLUSHED) { 601             ret = mOverlay->dequeueBuffer(&overlay_buffer); 602             if (ret == -1) { 603                 LOGE("ERR(%s):overlay dequeueBuffer fail", __func__); 604             } 605          } 606      } 607 #endif 608      609     // Notify the client of a new frame. 610     if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) { 611         mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie); 612     }    613      614     if (mRecordRunning == true) { 615         // sw5771.park : temporary fix 616         //               with HDMI, fimc2 is conflict... 617 #ifdef BOARD_USES_HDMI 618         int preview_index = index; 619          620         index = mSecCamera->getRecordFrame(); 621         if (index < 0) { 622             LOGE("ERR(%s):Fail on SecCamera->getRecordFrame()", __func__); 623             index = preview_index; 624             //return UNKNOWN_ERROR; 625         } else { 626             phyYAddr = mSecCamera->getRecPhyAddrY(index); 627             phyCAddr = mSecCamera->getRecPhyAddrC(index); 628         } 629 #else 630         index = mSecCamera->getRecordFrame(); 631         if (index < 0) { 632             LOGE("ERR(%s):Fail on SecCamera->getRecordFrame()", __func__); 633             return UNKNOWN_ERROR; 634         } 635  636         phyYAddr = mSecCamera->getRecPhyAddrY(index); 637         phyCAddr = mSecCamera->getRecPhyAddrC(index); 638 #endif 639  640         if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) { 641             LOGE("ERR(%s):Fail on SecCamera getRectPhyAddr Y addr = %0x C addr = %0x", __func__, phyYAddr, phyCAddr); 642             return UNKNOWN_ERROR; 643         } 644  645         addrs = (struct ADDRS *)mRecordHeap->base(); 646  647         sp<MemoryBase> buffer = new MemoryBase(mRecordHeap, mSizeOfADDRS * index, mSizeOfADDRS); 648         addrs[index].addr_y = phyYAddr; 649         addrs[index].addr_cbcr = phyCAddr; 650         addrs[index].buf_idx = index; 651  652         // Notify the client of a new frame. 653         if (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) { 654             mDataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, buffer, mCallbackCookie); 655         } else { 656             mSecCamera->releaseRecordFrame(index); 657         } 658     } 659  660     return NO_ERROR; 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数据。



原创粉丝点击