android 7 相機預覽

Camera.cpp

status_t Camera::startPreview()
{
    ALOGV("startPreview");
    sp <ICamera> c = mCamera; //mCamera其實就是cameraClient
    if (c == 0) return NO_INIT;
    return c->startPreview();
}

CameraClient.cpp

// start preview mode
status_t CameraClient::startPreview() {
    LOG1("startPreview (pid %d)", getCallingPid());
    return startCameraMode(CAMERA_PREVIEW_MODE);
}

// start preview or recording
status_t CameraClient::startCameraMode(camera_mode 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();
        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;
    }
}

status_t CameraClient::startPreviewMode() {
    LOG1("startPreviewMode");
    status_t result = NO_ERROR;

    // if preview has been enabled, nothing needs to be done
    if (mHardware->previewEnabled()) {
        return NO_ERROR;
    }

    if (mPreviewWindow != 0) {
        native_window_set_scaling_mode(mPreviewWindow.get(),
                NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
        native_window_set_buffers_transform(mPreviewWindow.get(),
                mOrientation);
    }

https://my.oschina.net/u/920274/blog/5006000//mHardware 就是CameraHardwareInterface 的實例
    mHardware->setPreviewWindow(mPreviewWindow); 
    result = mHardware->startPreview();

    if (result == NO_ERROR) {
        mCameraService->updateProxyDeviceState(
            ICameraServiceProxy::CAMERA_STATE_ACTIVE,
            String8::format("%d", mCameraId));
    }
    return result;
}

CameraHardwareInterface.h文件 

 /** 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) {
            mPreviewWindow = buf;
            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;
    }

關於 mDevice,我們結合 Camera.open() 流程與 hw_get_module() 相關邏輯,可以知道它的邏輯是這樣的:
在 CameraService 啓動時,會調用 onFirstRef() 對 module 進行初始化,獲取 module 實例。
在 open 過程中,CameraClient 連接 CameraServer 成功時,會實例化 CameraHardwareInterface,並傳入 module 實例對其初始化。
在初始化過程中,通過 module 實例對應的 open 方法,我們獲得一個 device 實例,即 mDevice,這對應了具體的攝像頭設備。
通過 mDevice,我們就可以將對應的指令傳達到硬件設備。
通過對 camera_device_t 類型進行追蹤,可以找到函數指針的一個具體指向

這裏看下另外一個地方 hw_get_module() -->load() 和mDevice有關

static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;

// 功能是以指定模式打開指定的動態鏈接庫文件,並返回一個句柄給dlsym()的調用進程
    handle = dlopen(path, RTLD_NOW);
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;

//功能是根據動態鏈接庫操作句柄與符號,返回符號對應的地址,不但可以獲取函數地址,也可以獲取變量地址。
    hmi = (struct hw_module_t *)dlsym(handle, sym);

    hmi->dso = handle;

    *pHmi = hmi;

    return status;
}

pHmi就是我們要的,最後指向 camera_module_t

CameraHardwareInterface.h的initialize

 status_t initialize(CameraModule *module)
    {
        ALOGI("Opening camera %s", mName.string());
        camera_info info;
        status_t res = module->getCameraInfo(atoi(mName.string()), &info);
        if (res != OK) return res;

        int rc = OK;
        if (module->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_3 &&
            info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
            // Open higher version camera device as HAL1.0 device.
            rc = module->openLegacy(mName.string(),
                                     CAMERA_DEVICE_API_VERSION_1_0,
                                     (hw_device_t **)&mDevice);

        } else {
            rc = module->oCameraHardwareInterface.hpen(mName.string(), (hw_device_t **)&mDevice);
        }
        if (rc != OK) {
            ALOGE("Could not open camera %s: %d", mName.string(), rc);
            return rc;
        }
        initHalPreviewWindow();
        return rc;
    }

回到CameraHardwareInterface.h

 status_t startPreview()
    {
        ALOGV("%s(%s)", __FUNCTION__, mName.string());
        if (mDevice->ops->start_preview)
            return mDevice->ops->start_preview(mDevice);
        return INVALID_OPERATION;
    }

來到文件

hardware/libhardware/include/hardware/camera.h

typedef struct camera_device {
    。。。
    hw_device_t common;
    camera_device_ops_t *ops;

    void *priv;

 。。。
} camera_device_t;

變量 mDevice 類型就是 camera_device_t

回到前面 調用

mDevice->ops->start_preview(mDevice);

camera_device_ops_t 是個結構體

start_preview 是個函數指針,看看指向哪個函數

經過搜索,發現在位置:hardware/ti/omap4-aah/camera/CameraHal_Module.cpp 有定義

int camera_device_open(const hw_module_t* module, const char* name,
                hw_device_t** device)
{
    int rv = 0;
   。。。
   。。。
   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;
        camera_ops->enable_msg_type = camera_enable_msg_type;
        camera_ops->disable_msg_type = camera_disable_msg_type;
        camera_ops->msg_type_enabled = camera_msg_type_enabled;
        camera_ops->start_preview = camera_start_preview;
        camera_ops->stop_preview = camera_stop_preview;
        camera_ops->preview_enabled = camera_preview_enabled;
        camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers;
        camera_ops->start_recording = camera_start_recording;
        camera_ops->stop_recording = camera_stop_recording;
        camera_ops->recording_enabled = camera_recording_enabled;
        camera_ops->release_recording_frame = camera_release_recording_frame;
        camera_ops->auto_focus = camera_auto_focus;
        camera_ops->cancel_auto_focus = camera_cancel_auto_focus;
        camera_ops->take_picture = camera_take_picture;
        camera_ops->cancel_picture = camera_cancel_picture;
        camera_ops->set_parameters = camera_set_parameters;
        camera_ops->get_parameters = camera_get_parameters;
        camera_ops->put_parameters = camera_put_parameters;
        camera_ops->send_command = camera_send_command;
        camera_ops->release = camera_release;
        camera_ops->dump = camera_dump;

        *device = &camera_device->base.common;
        。。。
        。。。
    return rv;
}

然後來到

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();

    return rv;
}

可以發現定義

static CameraHal* gCameraHals[MAX_CAMERAS_SUPPORTED];

最後調用到

status_t CameraHal::startPreview() {
    LOG_FUNCTION_NAME;
    status_t ret = cameraPreviewInitialization();

    if (!mPreviewInitializationDone) return ret;

    mPreviewInitializationDone = false;

    ///Enable the display adapter if present, actual overlay enable happens when we post the buffer
    if(mDisplayAdapter.get() != NULL) {
        CAMHAL_LOGDA("Enabling display");
        int width, height;
        mParameters.getPreviewSize(&width, &height);

#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
        ret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview);
#else
        ret = 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);
    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");
        freePreviewBufs();
        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():
這段代碼比較長,但從註釋看,它主要做三件事:
通過 Adapter 設置相關參數;
申請 Buffers 空間;
對 Buffers 進行相應設置以進行預覽。

瞭解了大體思路,再看看具體代碼:
mCameraAdapter->setParameters():設置參數。
allocPreviewBufs() :申請 Buffers。
desc:注意到這個變量對應着 CameraAdapter::BuffersDescriptor,在申請 Buffers 空間成功後,便對其進行相應的成員設置。
mAppCallbackNotifier->start():開啓回調通知。
mAppCallbackNotifier->startPreviewCallbacks():將 Buffers 對應到相應的回調函數中,以供上層 APP 獲取預覽所需的數據。
NOTE:
代碼中不斷使用 mCameraAdapter->sendCommand() 來發送指令,並獲取一些數據
指令發送到對應的 Adapter (如 V4L Adapter),就會調用相應的函數進行處理

注意到文件中定義的常量:分別對應不同的命令。

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 },
    { "CAMERA_START_IMAGE_CAPTURE",             CameraAdapter::CAMERA_START_IMAGE_CAPTURE },
    { "CAMERA_STOP_IMAGE_CAPTURE",              CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE },
    { "CAMERA_PERFORM_AUTOFOCUS",               CameraAdapter::CAMERA_PERFORM_AUTOFOCUS },
    { "CAMERA_CANCEL_AUTOFOCUS",                CameraAdapter::CAMERA_CANCEL_AUTOFOCUS },
    { "CAMERA_PREVIEW_FLUSH_BUFFERS",           CameraAdapter::CAMERA_PREVIEW_FLUSH_BUFFERS },
    { "CAMERA_START_SMOOTH_ZOOM",               CameraAdapter::CAMERA_START_SMOOTH_ZOOM },
    { "CAMERA_STOP_SMOOTH_ZOOM",                CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM },
    { "CAMERA_USE_BUFFERS_PREVIEW",             CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW },
    { "CAMERA_SET_TIMEOUT",                     CameraAdapter::CAMERA_SET_TIMEOUT },
    { "CAMERA_CANCEL_TIMEOUT",                  CameraAdapter::CAMERA_CANCEL_TIMEOUT },
    { "CAMERA_START_BRACKET_CAPTURE",           CameraAdapter::CAMERA_START_BRACKET_CAPTURE },
    { "CAMERA_STOP_BRACKET_CAPTURE",            CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE },
    { "CAMERA_QUERY_RESOLUTION_PREVIEW",        CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW },
    { "CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE", CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE },
    { "CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA",  CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA },
    { "CAMERA_USE_BUFFERS_IMAGE_CAPTURE",       CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE },
    { "CAMERA_USE_BUFFERS_PREVIEW_DATA",        CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA },
    { "CAMERA_TIMEOUT_EXPIRED",                 CameraAdapter::CAMERA_TIMEOUT_EXPIRED },
    { "CAMERA_START_FD",                        CameraAdapter::CAMERA_START_FD },
    { "CAMERA_STOP_FD",                         CameraAdapter::CAMERA_STOP_FD },
    { "CAMERA_SWITCH_TO_EXECUTING",             CameraAdapter::CAMERA_SWITCH_TO_EXECUTING },
    { "CAMERA_USE_BUFFERS_VIDEO_CAPTURE",       CameraAdapter::CAMERA_USE_BUFFERS_VIDEO_CAPTURE },
#ifdef OMAP_ENHANCEMENT_CPCAM
    { "CAMERA_USE_BUFFERS_REPROCESS",           CameraAdapter::CAMERA_USE_BUFFERS_REPROCESS },
    { "CAMERA_START_REPROCESS",                 CameraAdapter::CAMERA_START_REPROCESS },
#endif
};

BaseCameraAdapter::sendCommand():
利用 switch 將不同的命令對應到各自的邏輯中。
此處的 BaseCameraAdapter::startPreview() 實際上做什麼操作,具體的實現是在其子類中,接下來選取一個子類 V4LCameraAdapter 繼續深入。

  case CameraAdapter::CAMERA_START_PREVIEW:
            {

                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;

            }

位置:hardware/ti/omap4-aah/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h
類 V4LCameraAdapter 繼承了 BaseCameraAdapter。
注意它有一個內部私有類:
threadLoop() 應該是與線程的循環執行有關。
這個線程不斷執行 Adapter 中的 previewThread() 函數。

  virtual bool threadLoop() {
                mAdapter->previewThread();
                // loop until we need to quit
                return true;
            }

位置:hardware/ti/omap4-aah/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
startPreview():
通過 v4lIoctl() 函數從硬件獲取需要的數據,並存入 Buffers。
啓動一個 PreviewThread,用於接收從 V4L 攝像頭設備傳回的數據。
最後設置一些 flag 表明預覽功能已開啓,startPreview 的控制流程就結束了


status_t V4LCameraAdapter::startPreview()
{
    status_t ret = NO_ERROR;

  Mutex::Autolock lock(mPreviewBufsLock);

  if(mPreviewing)
    {
    return BAD_VALUE;
    }

   for (int i = 0; i < mPreviewBufferCount; i++) {

       mVideoInfo->buf.index = i;
       mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
       mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;

       ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
       if (ret < 0) {
           CAMHAL_LOGEA("VIDIOC_QBUF Failed");
           return -EINVAL;
       }

       nQueued++;
   }

    enum v4l2_buf_type bufType;
   if (!mVideoInfo->isStreaming) {
       bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;

       ret = ioctl (mCameraHandle, VIDIOC_STREAMON, &bufType);
       if (ret < 0) {
           CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno));
           return ret;
       }

       mVideoInfo->isStreaming = true;
   }

   // Create and start preview thread for receiving buffers from V4L Camera
   mPreviewThread = new PreviewThread(this);

   CAMHAL_LOGDA("Created preview thread");


   //Update the flag to indicate we are previewing
   mPreviewing = true;

   return ret;

}

previewThread():
在 PreviewThread 線程中不斷被調用。
獲取設備傳回的數據,並進行一些格式轉換操作:
convertYUV422ToNV12Tiler()
給幀數據進行一些必要的參數設置,如幀大小、時間戳等。
將幀數據發送給用戶:
sendFrameToSubscribers(&frame)


int V4LCameraAdapter::previewThread()
{
    status_t ret = NO_ERROR;
    int width, height;
    CameraFrame frame;
    void *y_uv[2];
    int index = 0;
    int stride = 4096;
    char *fp = NULL;

    mParams.getPreviewSize(&width, &height);

    if (mPreviewing) {

        fp = this->GetFrame(index);
        if(!fp) {
            ret = BAD_VALUE;
            goto EXIT;
        }
        CameraBuffer *buffer = mPreviewBufs.keyAt(index);
        CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer);
        if (!lframe) {
            ret = BAD_VALUE;
            goto EXIT;
        }

        debugShowFPS();

        if ( mFrameSubscribers.size() == 0 ) {
            ret = BAD_VALUE;
            goto EXIT;
        }
        y_uv[0] = (void*) lframe->mYuv[0];
        //y_uv[1] = (void*) lframe->mYuv[1];
        //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride);
        convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);
        CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );

#ifdef SAVE_RAW_FRAMES
        unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
        //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file
        convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
        saveFile( nv12_buff, ((width*height)*3/2) );
        free (nv12_buff);
#endif

        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;

        if (mRecording)
        {
            frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC;
            mFramesWithEncoder++;
        }

        ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
        if (ret != NO_ERROR) {
            CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
        } else {
            ret = sendFrameToSubscribers(&frame);
        }
    }
EXIT:

    return ret;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章