一、调用系统自带相机进行录像
调用系统相机进行拍照或者录像非常简单,主要有申请系统权限,创建一个Intent对象,使用startActivityForResult()
启动相机,在onActivityResult()
中获得录像文件保存的uri。
1.申请相机权限:
-
AndroidMainfest.xml:
xml <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
-
动态申请权限
//需要申请的运行时权限private String[] permissions = new String[]{ //Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
权限检查
private void checkPermissions() { //mPermissionList是没有权限的列表 if (SDK_INT >= VERSION_CODES.M) { for (int i = 0; i < permissions.length; i++) { if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) { mPermissionList.add(permissions[i]); } } if (!mPermissionList.isEmpty()) { String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]); ActivityCompat.requestPermissions(this, permissions, MY_PERMISSIONS_REQUEST); } }}
申请结果处理
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == MY_PERMISSIONS_REQUEST) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { Log.i(TAG, permissions[i] + " 权限被用户禁止!"); //checkPermissions();反复申请 break; } } }}
-
启动相机:
static final int REQUEST_VIDEO_CAPTURE = 1; Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); if (takeVideoIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE); }
-
onActivityResult()中取得文件的uri,并设置videoview播放录像
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) { videoUri = intent.getData(); Log.i(TAG, videoUri.toString()); videoView.setVideoURI(videoUri); videoView.start(); }
二、使用cameraAPI采集视频数据
使用CameraAPI可以直接操控手机的相机硬件,可以构建自己的相机APP,实现更多的效果,这里主要是打开相机,并通过SurfaceView和textureView预览,最后回调预览的NV21数据
-
同样的操作,先申请权限,不再赘述
-
使用surfaceview预览后置相机:
这里需要实现两个接口implements SurfaceHolder.Callback,Camera.PreviewCallback
//使用surfaceview预览后置相机 surfaceView.getHolder().addCallback(this); mCamera = Camera.open(0);//0 后置摄像头 1前置摄像头 mCamera.setDisplayOrientation(90);//将镜头画面旋转90度 //配置数据回调格式 Camera.Parameters parameters=mCamera.getParameters(); parameters.setPreviewFormat(ImageFormat.NV21); mCamera.setParameters(parameters); mCamera.setPreviewCallback(this);
重写相应方法
//----------------surfaceview预览-------------------------@Overridepublic void surfaceCreated(SurfaceHolder holder) { try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); }}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) { mCamera.release();}
-
使用textureView预览
设置参数等和Surfaceview类似,然后实现接口TextureView.SurfaceTextureListener
设置预览:textureView.setSurfaceTextureListener(this);
重写相应的方法://-----------------------------------TextureView预览--------------------@Overridepublic void onSurfaceTextureAvailable(final SurfaceTexture surface, int width, int height) { try { mCamera.setPreviewTexture(surface); mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); }}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { mCamera.release(); return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}
-
取回预览的视频数据
@Override public void onPreviewFrame(byte[] data, Camera camera) { /*data就是预览数据, *以下方法将NV21的数据转换为JPG格式存储, *测试发现,预览数据是定时拍摄画面 *预览数据依旧是横屏的,如果有必要,需要做旋转处理 */ // 刚刚拍照的文件名 String fileName = "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) .toString() + ".jpg"; File sdRoot = Environment.getExternalStorageDirectory(); String dir = "/Camera/"; File mkDir = new File(sdRoot, dir); if (!mkDir.exists()) mkDir.mkdirs(); File pictureFile = new File(sdRoot, dir + fileName); if (!pictureFile.exists()) { try { pictureFile.createNewFile(); Camera.Parameters parameters = camera.getParameters(); Camera.Size size = parameters.getPreviewSize(); YuvImage image = new YuvImage(data, parameters.getPreviewFormat(), size.width, size.height, null); FileOutputStream filecon = new FileOutputStream(pictureFile); image.compressToJpeg( new Rect(0, 0, image.getWidth(), image.getHeight()), 90, filecon); } catch (IOException e) { e.printStackTrace(); } }
-
其他:拍照调用
mCamera.takePicture()
方法,参考demo;此篇教程依旧不够完善,后续将实现一个自己的相机进行录制和拍摄视频