startPreview,release
一、摘要
本篇文章包含如下2个部分:
- startPreview
- release
二、伪代码
2.1 Camera1源码
Camera.java
源码里startPreview
描述如下:
/**
* 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.
*
* @throws RuntimeException if starting preview fails; usually this would be
* because of a hardware or other low-level error, or because release()
* has been called on this Camera instance. The QCIF (176x144) exception
* mentioned in {@link Parameters#setPreviewSize setPreviewSize} and
* {@link Parameters#setPictureSize setPictureSize} can also cause this
* exception be thrown.
*/
public native final void startPreview();
分析
- Starts capturing and drawing preview frames to the screen
- 需要提供SurfaceTexture或者SurfaceHolder才可preview
- setPreviewCallback可监听preview的状态
- 会抛异常。
2.2 官方Demo
官方Demo里startPreview
的相关逻辑如下:
Camera1(Callback callback, PreviewImpl preview) {
super(callback, preview);
preview.setCallback(new PreviewImpl.Callback() {
@Override
public void onSurfaceChanged() {
if (mCamera != null) {
setUpPreview();
adjustCameraParameters();
}
}
});
}
@Override
boolean start() {
chooseCamera();
openCamera();
if (mPreview.isReady()) {
setUpPreview();
}
mShowingPreview = true;
mCamera.startPreview();
return true;
}
// Suppresses Camera#setPreviewTexture
@SuppressLint("NewApi")
void setUpPreview() {
try {
if (mPreview.getOutputClass() == SurfaceHolder.class) {
mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
} else {
mCamera.setPreviewTexture((SurfaceTexture) mPreview.getSurfaceTexture());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
分析
- 构造函数里监听
surfaceChange
来设置SurfaceTexture/SurfaceHolder
start 函数
里直接调用mCamera.startPreview();
2.3 更新代码
public void initCamera(int cameraId, float aspectRatio, SurfaceTexture surfaceTexture){
this.mSurfaceTexture = surfaceTexture;
...
}
public void startPreview(){
//这里兜底再做一次权限检查防止无权限出错
if(CheckHasPermission(CAMERA_PERMISSION)){
Toast("无相机权限")
return;
}
if(isPreviewing){
Toast("重复初始化")
return;
}
if(mCamera == null){
//这里因为openCamera底层是异步的在极端情况下,mCamera会由于时许问题在此位null
return;
}
try{
//mCamera.startPreview() 经常会抛异常错误信息位startPreview fail. 该异常一部分通常与自动对焦有关系,所以这里try-catch cancelAutoFocus.
//cancelAutoFocus
mCamera.cancelAutoFocus();
}catch(Exception e){
}
synchronize(Lock){
if(acquireLock(timeot = 2000)){
Log.w("timeout");
}
mCamera.setPreviewDisplay(mSurfaceTexture);
//previewCallBack监听回调,通知UI层。
mCamera.setPreviewCallBack(new PreviewCallback(){
void onPreviewFrame(byte[] data, Camera camera){
releaseLock();
if(isPreviewing) return;
isPreviewing = true;
CameraManager.of().onCameraPreviewed();=
}
})
try{
mCamera.startPreview();
}catch(Exception e){
Log.e(TAG, "exp info = "+e.getInfos());
//重试逻辑
retryStartPreview();
}
}
}
2.4 releaseCamera
源码如下:
/**
* Disconnects and releases the Camera object resources.
*
* <p>You must call this as soon as you're done with the Camera object.</p>
*/
public final void release() {
native_release();
mFaceDetectionRunning = false;
releaseAppOps();
}
官方Demo代码如下:
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
mCallback.onCameraClosed();
}
}
更新代码如下:
public void releaseCamera(){
if(mCamera == null) return;
synchronized(Lock){
try{
if(acquireLock(timeout = 2000)){
Log.e(TAG, "timeout")
}
mCamera.stopPreview();
mCamera.release();
mCamera = null;
releaseLock();
}catch(Exception e){
...
}
}
}
至此Camera1Impl初始化销毁流程阐述完毕。下篇将会对所有伪代码进行汇总总结:
Camera1初始化销毁流程(七) —— 伪代码