zoukankan      html  css  js  c++  java
  • <Android Framework 之路>Android5.1 Camera Framework(三)

    上一次讲解了一下startPreview过程,主要是为了画出一条大致的从上到下的线条,今天我们看一下Camera在Framework的sendCommand和dataCallback,这部分属于衔接过程,可以看到上下是如何交流沟通的。

    首先,sendCommand

    Camera.java中并没有sendCommand方法,在Camera.cpp中存在sendCommand函数,所以这个sendCommand是从android_hardware_interface.cpp中开始使用的

    android_hardware_Camera.cpp (basecorejni)

    startSmoothZoom
    android_hardware_Camera_startSmoothZoom
    ——>CAMERA_CMD_START_SMOOTH_ZOOM

    stopSmoothZoom
    android_hardware_Camera_stopSmoothZoom
    ——>CAMERA_CMD_STOP_SMOOTH_ZOOM

    setDisplayOrientation
    android_hardware_Camera_setDisplayOrientation
    ——>CAMERA_CMD_SET_DISPLAY_ORIENTATION

    _enableShutterSound
    android_hardware_Camera_enableShutterSound
    ——>CAMERA_CMD_ENABLE_SHUTTER_SOUND

    _startFaceDetection
    android_hardware_Camera_startFaceDetection
    ——>CAMERA_CMD_START_FACE_DETECTION

    _stopFaceDetection
    android_hardware_Camera_stopFaceDetection
    ——>CAMERA_CMD_STOP_FACE_DETECTION

    enableFocusMoveCallback
    android_hardware_Camera_enableFocusMoveCallback
    ——>CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG

    诸如此类的命令类型定义在Camera.h (systemcoreincludesystem)
    enum {
    CAMERA_CMD_START_SMOOTH_ZOOM = 1,
    CAMERA_CMD_STOP_SMOOTH_ZOOM = 2,
    CAMERA_CMD_SET_DISPLAY_ORIENTATION = 3,
    CAMERA_CMD_ENABLE_SHUTTER_SOUND = 4,
    CAMERA_CMD_PLAY_RECORDING_SOUND = 5,
    CAMERA_CMD_START_FACE_DETECTION = 6,
    CAMERA_CMD_STOP_FACE_DETECTION = 7,
    CAMERA_CMD_ENABLE_FOCUS_MOVE_MSG = 8,
    CAMERA_CMD_PING = 9,
    CAMERA_CMD_SET_VIDEO_BUFFER_COUNT = 10,
    };

    以上者几种操作都是采用sendCommand()的函数来实现的,对应的命令类型也列举出来了,HAL层会根据这个消息类型做出判断,然后做出对应的操作。
    来看下sendCommand的实现:
    Camera.cpp (frameworksavcamera)

    // send command to camera driver
    status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
    {
        ALOGV("sendCommand");
        sp <ICamera> c = mCamera;
        if (c == 0) return NO_INIT;
        return c->sendCommand(cmd, arg1, arg2);  //三个参数,第一个是消息类型,后面两个参数有时候使用有时不使用,这里应该是具有扩展性的,如果需要添加更多的参数,上下接口同时修改就可以了。
    }

    然后通过Binder机制,

        virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
        {
            ALOGV("sendCommand");
            Parcel data, reply;
            data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
            data.writeInt32(cmd);
            data.writeInt32(arg1);
            data.writeInt32(arg2);
            remote()->transact(SEND_COMMAND, data, &reply);
            return reply.readInt32();
        }
    status_t BnCamera::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
            ......
            case SEND_COMMAND: {
                ALOGV("SEND_COMMAND");
                CHECK_INTERFACE(ICamera, data, reply);
                int command = data.readInt32();
                int arg1 = data.readInt32();
                int arg2 = data.readInt32();
                reply->writeInt32(sendCommand(command, arg1, arg2));
                return NO_ERROR;
             } break;
    }

    然后调用到

    status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
        ......
        if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
            // Mirror the preview if the camera is front-facing.
            orientation = getOrientation(arg1, mCameraFacing == CAMERA_FACING_FRONT);
            if (orientation == -1) return BAD_VALUE;
    
            if (mOrientation != orientation) {
                mOrientation = orientation;
                if (mPreviewWindow != 0) {
                    native_window_set_buffers_transform(mPreviewWindow.get(),
                            mOrientation);
                }
            }
            return OK;
        } else if (cmd == CAMERA_CMD_ENABLE_SHUTTER_SOUND) {
            switch (arg1) {    //这里就是对参数arg1的使用,通过参数来开关拍照声音
                case 0: 
                    return enableShutterSound(false);
                case 1:
                    return enableShutterSound(true);
                default:
                    return BAD_VALUE;
            }
            return OK;
        } else if (cmd == CAMERA_CMD_PLAY_RECORDING_SOUND) { //录像声音
            mCameraService->playSound(CameraService::SOUND_RECORDING);
        } else if (cmd == CAMERA_CMD_SET_VIDEO_BUFFER_COUNT) {
            // Silently ignore this command
            return INVALID_OPERATION;
        } else if (cmd == CAMERA_CMD_PING) {
            // If mHardware is 0, checkPidAndHardware will return error.
            return OK;
        } //以上是framework可以处理的命令
        return mHardware->sendCommand(cmd, arg1, arg2);  //HAL层处理
    }

    在HAL层中处理的消息类型主要是打开和停止人脸检测过程,
    QCamera2HWI.cpp (deviceasusflocameraqcamera2hal)

    int QCamera2HardwareInterface::sendCommand(int32_t command, int32_t /*arg1*/, int32_t /*arg2*/)
    {
        int rc = NO_ERROR;
        switch (command) {
        case CAMERA_CMD_START_FACE_DETECTION:
        case CAMERA_CMD_STOP_FACE_DETECTION:
            //开关人脸检测
            rc = setFaceDetection(command == CAMERA_CMD_START_FACE_DETECTION? true : false);
            break;
        default:
            rc = NO_ERROR;
            break;
        }
        return rc;
    }

    综上,如上就是sendCommand的过程

    然后,回调Callback

    从之前的文章可以看到callback主要有三种类型
    notifyCallback
    dataCallback
    dataTimestampCallback

    这个过程我们就不能按照之前的从上至下的跟过程了,这次需要反着来,从HAL层回调到
    CameraHardwareInterface.h (frameworksavservicescameralibcameraservicedevice1)

        static void __notify_cb(int32_t msg_type, int32_t ext1,
                                int32_t ext2, void *user)
        {
            ALOGV("%s", __FUNCTION__);
            CameraHardwareInterface *__this =
                    static_cast<CameraHardwareInterface *>(user);
            __this->mNotifyCb(msg_type, ext1, ext2, __this->mCbUser);
        }
    
        static void __data_cb(int32_t msg_type,
                              const camera_memory_t *data, unsigned int index,
                              camera_frame_metadata_t *metadata,
                              void *user)
        {
            ALOGV("%s", __FUNCTION__);
            CameraHardwareInterface *__this =
                    static_cast<CameraHardwareInterface *>(user);
            ......
            __this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser);
        }
    
        static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
                                 const camera_memory_t *data, unsigned index,
                                 void *user)
        {
            ALOGV("%s", __FUNCTION__);
            CameraHardwareInterface *__this =
                    static_cast<CameraHardwareInterface *>(user);
            ......
            __this->mDataCbTimestamp(timestamp, msg_type, mem->mBuffers[index], __this->mCbUser);
        }

    其中的mNotifyCb,mDataCb,mDataCbTimestamp是在CameraClient::initialize函数中设置的

        void setCallbacks(notify_callback notify_cb,
                          data_callback data_cb,
                          data_callback_timestamp data_cb_timestamp,
                          void* user)
        {
            mNotifyCb = notify_cb;
            mDataCb = data_cb;
            mDataCbTimestamp = data_cb_timestamp;
            mCbUser = user;
    
            ALOGV("%s(%s)", __FUNCTION__, mName.string());
    
            if (mDevice->ops->set_callbacks) {
                mDevice->ops->set_callbacks(mDevice,
                                       __notify_cb,
                                       __data_cb,
                                       __data_cb_timestamp,
                                       __get_memory,
                                       this);
            }
        }

    回调自然是到CameraClient中去找了

    void CameraClient::notifyCallback(int32_t msgType, int32_t ext1,
            int32_t ext2, void* user) {
        ......
    }
    
    void CameraClient::dataCallback(int32_t msgType,
            const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata, void* user) {
        LOG2("dataCallback(%d)", msgType);
    
        Mutex* lock = getClientLockFromCookie(user);
        if (lock == NULL) return;
        Mutex::Autolock alock(*lock);
    
        CameraClient* client =
                static_cast<CameraClient*>(getClientFromCookie(user));
        if (client == NULL) return;
    
        if (!client->lockIfMessageWanted(msgType)) return;
        if (dataPtr == 0 && metadata == NULL) {
            ALOGE("Null data returned in data callback");
            client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
            return;
        }
    
        switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
            case CAMERA_MSG_PREVIEW_FRAME:
                client->handlePreviewData(msgType, dataPtr, metadata);
                break;
            case CAMERA_MSG_POSTVIEW_FRAME:
                client->handlePostview(dataPtr);
                break;
            case CAMERA_MSG_RAW_IMAGE:
                client->handleRawPicture(dataPtr);
                break;
            case CAMERA_MSG_COMPRESSED_IMAGE:
                client->handleCompressedPicture(dataPtr);
                break;
            default:
                client->handleGenericData(msgType, dataPtr, metadata);
                break;
        }
    }
    
    void CameraClient::dataCallbackTimestamp(nsecs_t timestamp,
            int32_t msgType, const sp<IMemory>& dataPtr, void* user) {
        ......
    }

    这里主要看下dataCallback的过程吧,

        switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
            case CAMERA_MSG_PREVIEW_FRAME:  //预览帧数据
                client->handlePreviewData(msgType, dataPtr, metadata);
                break;
            case CAMERA_MSG_POSTVIEW_FRAME: //postview image
                client->handlePostview(dataPtr);
                break;
            case CAMERA_MSG_RAW_IMAGE:   //原始数据
                client->handleRawPicture(dataPtr);
                break;
            case CAMERA_MSG_COMPRESSED_IMAGE: //真实图片
                client->handleCompressedPicture(dataPtr);
                break;
            default:
                client->handleGenericData(msgType, dataPtr, metadata);
                break;
        }

    这里最后会调用到
    c->dataCallback,然后根据消息类型来做处理,然后在通过binder机制

        // generic data callback from camera service to app with image data
        void dataCallback(int32_t msgType, const sp<IMemory>& imageData,
                          camera_frame_metadata_t *metadata)
        {
            ALOGV("dataCallback");
            Parcel data, reply;
            data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
            data.writeInt32(msgType);
            data.writeStrongBinder(imageData->asBinder());
            if (metadata) {
                data.writeInt32(metadata->number_of_faces);
                data.write(metadata->faces, sizeof(camera_face_t) * metadata->number_of_faces);
            }
            remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
        }
    status_t BnCameraClient::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        switch(code) {
            ......
            case DATA_CALLBACK: {
                ALOGV("DATA_CALLBACK");
                CHECK_INTERFACE(ICameraClient, data, reply);
                int32_t msgType = data.readInt32();
                sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
                camera_frame_metadata_t *metadata = NULL;
                if (data.dataAvail() > 0) {
                    metadata = new camera_frame_metadata_t;
                    metadata->number_of_faces = data.readInt32();
                    metadata->faces = (camera_face_t *) data.readInplace(
                            sizeof(camera_face_t) * metadata->number_of_faces);
                }
                dataCallback(msgType, imageData, metadata);
                if (metadata) delete metadata;
                return NO_ERROR;
            } break;
            ......
    }

    这里转到Camera.cpp

    // callback from camera service when frame or image is ready
    void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
                              camera_frame_metadata_t *metadata)
    {
        sp<CameraListener> listener;
        {
            Mutex::Autolock _l(mLock);
            listener = mListener;
        }
        if (listener != NULL) {
            listener->postData(msgType, dataPtr, metadata);
        }
    }

    通过listener的方式来往上层甩数据,那么问题来了,这个listener是什么时候设置的?
    回想一下第一篇FWK分析博客中的native_setup过程中有这么一段

        sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
        context->incStrong((void*)android_hardware_Camera_native_setup);
        camera->setListener(context);

    就是在这里设置的listener,JNICameraContext继承CameraListener,复写父类的方法

    class JNICameraContext: public CameraListener{
        ......   
    }
    
    class CameraListener: virtual public RefBase
    {
    public:
        virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
        virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
                              camera_frame_metadata_t *metadata) = 0;
        virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
    };

    承接上面那一段,这里我们只看postData()
    android_hardware_Camera.cpp (frameworksasecorejni)

    void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr,
                                    camera_frame_metadata_t *metadata)
    {
        ......
        int32_t dataMsgType = msgType & ~CAMERA_MSG_PREVIEW_METADATA;
    
        // return data based on callback type
        switch (dataMsgType) {
            case CAMERA_MSG_VIDEO_FRAME:
                // should never happen
                break;
    
            // For backward-compatibility purpose, if there is no callback
            // buffer for raw image, the callback returns null.
            case CAMERA_MSG_RAW_IMAGE:
                ALOGV("rawCallback");
                if (mRawImageCallbackBuffers.isEmpty()) {
                    env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
                            mCameraJObjectWeak, dataMsgType, 0, 0, NULL);
                } else {
                    copyAndPost(env, dataPtr, dataMsgType);
                }
                break;
    
            // There is no data.
            case 0:
                break;
    
            default:
                ALOGV("dataCallback(%d, %p)", dataMsgType, dataPtr.get());
                copyAndPost(env, dataPtr, dataMsgType);
                break;
        }
        // post frame metadata to Java
        if (metadata && (msgType & CAMERA_MSG_PREVIEW_METADATA)) {
            postMetadata(env, CAMERA_MSG_PREVIEW_METADATA, metadata);//这里有人脸数据
        }
    }

    这里涉及到的
    env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
    mCameraJObjectWeak, dataMsgType, 0, 0, NULL);
    copyAndPost(env, dataPtr, dataMsgType);
    postMetadata(env, CAMERA_MSG_PREVIEW_METADATA, metadata);
    直接或间接的使用到fileds.post_event函数,这里是JNI中的方法注册,
    fields.post_event = env->GetStaticMethodID(clazz, “postEventFromNative”,
    “(Ljava/lang/Object;IIILjava/lang/Object;)V”);
    这个是在register_android_hardware_Camera()函数中调用的,这里不做过多停留,这个实际会调用到
    Camera.java (frameworksasecorejavaandroidhardware)

        private static void postEventFromNative(Object camera_ref,
                                                int what, int arg1, int arg2, Object obj)
        {
            Camera c = (Camera)((WeakReference)camera_ref).get();
            if (c == null)
                return;
    
            if (c.mEventHandler != null) {
                Message m = c.mEventHandler.obtainMessage(what, arg1, arg2, obj);
                c.mEventHandler.sendMessage(m);
            }
        }

    这里也是采用了JAVA中很常用的handler message处理

        private class EventHandler extends Handler
        {
            private final Camera mCamera;
    
            public EventHandler(Camera c, Looper looper) {
                super(looper);
                mCamera = c;
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch(msg.what) {
                case CAMERA_MSG_SHUTTER:
                    if (mShutterCallback != null) {
                        mShutterCallback.onShutter();
                    }
                    return;
    
                case CAMERA_MSG_RAW_IMAGE:
                    if (mRawImageCallback != null) {
                        mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_COMPRESSED_IMAGE:
                    if (mJpegCallback != null) {
                        mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_PREVIEW_FRAME:
                    PreviewCallback pCb = mPreviewCallback;
                    if (pCb != null) {
                        if (mOneShot) {
                            // Clear the callback variable before the callback
                            // in case the app calls setPreviewCallback from
                            // the callback function
                            mPreviewCallback = null;
                        } else if (!mWithBuffer) {
                            // We're faking the camera preview mode to prevent
                            // the app from being flooded with preview frames.
                            // Set to oneshot mode again.
                            setHasPreviewCallback(true, false);
                        }
                        pCb.onPreviewFrame((byte[])msg.obj, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_POSTVIEW_FRAME:
                    if (mPostviewCallback != null) {
                        mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_FOCUS:
                    AutoFocusCallback cb = null;
                    synchronized (mAutoFocusCallbackLock) {
                        cb = mAutoFocusCallback;
                    }
                    if (cb != null) {
                        boolean success = msg.arg1 == 0 ? false : true;
                        cb.onAutoFocus(success, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_ZOOM:
                    if (mZoomListener != null) {
                        mZoomListener.onZoomChange(msg.arg1, msg.arg2 != 0, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_PREVIEW_METADATA:
                    if (mFaceListener != null) {
                        mFaceListener.onFaceDetection((Face[])msg.obj, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_ERROR :
                    Log.e(TAG, "Error " + msg.arg1);
                    if (mErrorCallback != null) {
                        mErrorCallback.onError(msg.arg1, mCamera);
                    }
                    return;
    
                case CAMERA_MSG_FOCUS_MOVE:
                    if (mAutoFocusMoveCallback != null) {
                        mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera);
                    }
                    return;
    
                default:
                    Log.e(TAG, "Unknown message type " + msg.what);
                    return;
                }
            }
        }

    到这里基本上就是上层的处理了,callback都是在相机应用中设置的,然后各种数据就在相机应用中得到对应的处理。

    具体的每一个数据怎么处理,这里我们不做分析,后续有需要,可以在细讲一下,旨在弄清楚代码是怎么走的。

    本文中代码使用的是Android5.1原始代码,欢迎大家留言交流。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    结对项目电梯调度--设计模拟
    程序的单元测试
    一个文本单词统计的案例
    MFC vs2012 Office2013 读写excel文件
    Unix NetWork Programming(unix环境编程)——环境搭建(解决unp.h等源码编译问题)
    VMware三种上网模型
    矩阵求逆算法及程序实现(C++)
    unix环境高级编程基础知识之第四章
    2014阿里研发面试题目
    MFC下debug改成release版本出现问题及解决办法
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467217.html
Copyright © 2011-2022 走看看