音视频开发任务(3)——使用cameraAPI采集视频数据

一、调用系统自带相机进行录像

调用系统相机进行拍照或者录像非常简单,主要有申请系统权限,创建一个Intent对象,使用startActivityForResult()启动相机,在onActivityResult()中获得录像文件保存的uri。

1.申请相机权限:

  • AndroidMainfest.xml: xml

  • 动态申请权限

    //需要申请的运行时权限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数据

  1. 同样的操作,先申请权限,不再赘述

  2. 使用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();}
    
  3. 使用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) {}
    
  4. 取回预览的视频数据

        @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();
                }
        }
    
  5. 其他:拍照调用mCamera.takePicture()方法,参考demo;此篇教程依旧不够完善,后续将实现一个自己的相机进行录制和拍摄视频

 

你可能感兴趣的:(音视频开发任务(3)——使用cameraAPI采集视频数据)