本文章转载自sheldon_blogs的博客,具体网址如下:https://www.cnblogs.com/blogs-of-lxl/p/5152578.html
本文章仅供学习研究使用,如须转载请附上原作者名称及网址

四、Camera.startPreview()流程

1.Frameworks

frameworks/base/core/java/android/hardware/Camera.java

/*** Starts capturing and drawing preview frames to the screen.* Preview will not actually start until a surface is supplied* with {@link #setPreviewDisplay(SurfaceHolder)} or* {@link #setPreviewTexture(SurfaceTexture)}.** <p>If {@link #setPreviewCallback(Camera.PreviewCallback)},* {@link #setOneShotPreviewCallback(Camera.PreviewCallback)}, or* {@link #setPreviewCallbackWithBuffer(Camera.PreviewCallback)} were* called, {@link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)}* will be called when preview data becomes available.*/public native final void startPreview();  //给上层 application 提供一个接口, 进入 Runtime 层。

2.Android Runtime

frameworks/base/core/jni/android_hardware_Camera.cpp

static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{ALOGV("startPreview");sp<Camera> camera = get_native_camera(env, thiz, NULL); //调用 get_native_camera() 函数获取一个 Camera 实例。if (camera == 0) return;
​if (camera->startPreview() != NO_ERROR) {jniThrowRuntimeException(env, "startPreview failed");return;}
}sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
{sp<Camera> camera;Mutex::Autolock _l(sLock);JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context)); //从 DVM 中获取关于 Camera 的上下文。if (context != NULL) {camera = context->getCamera(); //从上下文信息中获取 Camera 实例。}ALOGV("get_native_camera: context=%p, camera=%p", context, camera.get());if (camera == 0) {jniThrowRuntimeException(env,"Camera is being used after Camera.release() was called");}
​if (pContext != NULL) *pContext = context;return camera;
}

3. Libraries

(1)frameworks/av/camera/Camera.cpp

// start preview mode
status_t Camera::startPreview()
{ALOGV("startPreview");sp <::android::hardware::ICamera> c = mCamera; //mCamera 即是在 connect 过程中返回的 CameraClient,它具体实现了 startPreview() 接口。if (c == 0) return NO_INIT;return c->startPreview();
}

(2)frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp

// start preview mode
status_t CameraClient::startPreview() {LOG1("startPreview (pid %d)", getCallingPid());return startCameraMode(CAMERA_PREVIEW_MODE); //通过 startCameraMode 函数进入具体的实现逻辑。
}

startCameraMode()

