Android SurfaceView 实现实时显示摄像头视频
16lz
2021-01-23
1.注册 SurfaceView实例:
private SurfaceView mainSfCamera; mainSfCamera = (SurfaceView) findViewById(R.id.main_sf_camera);
2.检测是否存在摄像头:
private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) { Toast.makeText(this, "搜索到摄像头硬件", Toast.LENGTH_SHORT).show(); return true; } else { Toast.makeText(this, "不具备摄像头硬件", Toast.LENGTH_SHORT).show(); return false; } }
3.建立CameraSurfaceHolder工具类
/** * 相机界面SurfaceView的Holder类 */public class CameraSurfaceHolder { Context context; SurfaceHolder surfaceHolder; SurfaceView surfaceView; SurfaceViewCallback callback = new SurfaceViewCallback(); /** * 设置相机界面SurfaceView的Holder * @param context 从相机所在的Activity传入的context * @param surfaceView Holder所绑定的响应的SurfaceView * */ public void setCameraSurfaceHolder(Context context, SurfaceView surfaceView) { this.context = context; this.surfaceView = surfaceView; surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(callback); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); callback.setContext(context); }}
4.在主类中绑定:
CameraSurfaceHolder mCameraSurfaceHolder = new CameraSurfaceHolder();mCameraSurfaceHolder.setCameraSurfaceHolder(MainActivity.this,mainSfCamera);
5.SurfaceViewCallback 工具类:
/** * 相机界面SurfaceView的回调类 */public final class SurfaceViewCallback implements SurfaceHolder.Callback, Camera.PreviewCallback { Context context; static final String TAG = "SYRFACECamera"; FrontCamera mFrontCamera = new FrontCamera(); boolean previewing = mFrontCamera.getPreviewing(); Camera mCamera; FaceTask mFaceTask; public void setContext(Context context) { this.context = context; } public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { if (previewing) { mCamera.stopPreview(); Log.i(TAG, "停止预览"); } try { mCamera.setPreviewDisplay(arg0); mCamera.startPreview(); mCamera.setPreviewCallback(this); Log.i(TAG, "开始预览"); //调用旋转屏幕时自适应 //setCameraDisplayOrientation(MainActivity.this, mCurrentCamIndex, mCamera); } catch (Exception e) { } } public void surfaceCreated(SurfaceHolder holder) { //初始化前置摄像头 mFrontCamera.setCamera(mCamera); mCamera = mFrontCamera.initCamera(); mCamera.setPreviewCallback(this); //适配竖排固定角度 FrontCamera.setCameraDisplayOrientation((Activity) context, mFrontCamera.getCurrentCamIndex(), mCamera); Log.i(TAG, "surfaceCreated"); } public void surfaceDestroyed(SurfaceHolder holder) { mFrontCamera.StopCamera(mCamera); Log.i(TAG, "surfaceDestroyed"); } /** * 相机实时数据的回调 * * @param data 相机获取的数据,格式是YUV * @param camera 相应相机的对象 */ @Override public void onPreviewFrame(byte[] data, Camera camera) { if (mFaceTask != null) { switch (mFaceTask.getStatus()) { case RUNNING: return; case PENDING: mFaceTask.cancel(false); break; } } mFaceTask = new FaceTask(data, camera); mFaceTask.execute((Void) null); //Log.i(TAG, "onPreviewFrame: 启动了Task"); }}
6.FrontCamera工具类:
/** * 相机类,相机的调用 */public class FrontCamera { static final String TAG = "Camera"; Camera mCamera; int mCurrentCamIndex = 0; boolean previewing; public void setCamera(Camera camera) { this.mCamera = camera; } public int getCurrentCamIndex() { return this.mCurrentCamIndex; } public boolean getPreviewing() { return this.previewing; } Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() { @Override public void onShutter() { } }; Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { } }; Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { Bitmap bitmap = null; bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); Log.i(TAG, "已经获取了bitmap:" + bitmap.toString()); previewing = false; //需要保存可执行下面/* new Thread(new Runnable() { @Override public void run() { String filePath = ImageUtil.getSaveImgePath(); File file = new File(filePath); FileOutputStream fos = null; try { fos = new FileOutputStream(file, true); fos.write(data); ImageUtil.saveImage(file, data, filePath); fos.close(); } catch (Exception e) { e.printStackTrace(); } } }).start();*/ try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } mCamera.startPreview();//重新开启预览 ,不然不能继续拍照 previewing = true; } }; //初始化相机 public Camera initCamera() { int cameraCount = 0; Camera cam = null; Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); cameraCount = Camera.getNumberOfCameras(); Log.e(TAG, "cameraCount: " + cameraCount); previewing = true; for (int camIdx = 0; camIdx < cameraCount; camIdx++) { Camera.getCameraInfo(camIdx, cameraInfo); //在这里打开的是前置摄像头,可修改打开后置OR前置 if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { try { cam = Camera.open(camIdx); mCurrentCamIndex = camIdx; } catch (RuntimeException e) { Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage()); } } } return cam; } /** * 停止相机 * @param mCamera 需要停止的相机对象 * */ public void StopCamera(Camera mCamera) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mCamera = null; previewing = false; } /** * 旋转屏幕后自动适配(若只用到竖的,也可不要) * 已经在manifests中让此Activity只能竖屏了 * @param activity 相机显示在的Activity * @param cameraId 相机的ID * @param camera 相机对象 */ public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror } else { // back-facing result = (info.orientation - degrees + 360) % 360; } camera.setDisplayOrientation(result); }}
7.FaceTask工具类:
/** * 单独的任务类。继承AsyncTask,来处理从相机实时获取的耗时操作 */public class FaceTask extends AsyncTask{ private byte[] mData; Camera mCamera; private static final String TAG = "CameraTag"; //构造函数 FaceTask(byte[] data , Camera camera) { this.mData = data; this.mCamera = camera; } @Override protected Object doInBackground(Object[] params) { Camera.Parameters parameters = mCamera.getParameters(); int imageFormat = parameters.getPreviewFormat(); int w = parameters.getPreviewSize().width; int h = parameters.getPreviewSize().height; Rect rect = new Rect(0, 0, w, h); YuvImage yuvImg = new YuvImage(mData, imageFormat, w, h, null); try { ByteArrayOutputStream outputstream = new ByteArrayOutputStream(); yuvImg.compressToJpeg(rect, 100, outputstream); Bitmap rawbitmap = BitmapFactory.decodeByteArray(outputstream.toByteArray(), 0, outputstream.size()); Log.i(TAG, "onPreviewFrame: rawbitmap:" + rawbitmap.toString()); //若要存储可以用下列代码,格式为jpg /* BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/fp.jpg")); img.compressToJpeg(rect, 100, bos); bos.flush(); bos.close(); mCamera.startPreview(); */ } catch (Exception e) { Log.e(TAG, "onPreviewFrame: 获取相机实时数据失败" + e.getLocalizedMessage()); } return null; }}
8.别忘了权限申请或targetSdkVersion设置为23以下
源码下载地址:https://download.csdn.net/download/qq_30297763/11181177
GitHub地址:https://github.com/xingaijian/surfaceviewcameras
更多相关文章
- android dex工具打包Could not reserve enough space for object
- android实现从相册和相机中取照片并剪辑
- Android菜鸟日记15-传感器与摄像头
- Android 手机相机自动对焦
- Android 学习之CalendarManager日历管理工具类
- Android调试工具 —— TraceView [整理]
- 如何使用ndk中addr2line工具查询so库中错误信息行数
- android 为摄像头增加闪光灯(s5pv210)
- android工程字符串多语言翻译遗漏查找工具