IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Camera: SnapdragonCamera OpenCamera(一) -> 正文阅读

[移动开发]Camera: SnapdragonCamera OpenCamera(一)

? ? ? ? 高通SnapdragonCamera相机研究一系列OpenCamer相关的流程,以及比较重要的需要check的Error状态的捕捉和监听。

?1.应用层OpenCamera?

????????CameraActivity::onCreate ->?cameraAPICheck();这边会走一下openCamera的流程,不过有返回就给release,这边open一下的目的怕是仅仅虚晃一枪,试试API1的接口还能不能走了吧。

private boolean cameraAPICheck() {
        boolean support = true;
        try {
            //使用Method方法通过调用android.hardware.Camera的openLegacy方法打开Camera
            Method openMethod = Class.forName("android.hardware.Camera").getMethod(
                    "openLegacy", int.class, int.class);
            
            //这边用来接收的是FrameWork层Camera的实例
            Camera camera = (android.hardware.Camera) openMethod.invoke(
                    null, 0, CAMERA_HAL_API_VERSION_1_0);

            //这里就有点那个啥了,好不容易打开了,然后又给release了,不着急后面切换到具体mode时候还要openLegacy
            camera.release();

        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
            if (e.getCause().getLocalizedMessage().indexOf("Unknown camera error") != -1) {
                support = false;
            }
        } finally {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            SharedPreferences.Editor editor = preferences.edit();
            editor.putBoolean(CAMERA_API_1_SUPPORT,support);
            editor.commit();
            return support;
        }
    }

? ? ? ? CameraActivity::onCreate->setModuleFromIndex(moduleIndex);真正的openCamera流程是在每一个module里面的,下面以PhotoModule为例研究一下。

private void setModuleFromIndex(int moduleIndex) {
        mCameraPhotoModuleRootView.setVisibility(View.GONE);
        mCameraVideoModuleRootView.setVisibility(View.GONE);
        mCameraPanoModuleRootView.setVisibility(View.GONE);
        mCameraCaptureModuleRootView.setVisibility(View.GONE);
        mCurrentModuleIndex = moduleIndex;
        switch (moduleIndex) {
            case ModuleSwitcher.VIDEO_MODULE_INDEX:
                if(mVideoModule == null) {
                    mVideoModule = new VideoModule();
                    mVideoModule.init(this, mCameraVideoModuleRootView);
                } else {
                    mVideoModule.reinit();
                }
                mCurrentModule = mVideoModule;
                mCameraVideoModuleRootView.setVisibility(View.VISIBLE);
                break;

            case ModuleSwitcher.PHOTO_MODULE_INDEX:
                if(mPhotoModule == null) {
                    mPhotoModule = new PhotoModule();

                    //init里面添加了openCamera的功能
                    mPhotoModule.init(this, mCameraPhotoModuleRootView);
                } else {
                    mPhotoModule.reinit();
                }
                mCurrentModule = mPhotoModule;
                mCameraPhotoModuleRootView.setVisibility(View.VISIBLE);
                break;

            ...
}

?LA.UM.8.6.2/LINUX/android/packages/apps/SnapdragonCamera/src/com/android/camera/PhotoModule.java

@Override
    public void init(CameraActivity activity, View parent) {
        mActivity = activity;
        mRootView = parent;
        mPreferences = ComboPreferences.get(mActivity);
        if (mPreferences == null) {
            mPreferences = new ComboPreferences(mActivity);
        }

        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal(), activity);
        mCameraId = getPreferredCameraId(mPreferences);

        mContentResolver = mActivity.getContentResolver();

        // Surface texture is from camera screen nail and startPreview needs it.
        // This must be done before startPreview.
        mIsImageCaptureIntent = isImageCaptureIntent();

        mPreferences.setLocalId(mActivity, mCameraId);
        CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());

        mUI = new PhotoUI(activity, this, parent);
        if (mOpenCameraThread == null) {

            //这边重新开了一个线程去做openCamera的流程
            mOpenCameraThread = new OpenCameraThread();
            mOpenCameraThread.start();
        }
        
        ...
}

private class OpenCameraThread extends Thread {
        @Override
        public void run() {
            openCamera();
            startPreview();
        }
    }

private OpenCameraThread mOpenCameraThread = null;

