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数据。
- Android S5PV210 cameraHAL 录像功能分析
- S5PV210 Android cameraHAL 录像功能分析
- Android S5PV210 cameraHAL 录像功能分析
- Android S5PV210 cameraHAL 录像功能分析
- Android S5PV210 cameraHAL 录像功能分析
- s5pv210加入recovery功能分析
- Android Camera CameraHal.cpp 分析
- Android Camera CameraHal.cpp 分析
- Android Camera CameraHal.cpp 分析
- Android Camera CameraHal.cpp 初始化分析
- Android Camera CameraHal.cpp 初始化分析
- android 录像
- Android:录像
- android-录像
- Android-录像
- Android短信功能分析
- android 截屏功能分析
- 功能分析
- 古希腊神话故事:杰森
- 文本分类算法的效果
- Android 实例教程
- isspace
- 使用Android系统自带的应用统计!!!
- Android S5PV210 cameraHAL 录像功能分析
- java code processDir
- 注册Weblogic9为Windows服务及weblogic密码遗忘补救方法
- 清晰的记得刚才做的梦,记录下来以后解析用
- jbpm4.4 分页
- Linux SVN 命令详解
- Visual studio 2008开发Adobe Acrobat/Adobe Reader插件开发-入门篇
- Why C++ ? 王者归来(转)
- 后台解决 json-lib封装的时间