安卓 camera 调用流程_[Camera]Camera1 open、preview、take picture流程分析(3)
四、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); //調(diào)用 get_native_camera() 函數(shù)獲取一個 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 中獲取關(guān)于 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,它具體實現(xiàn)了 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 函數(shù)進入具體的實現(xiàn)邏輯。 }startCameraMode():
// start preview or recording status_t CameraClient::startCameraMode(camera_mode mode) { //根據(jù)傳入的參數(shù) 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();//調(diào)用 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; //如果預(yù)覽已經(jīng)存在,則直接返回成功信息。} ?if (mPreviewWindow != 0) {mHardware->setPreviewScalingMode( //mHardware 是 CameraHardwareInterface 的實例,在 connect 過程的最后被初始化。NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);mHardware->setPreviewTransform(mOrientation);}mHardware->setPreviewWindow(mPreviewWindow); //通過 mHardware 調(diào)用 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() 相關(guān)流程進行初始化的設(shè)備實例,它的類型是 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 繼續(xù)向下調(diào)用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():
/**關(guān)于 mDevice,結(jié)合 Camera.open() 流程與 hw_get_module() 相關(guān)邏輯,可以知道它的邏輯是這樣的:在 CameraService 啟動時,會調(diào)用 onFirstRef() 對 module 進行初始化,獲取 module 實例。在 open 過程中,CameraClient 連接 CameraServer 成功時,會實例化 CameraHardwareInterface,并傳入 module 實例對其初始化。在初始化過程中,通過 module 實例對應(yīng)的 open 方法,我們獲得一個 device 實例,即 mDevice,這對應(yīng)了具體的攝像頭設(shè)備。通過 mDevice 就可以將對應(yīng)的指令傳達到硬件設(shè)備。*/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:所有關(guān)于 Camera 設(shè)備的操作對應(yīng)的函數(shù)指針都在這里聲明了。
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 中指針的對應(yīng)關(guān)系。
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(); //首先調(diào)用了 cameraPreviewInitialization() 函數(shù)進行初始化。 ?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 發(fā)送 CAMERA_START_PREVIEW 指令,若成功執(zhí)行,則完成流程。 ?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() 來發(fā)送指令,并獲取一些數(shù)據(jù)。
- 指令發(fā)送到對應(yīng)的 Adapter (如 V4L Adapter),就會調(diào)用相應(yīng)的函數(shù)進行處理。
(5)hardware/ti/omap4-aah/camera/BaseCameraAdapter.cpp : 各常量分別對應(yīng)不同的命令。
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 將不同的命令對應(yīng)到各自的邏輯中。
case CameraAdapter::CAMERA_START_PREVIEW: //BaseCameraAdapter::startPreview() 具體操作在其子類中實現(xiàn),后面通過子類 V4LCameraAdapter 繼續(xù)分析。{ ?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) : //該線程不斷執(zhí)行 Adapter 中的 previewThread() 函數(shù)。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() 函數(shù)從硬件獲取需要的數(shù)據(jù),并存入 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 攝像頭設(shè)備傳回的數(shù)據(jù)。 CAMHAL_LOGDA("Created preview thread");} ?//Update the flag to indicate we are previewing(設(shè)置標志,表明預(yù)覽功能已開啟)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); //獲取設(shè)備傳回的數(shù)據(jù),并進行一些格式轉(zhuǎn)換操作. ...//給幀數(shù)據(jù)進行一些必要的參數(shù)設(shè)置,如幀大小、時間戳等。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); //將幀數(shù)據(jù)發(fā)送給用戶}} EXIT:return ret; }(8)hardware/ti/omap4-aah/camera/AppCallbackNotifier.cpp:預(yù)覽功能初始化的部分,調(diào)用到了 AppCallbackNotifier 類的函數(shù)。
status_t AppCallbackNotifier::startPreviewCallbacks(android::CameraParameters ¶ms, 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); //同步預(yù)覽幀}return NO_ERROR; }以上回調(diào)函數(shù)在這里設(shè)置:
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: //預(yù)覽元數(shù)據(jù) ?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 對應(yīng)的 Buffers 空間后,就調(diào)用回調(diào)函數(shù)將元數(shù)據(jù)往上層進行傳輸了。 ?mDataCb(CAMERA_MSG_PREVIEW_METADATA,tmpBuffer,0,metaEvtData->getMetadataResult(),mCallbackCookie); ?metaEvtData.clear(); ?if ( NULL != tmpBuffer ) {tmpBuffer->release(tmpBuffer);} ?} ?break;簡圖總結(jié): HAL 層中,CameraHardwareInterface 是通用的入口,而真正實現(xiàn)與驅(qū)動層的對接是與平臺相關(guān),不同平臺有不同的實現(xiàn)方案。
總結(jié)
以上是生活随笔為你收集整理的安卓 camera 调用流程_[Camera]Camera1 open、preview、take picture流程分析(3)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用t-sql语句修改表中的某些数据及数
- 下一篇: 看漫画学python pdf下载_看漫画