private void openCamera() {
        if (mPaused) {
            return;
        }
        Log.v(TAG, "Open camera device.");
        
        //这边的mCameraDevice是应用层用来接收的CameraProxy
        mCameraDevice = CameraUtil.openCamera(
                mActivity, mCameraId, mHandler,
                mActivity.getCameraOpenErrorCallback());
        if (mCameraDevice == null) {
            Log.e(TAG, "Failed to open camera:" + mCameraId);
            mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
            return;
        }
        mParameters = mCameraDevice.getParameters();
        mCameraPreviewParamsReady = true;
        initializeCapabilities();
        mHandler.sendEmptyMessageDelayed(CAMERA_OPEN_DONE, 100);
        return;
    }

?LA.UM.8.6.2/LINUX/android/packages/apps/SnapdragonCamera/src/com/android/camera/util/CameraUtil.java

public static CameraManager.CameraProxy openCamera(
            Activity activity, final int cameraId,
            Handler handler, final CameraManager.CameraOpenErrorCallback cb) {
        try {
            throwIfCameraDisabled(activity);
            return CameraHolder.instance().open(handler, cameraId, cb);
        } catch (CameraDisabledException ex) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    cb.onCameraDisabled(cameraId);
                }
            });
        }
        return null;
    }

?LA.UM.8.6.2/LINUX/android/packages/apps/SnapdragonCamera/src/com/android/camera/CameraHolder.java

 public synchronized CameraProxy open(
            Handler handler, int cameraId,
            CameraManager.CameraOpenErrorCallback cb) {
        if (DEBUG_OPEN_RELEASE) {
            collectState(cameraId, mCameraDevice);
            if (mCameraOpened) {
                Log.e(TAG, "double open");
                dumpStates();
            }
        }
        Assert(!mCameraOpened);
        if (mCameraDevice != null && mCameraId != cameraId) {
            mCameraDevice.release();
            mCameraDevice = null;
            mCameraId = -1;
        }
        if (mCameraDevice == null) {
            Log.v(TAG, "open camera " + cameraId);
            if (mMockCameraInfo == null) {
                mCameraDevice = CameraManagerFactory
                        .getAndroidCameraManager().cameraOpen(handler, cameraId, cb);
            } else {
                if (mMockCamera != null) {
                    mCameraDevice = mMockCamera[cameraId];
                } else {
                    Log.e(TAG, "MockCameraInfo found, but no MockCamera provided.");
                    mCameraDevice = null;
                }
            }

         ...
}

?LA.UM.8.6.2/LINUX/android/packages/apps/SnapdragonCamera/src/com/android/camera/AndroidCameraManagerImpl.java

@Override
    public CameraManager.CameraProxy cameraOpen(
        Handler handler, int cameraId, CameraOpenErrorCallback callback) {
        mCameraHandler.errorCbInstance = CameraOpenErrorCallbackForward
                .getNewInstance(handler, callback);
        mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0, mCameraHandler.errorCbInstance)
                .sendToTarget();
        mCameraHandler.waitDone();
        if (mCamera != null) {
            //AndroidCameraProxyImpl继承的CameraProxy,通过这个应用层代理可以做所有的流的管理
            return new AndroidCameraProxyImpl();
        } else {
            return null;
        }
    }

