RK Android7.1 Camera2 预览、内置客户SDK预览
一.预览
1.SurfaceView
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <SurfaceView android:id="@+id/sfv_preview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout>
AndroidManifest
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gatsby.ypcamerdemo"> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.YpCamerDemo"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Mainactivity.java
package com.gatsby.ypcamerdemo; import android.hardware.Camera; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; public class MainActivity extends AppCompatActivity { private SurfaceView sfv_preview; private Camera camera = null; private SurfaceHolder.Callback cpHolderCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { startPreview(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { stopPreview(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindViews(); } private void bindViews() { sfv_preview = (SurfaceView) findViewById(R.id.sfv_preview); sfv_preview.getHolder().addCallback(cpHolderCallback); } //开始预览 private void startPreview() { camera = Camera.open(); try { camera.setPreviewDisplay(sfv_preview.getHolder()); camera.setDisplayOrientation(0); camera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } //停止预览 private void stopPreview() { camera.stopPreview(); camera.release(); camera = null; } }
2.TextureView
- CameraManager: 管理手机上的所有摄像头设备,它的作用主要是获取摄像头列表和打开指定的摄像头
- CameraDevice: 具体的摄像头设备,它有一系列参数(预览尺寸、拍照尺寸等),可以通过CameraManager的getCameraCharacteristics()方法获取。它的作用主要是创建CameraCaptureSession和CaptureRequest
- CameraCaptureSession: 相机捕获会话,用于处理拍照和预览的工作(很重要)
- CaptureRequest: 捕获请求,定义输出缓冲区以及显示界面(TextureView或SurfaceView)等
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextureView android:id="@+id/textureview" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
Mainactivity.java
package com.gatsby.textureviewtest; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.util.Log; import android.view.Surface; import android.view.TextureView; import androidx.appcompat.app.AppCompatActivity; import java.util.Arrays; public class MainActivity extends AppCompatActivity { private TextureView textureView; private String TAG="Gatsby"; private HandlerThread mThreadHandler; private Handler mHandler; private CaptureRequest.Builder mPreviewBuilder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mThreadHandler = new HandlerThread("CAMERA2"); mThreadHandler.start(); mHandler = new Handler(mThreadHandler.getLooper()); textureView= (TextureView) findViewById(R.id.textureview); textureView.setSurfaceTextureListener(textureListener); } private TextureView.SurfaceTextureListener textureListener=new TextureView.SurfaceTextureListener() { @SuppressLint("MissingPermission") @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) { Log.e(TAG,"可用"); //CameraManaer 摄像头管理器,用于检测摄像头,打开系统摄像头 CameraManager cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE); try { String[] CameraIdList=cameraManager.getCameraIdList();//获取可用相机列表 Log.e(TAG,"可用相机的个数是:"+CameraIdList.length); //获取某个相机(摄像头特性) CameraCharacteristics cameraCharacteristics=cameraManager.getCameraCharacteristics(CameraIdList[0]); cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);//检查支持 cameraManager.openCamera(CameraIdList[0],mCameraDeviceStateCallback, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { Log.e(TAG,"change"); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { Log.e(TAG,"destroy"); return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { Log.e(TAG,"update"); } }; //CameraDeviceandroid.hardware.Camera也就是Camera1的Camera private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { try { startPreview(camera); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(CameraDevice camera) { } @Override public void onError(CameraDevice camera, int error) { } }; /** * @param camera * @throws CameraAccessException * 开始预览 */ private void startPreview(CameraDevice camera) throws CameraAccessException { SurfaceTexture texture = textureView.getSurfaceTexture(); texture.setDefaultBufferSize(textureView.getWidth(), textureView.getHeight()); Surface surface = new Surface(texture); try { //CameraRequest表示一次捕获请求,用来对z照片的各种参数设置,比如对焦模式、曝光模式等。CameraRequest.Builder用来生成CameraRequest对象 mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); } catch (CameraAccessException e) { e.printStackTrace(); } mPreviewBuilder.addTarget(surface); camera.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, mHandler); } //CameraCaptureSession 这个对象控制摄像头的预览或者拍照 //setRepeatingRequest()开启预览,capture()拍照 //StateCallback监听CameraCaptureSession的创建 private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { Log.e(TAG,"相机创建成功!"); try { session.capture(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);//拍照 session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);//返回结果 } catch (CameraAccessException e) { e.printStackTrace(); Log.e(TAG,"这里异常"); } } @Override public void onConfigureFailed(CameraCaptureSession session) { Log.e(TAG,"相机创建失败!"); } }; //CameraCaptureSession.CaptureCallback监听拍照过程 private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { Log.e(TAG,"这里接受到数据"+result.toString()); } @Override public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult){ }}; }
二.Android camera2预览界面流程 https://blog.csdn.net/fireness/article/details/50594706
2.1.找到布局
activity_main.xml
<com.android.camera.ui.MainActivityLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_root_view" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@null"> <include layout="@layout/camera" /> <include layout="@layout/camera_filmstrip" /> <com.android.camera.ui.ModeTransitionView android:id="@+id/mode_transition_view" android:visibility="gone" android:layout_width="match_parent" android:layout_height="match_parent" /> </com.android.camera.ui.MainActivityLayout>
预览布局 camera.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/camera_app_root" android:background="@android:color/black" android:layout_width="match_parent" android:layout_height="match_parent" > <TextureView android:id="@+id/preview_content" android:layout_width="match_parent" android:layout_height="match_parent" />
2.1.CameraActivity.java onCreateTasks() 准备预览mCameraAppUI.prepareModuleUI();
packages\apps\Camera2\src\com\android\camera\app\CameraAppUI.java
public void prepareModuleUI() { mController.getSettingsManager().addListener(this); mModuleUI = (FrameLayout) mCameraRootView.findViewById(R.id.module_layout); mTextureView = (TextureView) mCameraRootView.findViewById(R.id.preview_content); mTextureViewHelper = new TextureViewHelper(mTextureView, mCaptureLayoutHelper, mController.getCameraProvider(), mController); mTextureViewHelper.setSurfaceTextureListener(this); mTextureViewHelper.setOnLayoutChangeListener(mPreviewLayoutChangeListener);
2.3.TextureViewHelper 初始化
packages\apps\Camera2\src\com\android\camera\TextureViewHelper.java
public TextureViewHelper(TextureView preview, CaptureLayoutHelper helper, CameraProvider cameraProvider, AppController appController) { mPreview = preview; mCameraProvider = cameraProvider; mPreview.addOnLayoutChangeListener(this); mPreview.setSurfaceTextureListener(this); mCaptureLayoutHelper = helper; mAppController = appController; mCameraModeId = appController.getAndroidContext().getResources() .getInteger(R.integer.camera_mode_photo); mCaptureIntentModeId = appController.getAndroidContext().getResources() .getInteger(R.integer.camera_mode_capture_intent); }
还要去实现 implements TextureView.SurfaceTextureListener
@Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { // Workaround for b/11168275, see b/10981460 for more details if (mWidth != 0 && mHeight != 0) { // Re-apply transform matrix for new surface texture updateTransform(); } if (mSurfaceTextureListener != null) { mSurfaceTextureListener.onSurfaceTextureAvailable(surface, width, height); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { if (mSurfaceTextureListener != null) { mSurfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height); } }
packages\apps\Camera2\src\com\android\camera\PhotoUI.java
@Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { mController.onPreviewUIReady(); }
2.4.packages\apps\Camera2\src\com\android\camera\PhotoModule.java
@Override public void onPreviewUIReady() { Log.i(TAG, "onPreviewUIReady"); startPreview(); } private void startPreview() { if (mCameraDevice == null) { Log.i(TAG, "attempted to start preview before camera device"); // do nothing return; } ………………………… Log.i(TAG, "startPreview"); // If we're using API2 in portability layers, don't use startPreviewWithCallback() // b/17576554 CameraAgent.CameraStartPreviewCallback startPreviewCallback = new CameraAgent.CameraStartPreviewCallback() { @Override public void onPreviewStarted() { mFocusManager.onPreviewStarted(); PhotoModule.this.onPreviewStarted(); SessionStatsCollector.instance().previewActive(true); if (mSnapshotOnIdle || (mAppController.getSettingsManager().getBoolean (SettingsManager.SCOPE_GLOBAL, Keys.KEY_SMILE_SHUTTER_ON) && DebugPropertyHelper.isSmileShutterAuto())) { mHandler.postDelayed(mDoSmileShutterRunnable, 2000); } } };
三.内置SDK 预览
3.1.客户demo
private var mSurfaceTexture: SurfaceTexture? = null private var mSurface: Surface? = null private val mSurfaceTextureListener: SurfaceTextureListener = object : SurfaceTextureListener { override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) { mSurfaceTexture = surface } override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) { mSurfaceTexture = surface } override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean { mSurfaceTexture = surface return false } override fun onSurfaceTextureUpdated(surface: SurfaceTexture) { mSurfaceTexture = surface } } private fun initView() { if (mSurface == null && mSurfaceTexture != null) { mSurface = Surface(mSurfaceTexture) } mYpDevicesManager = YpDevicesManager.getInstance() mYpDevicesManager?.setContext(this) mYpDevicesManager?.setCodereaderCameraView(mSurface)
3.2.客户是特殊的USB3.0摄像头 走的不是 Camera open(int cameraId) 方法 而Camera2 预览走的流程是标准的 open方法
原计划是在Camera2 预览控件TextureView做动作 现在不走open 表示要大改预览框架
08-17 16:17:35.796 E/CameraService( 244): No camera be found ! check again... 08-17 16:17:35.796 I/CameraService( 244): CameraService process starting 08-17 16:17:35.797 I/CAM2PORT_AndCamAgntImp( 1442): Opening camera 0 with camera1 API 08-17 16:17:35.797 D/CameraHal( 244): Calling process is: com.android.camera2 08-17 16:17:35.798 I/CameraService( 244): CameraService::connect call (PID -1 "com.android.camera2", camera ID 0) for HAL version default and Camera API version 1 08-17 16:17:35.798 E/CameraService( 244): CameraService::connect X (PID 1442) rejected (invalid camera ID 0) 08-17 16:17:35.798 W/CameraBase( 1442): An error occurred while connecting to camera 0: Service not available 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): RuntimeException during CameraAction[OPEN_CAMERA] at CameraState[1] 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): java.lang.RuntimeException: Fail to connect to camera service 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): at android.hardware.Camera.<init>(Camera.java:496) 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): at android.hardware.Camera.open(Camera.java:345) 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): at com.android.ex.camera2.portability.AndroidCameraAgentImpl$CameraHandler.handleMessage(AndroidCameraAgentImpl.java:384) 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): at android.os.Handler.dispatchMessage(Handler.java:102) 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): at android.os.Looper.loop(Looper.java:154) 08-17 16:17:35.799 E/CAM2PORT_AndCamAgntImp( 1442): at android.os.HandlerThread.run(HandlerThread.java:61) 08-17 16:17:35.801 D/CameraHal( 244): createInstance(1041): open xml file(/etc/cam_board.xml) success 08-17 16:17:35.801 E/CameraHal( 244): cam_board.xml version(v0x0.0x0.0x0) != xml parser version(v0x0.0xf.0x0)
不使用反射 修改标准Surface 将客户SDK api 封装进去
diff --git a/frameworks/base/core/java/android/view/Surface.java b/frameworks/base/core/java/android/view/Surface.java old mode 100644 new mode 100755 index 22e68a3..78c78d0 --- a/frameworks/base/core/java/android/view/Surface.java +++ b/frameworks/base/core/java/android/view/Surface.java @@ -31,6 +31,11 @@ import java.lang.annotation.RetentionPolicy; import dalvik.system.CloseGuard; +import android.os.SystemProperties; +import java.lang.reflect.Method; +import com.yp.ypcodereader.manager.YpDevicesManager; +import android.view.TextureView; + /** * Handle onto a raw buffer that is being managed by the screen compositor. * @@ -158,8 +163,10 @@ public class Surface implements Parcelable { public Surface() { } + private Surface xhSurface; + /** - * Create Surface from a {@link SurfaceTexture}. + * Create Surface from a {@link SurfaceTex ture}. * * Images drawn to the Surface will be made available to the {@link * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link @@ -178,8 +185,19 @@ public class Surface implements Parcelable { mName = surfaceTexture.toString(); setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture)); } + if(TextureView.xhSurface_flag) { + GetXSurface(surfaceTexture); + } } + public void GetXSurface(SurfaceTexture surfaceTexture) { + TextureView.xhSurface_flag = false; + xhSurface = new Surface(surfaceTexture); + TextureView.ypDevicesManager.setCodereaderCameraView(xhSurface); + TextureView.ypDevicesManager.openCodereaderCamera(null); + } + + /* called from android_view_Surface_createFromIGraphicBufferProducer() */ private Surface(long nativeObject) { synchronized (mLock) { @@ -225,6 +243,7 @@ public class Surface implements Parcelable { */ public void destroy() { release(); + TextureView.ypDevicesManager.closeCodereaderCamera(); } /** diff --git a/frameworks/base/core/java/android/view/TextureView.java b/frameworks/base/core/java/android/view/TextureView.java old mode 100644 new mode 100755 index 645ab5c..0582f5d --- a/frameworks/base/core/java/android/view/TextureView.java +++ b/frameworks/base/core/java/android/view/TextureView.java @@ -27,6 +27,14 @@ import android.graphics.SurfaceTexture; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; +import android.text.TextUtils; +import android.os.SystemProperties; +import android.app.ActivityManager; +import android.content.ComponentName; + +import com.yp.ypcodereader.manager.YpDevicesManager; + +import java.util.List; /** * <p>A TextureView can be used to display a content stream. Such a content @@ -123,6 +131,12 @@ public class TextureView extends View { private Canvas mCanvas; private int mSaveCount; + public static YpDevicesManager ypDevicesManager; + private String outPackageInfo; + private String CLASS_NAME = "com.gatsby.ypcamerademo2.MainActivity"; + public static boolean xhSurface_flag; + + private final Object[] mNativeWindowLock = new Object[0]; // Set by native code, do not write! private long mNativeWindow; @@ -144,8 +158,27 @@ public class TextureView extends View { */ public TextureView(Context context, AttributeSet attrs) { super(context, attrs); + boolean packageInfo = isForeground(context,CLASS_NAME); + if(packageInfo){ + xhSurface_flag = true; + ypDevicesManager = new YpDevicesManager().getInstance(); + ypDevicesManager.setContext(context); + } + } + + public static boolean isForeground(Context context, String className) { + if (context == null || TextUtils.isEmpty(className)) + return false; + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(1); + if (list != null && list.size() > 0) { + ComponentName cpn = list.get(0).topActivity; + if (className.equals(cpn.getClassName())) + return true; + } + return false; } - + /** * Creates a new TextureView. *