Android笔记——Camera

最近用到Camera.java这个类,记录下在开发过程中遇到的一些问题和最终是如何解决的。


1、ActivityCamera的启动和关闭十分缓慢,在普通性能的手机上运行比较明显;


分析:

从获取Camera的实例和进行一些配置后,到开启预览startPreview整个过程的占用主线程时间较长,直接影响了Activity的启动。
private void initCamera(SurfaceHolder surfaceHolder){
        if (mCamera==null) {
            try {
                mCamera = Camera.open();//打开后置摄像头

            }catch (RuntimeException e){

            }
        }
        if (surfaceHolder!=null && sCamera!=null){
            try {
                sCamera.setPreviewDisplay(surfaceHolder);
                initFromCameraParameters(sCamera.getParameters());
                setDesiredCameraParameters(sCamera);
                sCamera.startPreview();
                sCamera.autoFocus(focusCallBack);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

一开始直接开启了一个子线程将initCamera直接放在子线程中执行,发现Activity启动时间确实不再受影响,但是释放Camera的时候并没有效果,分析Camera的源码发现,

1、Camera.open();打开默认的后置摄像头CAMERA_FACING_BACK

public static Camera open() {
       int numberOfCameras = getNumberOfCameras();
       CameraInfo cameraInfo = new CameraInfo();
       for (int i = 0; i < numberOfCameras; i++) {
           getCameraInfo(i, cameraInfo);
           if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
               return new Camera(i);
           }
       }
       return null;   
 }

1.2、new Camera(cameraId);

Camera(int cameraId) {
        int err = cameraInitNormal(cameraId);
        if (checkInitErrors(err)) {
            if (err == -EACCES) {
                throw new RuntimeException("Fail to connect to camera service");
            } else if (err == -ENODEV) {
                throw new RuntimeException("Camera initialization failed");
            }
            // Should never hit this.
            throw new RuntimeException("Unknown camera error");
        }
    }

1.3、int err = cameraInitNormal(cameraId);

private int cameraInitNormal(int cameraId) {
        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
    }

其中halVersion是硬件版本号

private int cameraInitVersion(int cameraId, int halVersion) {
        mShutterCallback = null;
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mUsingPreviewAllocation = false;
        mZoomListener = null;

        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        return native_setup(new WeakReference<Camera>(this), cameraId, halVersion,
                ActivityThread.currentOpPackageName());
    }
private native final int native_setup(Object camera_this, int cameraId, int halVersion,
                                           String packageName);

native_setup是一个本地方法,具体是在:/frameworks/base/core/jni/android_hardware_Camera.cpp

// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
    // Convert jstring to String16
    const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
        env->GetStringChars(clientPackageName, NULL));
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName,
                            reinterpret_cast<const jchar*>(rawClientName));

    sp<Camera> camera;
    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
        // Default path: hal version is don't care, do normal camera connect.
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID);
    } else {
        jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
                Camera::USE_CALLING_UID, camera);
        if (status != NO_ERROR) {
            return status;
        }
    }

    if (camera == NULL) {
        return -EACCES;
    }

    // make sure camera hardware is alive
    if (camera->getStatus() != NO_ERROR) {
        return NO_INIT;
    }

    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
        // This should never happen
        jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
        return INVALID_OPERATION;
    }

    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong((void*)android_hardware_Camera_native_setup);
    camera->setListener(context);

    // save context in opaque field
    env->SetLongField(thiz, fields.context, (jlong)context.get());
    return NO_ERROR;
}


----------

2、mCamera.setPreviewDisplay(surfaceHolder);


 public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
        if (holder != null) {
            setPreviewSurface(holder.getSurface());
        } else {
            setPreviewSurface((Surface)null);
        }
    }
public native final void setPreviewSurface(Surface surface) throws IOException;
static void android_hardware_Camera_setPreviewSurface(JNIEnv *env, jobject thiz, jobject jSurface)
{
    ALOGV("setPreviewSurface");
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    sp<IGraphicBufferProducer> gbp;
    sp<Surface> surface;
    if (jSurface) {
        surface = android_view_Surface_getSurface(env, jSurface);
        if (surface != NULL) {
            gbp = surface->getIGraphicBufferProducer();
        }
    }

    if (camera->setPreviewTarget(gbp) != NO_ERROR) {
        jniThrowException(env, "java/io/IOException", "setPreviewTexture failed");
    }
}

3、mCamera.startPreview();开启预览


public native final void startPreview();
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
    ALOGV("startPreview");
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    if (camera->startPreview() != NO_ERROR) {
        jniThrowRuntimeException(env, "startPreview failed");
        return;
    }
}

释放和关闭相机

static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
{
    ALOGV("stopPreview");
    sp<Camera> c = get_native_camera(env, thiz, NULL);
    if (c == 0) return;

    c->stopPreview();
}
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
{
    ALOGV("release camera");
    JNICameraContext* context = NULL;
    sp<Camera> camera;
    {
        Mutex::Autolock _l(sLock);
        context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context));

        // Make sure we do not attempt to callback on a deleted Java object.
        env->SetLongField(thiz, fields.context, 0);
    }

    // clean up if release has not been called before
    if (context != NULL) {
        camera = context->getCamera();
        context->release();
        ALOGV("native_release: context=%p camera=%p", context, camera.get());

        // clear callbacks
        if (camera != NULL) {
            camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
            camera->disconnect();
        }

        // remove context to prevent further Java access
        context->decStrong((void*)android_hardware_Camera_native_setup);
    }
}
else if (hadSurface) {
    mSurfaceHolder.ungetCallbacks();
    SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
    mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder);
    if (callbacks != null) {
        for (SurfaceHolder.Callback c : callbacks) {
            c.surfaceDestroyed(mSurfaceHolder);
        }
    }
    mSurfaceHolder.mSurfaceLock.lock();
    try {
        mSurfaceHolder.mSurface = new Surface();
    } finally {
        mSurfaceHolder.mSurfaceLock.unlock();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值