@Override
        public void handleMessage(final Message msg) {
            try {
                switch (msg.what) {
                    case OPEN_CAMERA:
                        try {
                            Method openMethod = Class.forName("android.hardware.Camera").getMethod(
                                    "openLegacy", int.class, int.class);
                            
                            //与CameraActivity一样的OpenCamera方法
                            mCamera = (android.hardware.Camera) openMethod.invoke(
                                    null, msg.arg1, CAMERA_HAL_API_VERSION_1_0);
                        } catch (Exception e) {
                            /* Retry with open if openLegacy doesn't exist/fails */
                            Log.v(TAG, "openLegacy failed due to " + e.getMessage()
                                    + ", using open instead");

                            //调用了高通另一个openCamera的方法
                            mCamera = android.hardware.Camera.open(msg.arg1);
                        }

                        if (mCamera != null) {
                            mParametersIsDirty = true;

                            // Get a instance of Camera.Parameters for later use.
                            if (mParamsToSet == null) {
                                mParamsToSet = mCamera.getParameters();
                            }
                        } else {
                            if (msg.obj != null) {
                                ((CameraOpenErrorCallback) msg.obj).onDeviceOpenFailure(msg.arg1);
                            }
                        }
                        return;

            ...
}

? ? ? ? 应用层OpenCamera流程到现在就走完了,但是真正接触项目时,光知道流程是不够的,必须要监控这个流程的状态,有没有正常走完,open是否成功,这一部分的监控是必不可少的。高通SnapdragonCamera CameraOpenErrorCallback是在应用层通过一些抛出的异常做监控的,而MTK Camera是在底层会有onOpend或onError的回调来处理的。

LA.UM.8.6.2/LINUX/android/packages/apps/SnapdragonCamera/src/com/android/camera/CameraManager.java

 public interface CameraOpenErrorCallback {
        /**
         * Callback when {@link com.android.camera.CameraDisabledException} is
         * caught.
         *
         * @param cameraId The disabled camera.
         */

        //CameraUtil OpenCamera时抛出
        public void onCameraDisabled(int cameraId);

        /**
         * Callback when {@link com.android.camera.CameraHardwareException} is
         * caught.
         *
         * @param cameraId The camera with the hardware failure.
         */

        //AndroidCameraManagerImpl时没有获得FrameWork返回时抛出
        public void onDeviceOpenFailure(int cameraId);

        /**
         * Callback when {@link java.io.IOException} is caught during
         * {@link android.hardware.Camera#reconnect()}.
         *
         * @param mgr The {@link com.android.camera.CameraManager}
         *            with the reconnect failure.
         */
        public void onReconnectionFailure(CameraManager mgr);

        /**
         * Callback when startPreview failure runtime exception is
         * caught.
         *
         * @param cameraId The camera with the hardware failure.
         */

        //PhotoModule里面通过应用层代理CameraProxy去SetPreviewDisplay、startPreview时有异常会抛出
        public void onStartPreviewFailure(int cameraId);

    }

? ? ?

2.应用层对CameraDevice整个状态的监控??

????????高通晓龙相机在应用层还需要check一个底层绑定的error的回调,用来check整个device的状态是否正常。

public class CameraErrorCallback
        implements android.hardware.Camera.ErrorCallback {
    public CameraActivity mActivity = null;
    //custom error code for thermal shutdown. This should be in sync
    //with HAL.
    private static final int THERMAL_SHUTDOWN = 50;

    public void setActivity(CameraActivity activity) {
        mActivity = activity;
    }

    @Override
    public void onError(int error, android.hardware.Camera camera) {
        Log.e(TAG, "Got camera error callback. error=" + error);
        if (mActivity != null) {
            final int resId;
            switch (error) {
                case android.hardware.Camera.CAMERA_ERROR_SERVER_DIED:
                    resId = R.string.camera_server_died;
                    break;
                case THERMAL_SHUTDOWN:
                    resId = R.string.camera_thermal_shutdown;
                    break;
                case android.hardware.Camera.CAMERA_ERROR_UNKNOWN:
                default:
                    resId = R.string.camera_unknown_error;
                    break;
            }
            mActivity.runOnUiThread(new Runnable() {
                public void run() {
                     RotateTextToast.makeText(mActivity, resId, Toast.LENGTH_LONG).show();
                     mActivity.finish();
                }
            });
        } else {
            throw new RuntimeException("Unknown error");
        }
    }
}

? ? ? ? PhotoModule里面将继承自FrameWork Camera的errorCallback?绑定起来.

    private void startPreview() {
        if (mPaused || mCameraDevice == null || mParameters == null) {
            return;
        }

        synchronized (mCameraDevice) {
            SurfaceHolder sh = null;
            Log.v(TAG, "startPreview: SurfaceHolder (MDP path)");
            if (mUI != null) {
                sh = mUI.getSurfaceHolder();
            }

            // Let UI set its expected aspect ratio
            mCameraDevice.setPreviewDisplay(sh);
        }

        if (!mCameraPreviewParamsReady) {
            Log.w(TAG, "startPreview: parameters for preview are not ready.");
            return;
        }

        //Error在openCamera之后,startPreview之前设置
        mErrorCallback.setActivity(mActivity);
        //mCameraDevice为应用层代理CameraProxy
        mCameraDevice.setErrorCallback(mErrorCallback);
    
        ...
}

? ? ? ? 下面就详细研究一下HAL捕获到sensor异常,2.5s之后没有数据传输抛出异常之后,一直传给应用层,应用层做相关的规避处理的过程。

LA.UM.8.6.2/LINUX/android/vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/mct/controller/mct_controller.c

boolean mct_controller_send_cb(mct_pipeline_t *pipeline,
  mct_bus_msg_type_t type)
{
  boolean rc = FALSE;
  mct_pipeline_get_stream_info_t info;
  mct_stream_t *parm_stream = NULL;

  switch (type) {

    case MCT_BUS_MSG_SEND_HW_ERROR: {
      CLOGE(CAM_MCT_MODULE, "FATAL: Sending HW_Error");

      //捕获到HW异常,发送了CAM_EVENT_TYPE_DAEMON_DIED信号
      rc = mct_controller_notify_hal_internal_event(pipeline,
      CAM_EVENT_TYPE_DAEMON_DIED);
      info.check_type  = CHECK_INDEX;
      info.stream_index  = MCT_SESSION_STREAM_ID;
      parm_stream = mct_pipeline_get_stream(pipeline, &info);
      if (!parm_stream) {
        CLOGE(CAM_MCT_MODULE, "Couldn't find session stream");
        rc = FALSE;
        break;
      }
      parm_stream->state = MCT_ST_STATE_BAD;
    }

    ...
}

?LA.UM.8.6.2/LINUX/android/hardware/qcom/camera/QCamera2/HAL/QCameraStateMachine.cpp

case QCAMERA_SM_EVT_EVT_NOTIFY:
        {
            mm_camera_event_t *cam_evt = (mm_camera_event_t *)payload;
            switch (cam_evt->server_event_type) {
            case CAM_EVENT_TYPE_DAEMON_DIED:
                {
                    //发送CAMERA_ERROR_SERVER_DIED信号
                    m_parent->sendEvtNotify(CAMERA_MSG_ERROR,
                                            CAMERA_ERROR_SERVER_DIED,
                                            0);
                }
                break;
            default:
                LOGE("Invalid internal event %d in state(%d)",
                             cam_evt->server_event_type, m_state);
                break;
            }
        }
        break;

?LA.UM.8.6.2/LINUX/android/frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp

void Camera2Client::notifyError(int32_t errorCode,
        const CaptureResultExtras& resultExtras) {
    int32_t err = CAMERA_ERROR_UNKNOWN;
    switch(errorCode) {
        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED:
            err = CAMERA_ERROR_RELEASED;
            break;
        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE:
            err = CAMERA_ERROR_UNKNOWN;
            break;
        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE:
            err = CAMERA_ERROR_SERVER_DIED;
            break;
        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
        case hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
            ALOGW("%s: Received recoverable error %d from HAL - ignoring, requestId %" PRId32,
                    __FUNCTION__, errorCode, resultExtras.requestId);
            mCaptureSequencer->notifyError(errorCode, resultExtras);
            return;
        default:
            err = CAMERA_ERROR_UNKNOWN;
            break;
    }

    ALOGE("%s: Error condition %d reported by HAL, requestId %" PRId32, __FUNCTION__, errorCode,
              resultExtras.requestId);

    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
    if (l.mRemoteCallback != nullptr) {
        l.mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, err, 0);
    }
}

?LA.UM.8.6.2/LINUX/android/frameworks/base/core/java/android/hardware/Camera.java

 case CAMERA_MSG_ERROR :
                Log.e(TAG, "Error " + msg.arg1);
                if (mDetailedErrorCallback != null) {
                    mDetailedErrorCallback.onError(msg.arg1, mCamera);
                } else if (mErrorCallback != null) {
                    if (msg.arg1 == CAMERA_ERROR_DISABLED) {
                        mErrorCallback.onError(CAMERA_ERROR_EVICTED, mCamera);
                    } else {
                        mErrorCallback.onError(msg.arg1, mCamera);
                    }
                }
                return;

? ? ? ? ?剩下的Error信息通过应用层的CameraErrorCallBack来接收就好了,下图是用来追踪、定位问题的log。

小结:

? ? ? ? 本篇从应用层角度check了晓龙相机openCamera的阶段,重点放在了项目中遇到异常之后的监控、获取机制上,便于项目开展之后的问题分析。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:18:44  更:2021-07-22 14:19:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 17:09:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码