// start preview or recording
status_t CameraClient::startCameraMode(camera_mode mode) { //根据传入的参数 CAMERA_PREVIEW_MODE 确定进入的分支。LOG1("startCameraMode(%d)", mode);Mutex::Autolock lock(mLock);status_t result = checkPidAndHardware();if (result != NO_ERROR) return result;
​switch(mode) {case CAMERA_PREVIEW_MODE:if (mSurface == 0 && mPreviewWindow == 0) {LOG1("mSurface is not set yet.");// still able to start preview in this case.}return startPreviewMode();//调用 startPreviewMode() 。case CAMERA_RECORDING_MODE:if (mSurface == 0 && mPreviewWindow == 0) {ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");return INVALID_OPERATION;}return startRecordingMode();default:return UNKNOWN_ERROR;}
}

startPreviewMode()

status_t CameraClient::startPreviewMode() {LOG1("startPreviewMode");status_t result = NO_ERROR;
​// if preview has been enabled, nothing needs to be doneif (mHardware->previewEnabled()) { return NO_ERROR; //如果预览已经存在,则直接返回成功信息。}
​if (mPreviewWindow != 0) {mHardware->setPreviewScalingMode( //mHardware 是 CameraHardwareInterface 的实例,在 connect 过程的最后被初始化。NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);mHardware->setPreviewTransform(mOrientation);}mHardware->setPreviewWindow(mPreviewWindow); //通过 mHardware 调用 setPreviewWindow() 和 startPreview() 接口。result = mHardware->startPreview();if (result == NO_ERROR) {mCameraService->updateProxyDeviceState( //进入 HAL 层。ICameraServiceProxy::CAMERA_STATE_ACTIVE,String8::format("%d", mCameraId));}return result;
}

4. HAL

(1)frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h

/*** Returns true if preview is enabled.*/int previewEnabled(){ALOGV("%s(%s)", __FUNCTION__, mName.string());if (mDevice->ops->preview_enabled) //mDevice 即是通过 hw_get_module() 相关流程进行初始化的设备实例,它的类型是 camera_device_t 。return mDevice->ops->preview_enabled(mDevice); //如果 preview 存在,则返回 true 。return false;}

setPreviewWindow()

/** Set the ANativeWindow to which preview frames are sent */status_t setPreviewWindow(const sp<ANativeWindow>& buf){ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());if (mDevice->ops->set_preview_window) { //通过 mDevice->ops 继续向下调用mPreviewWindow = buf;if (buf != nullptr) {if (mPreviewScalingMode != NOT_SET) {setPreviewScalingMode(mPreviewScalingMode);}if (mPreviewTransform != NOT_SET) {setPreviewTransform(mPreviewTransform);}}mHalPreviewWindow.user = this;ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,&mHalPreviewWindow, mHalPreviewWindow.user);return mDevice->ops->set_preview_window(mDevice,buf.get() ? &mHalPreviewWindow.nw : 0);}return INVALID_OPERATION;}

startPreview()

/**关于 mDevice,结合 Camera.open() 流程与 hw_get_module() 相关逻辑,可以知道它的逻辑是这样的:在 CameraService 启动时,会调用 onFirstRef() 对 module 进行初始化,获取 module 实例。在 open 过程中,CameraClient 连接 CameraServer 成功时,会实例化 CameraHardwareInterface,并传入 module 实例对其初始化。在初始化过程中,通过 module 实例对应的 open 方法,我们获得一个 device 实例,即 mDevice,这对应了具体的摄像头设备。通过 mDevice 就可以将对应的指令传达到硬件设备。*/status_t startPreview(){ALOGV("%s(%s)", __FUNCTION__, mName.string());if (mDevice->ops->start_preview)return mDevice->ops->start_preview(mDevice);return INVALID_OPERATION;}

(2)hardware/libhardware/include/hardware/camera.h

typedef struct camera_device { //这里就声明了要追踪的 camera_device_t 。/*** camera_device.common.version must be in the range* HARDWARE_DEVICE_API_VERSION(0,0)-(1,FF). CAMERA_DEVICE_API_VERSION_1_0 is* recommended.*/hw_device_t common;camera_device_ops_t *ops;void *priv;
} camera_device_t;

其中struct camera_device_ops:所有关于 Camera 设备的操作对应的函数指针都在这里声明了。

typedef struct camera_device_ops {int (*set_preview_window)(struct camera_device *,struct preview_stream_ops *window);
​void (*set_callbacks)(struct camera_device *,camera_notify_callback notify_cb,camera_data_callback data_cb,camera_data_timestamp_callback data_cb_timestamp,camera_request_memory get_memory,void *user);
​void (*enable_msg_type)(struct camera_device *, int32_t msg_type);
​void (*disable_msg_type)(struct camera_device *, int32_t msg_type);
​int (*msg_type_enabled)(struct camera_device *, int32_t msg_type);
​/*** Start preview mode.*/int (*start_preview)(struct camera_device *);
​void (*stop_preview)(struct camera_device *);
​    ...
} camera_device_ops_t;

(3)hardware/ti/omap4-aah/camera/CameraHal_Module.cpp: 在 open 流程中,就指定了 ops 中指针的对应关系。

memset(camera_device, 0, sizeof(*camera_device));memset(camera_ops, 0, sizeof(*camera_ops));
​camera_device->base.common.tag = HARDWARE_DEVICE_TAG;camera_device->base.common.version = 0;camera_device->base.common.module = (hw_module_t *)(module);camera_device->base.common.close = camera_device_close;camera_device->base.ops = camera_ops;
​camera_ops->set_preview_window = camera_set_preview_window;camera_ops->set_callbacks = camera_set_callbacks;...*device = &camera_device->base.common;
​// -------- TI specific stuff --------
​camera_device->cameraid = cameraid;

camera_start_preview():

int camera_start_preview(struct camera_device * device)
{CAMHAL_LOG_MODULE_FUNCTION_NAME;
​int rv = -EINVAL;ti_camera_device_t* ti_dev = NULL;
​if(!device)return rv;
​ti_dev = (ti_camera_device_t*) device;
​rv = gCameraHals[ti_dev->cameraid]->startPreview(); //gCameraHals 是 CameraHal * 。
​return rv;
}

(4)hardware/ti/omap4-aah/camera/CameraHal.cpp : 将 Camera Hardware Interface 映射到 V4L2

status_t CameraHal::startPreview() {LOG_FUNCTION_NAME;
​status_t ret = cameraPreviewInitialization(); //首先调用了 cameraPreviewInitialization() 函数进行初始化。
​if (!mPreviewInitializationDone) return ret;
​mPreviewInitializationDone = false;
​if(mDisplayAdapter.get() != NULL) {CAMHAL_LOGDA("Enabling display");int width, height;mParameters.getPreviewSize(&width, &height);
​
#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABSret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview);
#elseret = mDisplayAdapter->enableDisplay(width, height, NULL);
#endif
​if ( ret != NO_ERROR ) {CAMHAL_LOGEA("Couldn't enable display");CAMHAL_ASSERT_X(false,"At this stage mCameraAdapter->mStateSwitchLock is still locked, ""deadlock is guaranteed");
​goto error;}}
​CAMHAL_LOGDA("Starting CameraAdapter preview mode");
​ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW); //通过 CameraAdapter 发送 CAMERA_START_PREVIEW 指令,若成功执行,则完成流程。
​if(ret!=NO_ERROR) {CAMHAL_LOGEA("Couldn't start preview w/ CameraAdapter");goto error;}CAMHAL_LOGDA("Started preview");
​mPreviewEnabled = true;mPreviewStartInProgress = false;return ret;
​error:
​CAMHAL_LOGEA("Performing cleanup after error");
​//Do all the cleanupfreePreviewBufs();mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW);if(mDisplayAdapter.get() != NULL) {mDisplayAdapter->disableDisplay(false);}mAppCallbackNotifier->stop();mPreviewStartInProgress = false;mPreviewEnabled = false;LOG_FUNCTION_NAME_EXIT;
​return ret;
}

cameraPreviewInitialization()

  • 代码中不断使用 mCameraAdapter->sendCommand() 来发送指令,并获取一些数据。
  • 指令发送到对应的 Adapter (如 V4L Adapter),就会调用相应的函数进行处理。
...if ( NULL != mCameraAdapter ) {ret = mCameraAdapter->setParameters(mParameters); //通过 Adapter 设置相关参数;}
...///Allocate the preview buffersret = allocPreviewBufs(mPreviewWidth, mPreviewHeight, mParameters.getPreviewFormat(), required_buffer_count, max_queueble_buffers); //申请 Buffers 空间;
...
if ( NO_ERROR == ret ){//在申请 Buffers 空间成功后设置相应的成员。desc.mBuffers = mPreviewDataBuffers;desc.mOffsets = mPreviewDataOffsets;desc.mFd = mPreviewDataFd;desc.mLength = mPreviewDataLength;desc.mCount = ( size_t ) required_buffer_count;desc.mMaxQueueable = (size_t) required_buffer_count;mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA,( int ) &desc);}
...///Start the callback notifierret = mAppCallbackNotifier->start(); //开启回调通知。
....//将 Buffers 对应到相应的回调函数中,以供上层 APP 获取预览所需的数据。mAppCallbackNotifier->startPreviewCallbacks(mParameters, mPreviewBuffers, mPreviewOffsets, mPreviewFd, mPreviewLength, required_buffer_count);

(5)hardware/ti/omap4-aah/camera/BaseCameraAdapter.cpp : 各常量分别对应不同的命令。

const LUT cameraCommandsUserToHAL[] = {{ "CAMERA_START_PREVIEW",                   CameraAdapter::CAMERA_START_PREVIEW },{ "CAMERA_STOP_PREVIEW",                    CameraAdapter::CAMERA_STOP_PREVIEW },{ "CAMERA_START_VIDEO",                     CameraAdapter::CAMERA_START_VIDEO },{ "CAMERA_STOP_VIDEO",                      CameraAdapter::CAMERA_STOP_VIDEO },....
#endif
};

BaseCameraAdapter::sendCommand()利用 switch 将不同的命令对应到各自的逻辑中。

case CameraAdapter::CAMERA_START_PREVIEW: //BaseCameraAdapter::startPreview() 具体操作在其子类中实现,后面通过子类 V4LCameraAdapter 继续分析。{​CAMHAL_LOGDA("Start Preview");
​if ( ret == NO_ERROR ){ret = setState(operation);}
​if ( ret == NO_ERROR ){ret = startPreview();}
​if ( ret == NO_ERROR ){ret = commitState();}else{ret |= rollbackState();}
​break;
​}

(6)hardware/ti/omap4-aah/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h

private:
​class PreviewThread : public android::Thread {V4LCameraAdapter* mAdapter; //类 V4LCameraAdapter 继承了 BaseCameraAdapterpublic:PreviewThread(V4LCameraAdapter* hw) : //该线程不断执行 Adapter 中的 previewThread() 函数。Thread(false), mAdapter(hw) { }virtual void onFirstRef() {run("CameraPreviewThread", android::PRIORITY_URGENT_DISPLAY);}virtual bool threadLoop() {mAdapter->previewThread();// loop until we need to quitreturn true;}};
​//Used for calculation of the average frame rate during previewstatus_t recalculateFPS();
​char * GetFrame(int &index);
​int previewThread();

(7)hardware/ti/omap4-aah/camera/V4LCameraAdapter/V4LCameraAdapter.cpp

startPreview()

status_t V4LCameraAdapter::startPreview()
{status_t ret = NO_ERROR;
​LOG_FUNCTION_NAME;android::AutoMutex lock(mPreviewBufsLock);
​if(mPreviewing) {ret = BAD_VALUE;goto EXIT;}
​for (int i = 0; i < mPreviewBufferCountQueueable; i++) {​mVideoInfo->buf.index = i;mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
​ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); //通过 v4lIoctl() 函数从硬件获取需要的数据,并存入 Buffers。if (ret < 0) {CAMHAL_LOGEA("VIDIOC_QBUF Failed");goto EXIT;}nQueued++;}
​ret = v4lStartStreaming();// Create and start preview thread for receiving buffers from V4L Cameraif(!mCapturing) {mPreviewThread = new PreviewThread(this);  //启动一个 PreviewThread,用于接收从 V4L 摄像头设备传回的数据。 CAMHAL_LOGDA("Created preview thread");}
​//Update the flag to indicate we are previewing(设置标志,表明预览功能已开启)mPreviewing = true;mCapturing = false;
​
EXIT:LOG_FUNCTION_NAME_EXIT;return ret;
}

previewThread()

int V4LCameraAdapter::previewThread()
{...convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height); //获取设备传回的数据,并进行一些格式转换操作.
...//给帧数据进行一些必要的参数设置,如帧大小、时间戳等。frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;frame.mBuffer = buffer;frame.mLength = width*height*3/2;frame.mAlignment = stride;frame.mOffset = 0;frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC;
...ret = sendFrameToSubscribers(&frame); //将帧数据发送给用户}}
EXIT:return ret;
}

(8)hardware/ti/omap4-aah/camera/AppCallbackNotifier.cpp:预览功能初始化的部分,调用到了 AppCallbackNotifier 类的函数。

status_t AppCallbackNotifier::startPreviewCallbacks(android::CameraParameters &params, CameraBuffer *buffers, uint32_t *offsets, int fd, size_t length, size_t count)
{
...///Get preview sizeparams.getPreviewSize(&w, &h);
...if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_POSTVIEW_FRAME) ) {mFrameProvider->enableFrameNotification(CameraFrame::SNAPSHOT_FRAME); //同步预览帧}return NO_ERROR;
}

以上回调函数在这里设置:

void AppCallbackNotifier::setCallbacks(CameraHal* cameraHal,camera_notify_callback notify_cb,camera_data_callback data_cb,camera_data_timestamp_callback data_cb_timestamp,camera_request_memory get_memory,void *user)
{android::AutoMutex lock(mLock);
​LOG_FUNCTION_NAME;
​mCameraHal = cameraHal;mNotifyCb = notify_cb;mDataCb = data_cb;mDataCbTimestamp = data_cb_timestamp;mRequestMemory = get_memory;mCallbackCookie = user;
​LOG_FUNCTION_NAME_EXIT;
}

notifyEvent()

case CameraHalEvent::EVENT_METADATA: //预览元数据
​metaEvtData = evt->mEventData->metadataEvent;
​if ( ( NULL != mCameraHal ) &&( NULL != mNotifyCb) &&( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_METADATA) ) ){// WA for an issue inside CameraServicecamera_memory_t *tmpBuffer = mRequestMemory(-1, 1, 1, NULL); //申请一个 camera_memory_t 对应的 Buffers 空间后,就调用回调函数将元数据往上层进行传输了。
​mDataCb(CAMERA_MSG_PREVIEW_METADATA,tmpBuffer,0,metaEvtData->getMetadataResult(),mCallbackCookie);
​metaEvtData.clear();
​if ( NULL != tmpBuffer ) {tmpBuffer->release(tmpBuffer);}
​}
​break;

简图总结: HAL 层中,CameraHardwareInterface 是通用的入口,而真正实现与驱动层的对接是与平台相关,不同平台有不同的实现方案。

安卓 camera 调用流程_[Camera]Camera1 open、preview、take picture流程分析(3)相关推荐

  1. hdfs读写流程_一文读懂HDFS分布式存储框架分析

    一文读懂HDFS分布式存储框架分析 HDFS是一套基于区块链技术的个人的数据存储系统,利用无处不在的私人PC存储空间及便捷的网络为个人提供数据加密存储服务,将闲置的存储空间利用起来,服务于正处于爆发期 ...

  2. springmvc流程_基于Spring MVC框架的Http流程分析

    一.问题提出 我们可以方便的利用Spring MVC进行业务开发,请求的大部分工作都被框架和容器封装,使得我们只需要做很少量的工作.但是整个http请求流程是怎么样的?Spring MVC框架在其中起 ...

  3. 小程序发布上线流程_家居小程序傻瓜式制作流程

    近几年"小程序+"成为很多服务和零售商家的选择,比如点餐小程序.电商购物小程序.家政预约小程序--借助于小程序的便捷性,很多传统行业商家获得了新的商机,家居行业也是如此. 传统家居 ...

  4. gms认证流程_申请谷歌GMS认证MADA协议流程

    随着谷歌对GMS认证的要求越来越严格,为了打开国外运营商申请GMS认证成为了企业的必须迈过去的坎.在GMS认证的申请过程中企业首先需要提供MADA商的相关信息,那到底什么是MADA呢? 一.什么是MA ...

  5. 两用物项许可证办理流程_办理两用物项和技术进口许可证流程

    原标题:办理两用物项和技术进口许可证流程 我们国家为了防止两用物项易制毒化学品流入非法制毒渠道,制定了一系列相关法律与行政法规,规定<易制毒化学品管理条例>附表所列可用于制毒的主要原料及化 ...

  6. python接口自动化测试流程_【转】接口自动化测试基本流程及测试思路

    接口自动化大致步骤: 1.发送请求 2.解析结果 3.验证结果 定义三个和业务相关的类 1.一个用来封装HTTPclient,用来发送请求 2.解析结果xml的类 3.一个用于比较测试结果和期望值的类 ...

  7. 电子产品设计流程_指纹锁生产的八大工序流程

    市面上指纹锁的价格高居不下,除了材料成本变动小,指纹锁的工艺成本长期稳定也是一个重要因素.指纹锁的生产流程细数可达百项,而简单归纳则可划分为以下8个主要生产环节.   一.产品设计,灵感转化产品的开始 ...

  8. 安卓 camera 调用流程_音视频开发之旅(四)Camera视频采集

    目录 Camera基础知识 视频采集的流程 遇到的问题和常见的坑(重点) 收获 一. Camera基础知识 Camera 有几个重要的基础概念. facing相机的方向,一般后置摄像头和前置摄像头. ...

  9. 展锐camera 调用流程

    本文将要为您介绍的是[Camera专题]Sprd-深入浅出Camera驱动框架1(HAL层-Kernel层),具体完成步骤: 一.前言 本文主要研究展讯平台Camera驱动和HAL层代码架构,熟悉展讯 ...

最新文章

  1. vue-cli构建项目
  2. 技术人生:如何成为一位优秀的程序员
  3. Fluentd初探 简介与安装
  4. free 命令查看linux的内存使用情况
  5. linux wheel用户组,Linux的用户和组之详解用户和组的分类
  6. ubuntu12.04 安装Android Studio笔记
  7. 实例:用户登录(python 版)
  8. tomcat源码分析(一)从tomcat架构说起
  9. 中软python编码规范考试试题_这些常见的python学习问题,你中枪了吗?
  10. java 千位分隔,如何在Java中设置千位分隔符?
  11. 多模块顺序_广东省考行测时间如何分配?答题顺序的建议?
  12. SAP GUI 安全性 下载文件
  13. 电机编码器调零步骤_伺服电机编码器调零
  14. linux进程操作日志文件,我使用过的Linux命令之tailf - 跟踪日志文件/更好的tail -f版本...
  15. ANSYS 2020R2 workbench汉化的方法
  16. element Table+Pagination实现分页
  17. MFC 添加静态图片(Picture Control控件)
  18. 破局模块总结 -- 宁向东的清华管理学课总结
  19. 【自适应盲均衡12】判决引导(DD)+判决反馈(DFE)+双模式切换的盲均衡算法在双绞线基带通信中的应用MATLAB仿真(采用三电平PAM信号模型)
  20. 『Reprint』GRADUAL

热门文章

  1. 使用Opencv的一些注意事项
  2. [云炬学英语]每日一句2020.8.26
  3. java rest 图_SpringMVC视图及REST风格
  4. 研究生第一篇学术论文常犯问题总结【喻海良箴言】
  5. C/C++中extern关键字详解与应用
  6. 深入理解文档/视图框架体系_九宫格项目开发感悟
  7. c++/cli中System::Type::GetType的使用注意事项
  8. WINDOWS键盘事件的挂钩监控原理及其应用技术
  9. UML统一建模语言知识体系概述
  10. 对PE文件进行十六进制代码(机器码)提取并保存到外部文件