android进阶4step2:Android音视频处理——拍照功能实现及应用

Camera有哪几种使用场景?

  • 调用系统相机
  • 使用Camera API

使用Camera大致的流程

1、调用系统的相机实现拍照/存储/显示

AndroidManifest.xml中写上需要的权限 注意:android6.0之后需要动态申请权限

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/id_btn"
        android:layout_width="match_parent"
        android:text="拍照"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/id_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

 主要代码: MainActivity.java

public class MainActivity extends AppCompatActivity {

    public static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/pic/pic.jpg";
    private static final int REQ_CODE = 1001;
    private ImageView mImageView;
    private Button mBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView = findViewById(R.id.id_iv);
        mBtn = findViewById(R.id.id_btn);
        initEvent();
        initPhotoError();
    }

    private void initEvent() {
        mBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                requestPermission();
            }
        });
    }

    /**
     * 调用系统相机拍照
     *
     * @param
     */
    public void systemCamera() {
        Intent intent = new Intent();
        //添加动作和策略
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        //在内存卡中创建文件夹保存 拍完的照片
        File file = new File(PATH);
        //判断文件是否存在 存在删除
        if (file.exists()) {
            file.delete();
        }
        //将文件转成Uri
        Uri uri = Uri.fromFile(file);
        //将拍完照的结果 放到定义好的uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        //因为拍照的保存是异步的,所以需要利用这个start方法拿最终的结果
        startActivityForResult(intent, REQ_CODE);
    }

    /**
     * 解决 报错 exposed beyond app through ClipData.Item.getUri()
     */
    private void initPhotoError() {
        // android 7.0系统解决拍照的问题
        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());
        builder.detectFileUriExposure();
    }


    //当异步数据存储好后,重写这个方法拿返回完成的数据
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQ_CODE) {
            //拿到存储的好的照片
            File file = new File(PATH);
            if (file.exists()) {
                //设置给图片
                //Uri.fromFile(file)是file:///storage/emulated/0/pic/pic.jpg
                //第二次覆盖的时候,先让它设置为null
                mImageView.setImageURI(null);
                mImageView.setImageURI(Uri.fromFile(file));
            }
        }
    }

    /**
     * android 6.0 动态申请权限
     */
    private void requestPermission() {
        //如果读内存的权限没有被申请
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            //则申请
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQ_CODE);
        }
        //如果相机的权限没有被申请
        else if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            //则申请
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQ_CODE);
        } else {
            //才能调用拍照的方法
            systemCamera();
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQ_CODE) {
            //如果权限被授予了
            if (grantResults.length > 0) {

                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    //如果第一个权限还没有申请
                    Toast.makeText(this, "需要读取内存的权限", Toast.LENGTH_SHORT).show();
                } else if (grantResults[1] != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "需要开启相机的权限", Toast.LENGTH_SHORT).show();
                } else {//两个都申请了
                    //才能调用拍照的方法
                    systemCamera();
                }
            }
            return;
        }
    }
}

2、使用Camera API

Camera API的使用

  • 1. 有哪些API?
  • 2. 如何使用?
  • 3. 学会学习API的方法

效果:

  • 点击CAMERA API 创建camera视图 (surfaceView 装 Camera 来显示)
  • 点击 TAKE PHOTO 实现 camera的拍照功能  (Camera的方法、还有更多的参数设置)
  • 点击 “拍照” 是调用系统拍照的方法

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/id_btn_system"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="拍照" />

    <Button
        android:id="@+id/id_btn_api"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Camera API" />

    <Button
        android:id="@+id/id_btn_take_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Take photo" />

    <FrameLayout
        android:id="@+id/CameraLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

    </FrameLayout>

    <ImageView
        android:id="@+id/id_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

在之前的代码基础下,添加使用Camera API 的方式调用相机 和拍照

java 代码

  • 点击CAMERA API 创建camera视图 (surfaceView 装 Camera 来显示)
  • 点击 TAKE PHOTO 实现 camera的拍照功能  (Camera的方法、还有更多的参数设置)
  • 注意是这个 hardware包下的 Camera import android.hardware.Camera;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/pic/pic.jpg";
    private static final int REQ_CODE = 1001;
    private ImageView mImageView;
    //调用Camera 时API弹出的拍照视图
    private FrameLayout mCameraLayout;
    private volatile int mStatus = 0;
    private Button mBtn_System, mBtn_API, mBtn_take_photo;
    private Camera mCamera;
    private CameraView mCameraView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        mImageView = findViewById(R.id.id_iv);
        mCameraLayout = findViewById(R.id.CameraLayout);
        mBtn_System = findViewById(R.id.id_btn_system);
        mBtn_API = findViewById(R.id.id_btn_api);
        mBtn_take_photo = findViewById(R.id.id_btn_take_photo);
        mBtn_take_photo.setOnClickListener(this);
        mBtn_System.setOnClickListener(this);
        mBtn_API.setOnClickListener(this);
        initPhotoError();
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.id_btn_system:
                mStatus = 0;
                break;
            case R.id.id_btn_api:
                mStatus = 1;
                break;
            case R.id.id_btn_take_photo:
                mStatus = 2;
                break;
        }
        //权限申请
        requestPermission();
    }


    /**
     * 调用系统相机拍照
     *
     * @param
     */
    public void systemCamera() {
        /**
         * 因为Camera API 和 调用系统的方法都是调用系统的相机
         * 所已可能会造成一些冲突
         */
        if (mImageView != null) {
            //如果不为空,先释放 避免占用冲突
            mCameraView.release();
        }
        Intent intent = new Intent();
        //添加动作和策略
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        //在内存卡中创建文件夹保存 拍完的照片
        File file = new File(PATH);
        //判断文件是否存在 存在删除
        if (file.exists()) {
            file.delete();
        }
        //将文件转成Uri
        Uri uri = Uri.fromFile(file);
        //将拍完照的结果 放到定义好的uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        //因为拍照的保存是异步的,所以需要利用这个start方法拿最终的结果
        startActivityForResult(intent, REQ_CODE);
    }

    /**
     * 使用Camera API 时的方法
     */
    private void cameraAPI() {
        //1.创建一个camera视图
        //2.将camera视图添加到cameraLayout中
        //做一下camera的设置
        mCamera = getCamera();
        mCameraView = new CameraView(this, mCamera);
        //将CameraView添加到FragmentLayout中
        mCameraLayout.addView(mCameraView);
        //将拍完的照片旋转角度保存 因为不旋转不是水平的一个状态
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setRotation(90);
        mCamera.setParameters(parameters);
    }

    /**
     * Camera API 的拍照按钮
     */
    private void takePhoto() {
        //3.点击按钮,并保存到存储里面
        if (mCamera != null) {
            mCamera.takePicture(null, null, new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {
                    File file = new File(PATH);
                    try {
                        FileOutputStream fileOutputStream = new FileOutputStream(file);
                        //将拍照完之后的数据 这里是byte[] 类型的写入到之前的文件中
                        fileOutputStream.write(data);
                        fileOutputStream.close();
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    /**
     * 得到Camera
     *
     * @return
     */
    public Camera getCamera() {
        Camera camera = null;
        //打开相机
        try {
            camera = Camera.open();
        } catch (Exception e) {
            e.printStackTrace();
            //错误提示
        }
        return camera;
    }

    //新建内部类做camera的视图
    public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
        Camera mCamera;
        private final SurfaceHolder mHolder;

        public CameraView(Context context, Camera camera) {
            super(context);
            mCamera = camera;
            //surfaceView的监听器
            mHolder = getHolder();
            mHolder.addCallback(this);
        }

        //SurfaceView的创建
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                if (mCamera != null) {
                    //把Camera的显示设置为当前的SurfaceHolder
                    mCamera.setPreviewDisplay(holder);
                    mCamera.startPreview();
                    //设置相机显示的角度
                    mCamera.setDisplayOrientation(90);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //视图变更
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            if (mHolder.getSurface() == null) {
                return;
            }
            try {
                if (mCamera != null) {
                    mCamera.stopPreview();
                    mCamera.setPreviewDisplay(holder);
                    mCamera.startPreview();
                } else {
                    //提示用户
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //销毁
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            release();
        }

        /**
         * 释放Camera
         */
        public void release() {
            if (mCamera != null) {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.release();
                mCamera = null;

            }
        }
    }


    private void Method() {
        switch (mStatus) {
            case 0:
                systemCamera();
                break;
            case 1:
                cameraAPI();
                break;
            case 2:
                takePhoto();
                break;
        }
    }


    /**
     * 解决 报错 exposed beyond app through ClipData.Item.getUri()
     */
    private void initPhotoError() {
        // android 7.0系统解决拍照的问题
        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());
        builder.detectFileUriExposure();
    }


    //当异步数据存储好后,重写这个方法拿返回完成的数据
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQ_CODE) {
            //拿到存储的好的照片
            File file = new File(PATH);
            if (file.exists()) {
                //设置给图片
                //Uri.fromFile(file)是file:///storage/emulated/0/pic/pic.jpg
                //第二次覆盖的时候,先让它设置为null
                mImageView.setImageURI(null);
                mImageView.setImageURI(Uri.fromFile(file));
            }
        }
    }

    /**
     * android 6.0 动态申请权限
     */
    private void requestPermission() {
        //如果相机的权限没有被申请
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            //则申请
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQ_CODE);
        } else {
            //如果申请了执行相应的方法
            Method();
            Log.e("TAG", mStatus + "");
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQ_CODE) {
            //如果权限被授予了
            if (grantResults.length > 0) {

                if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    //如果第一个权限还没有申请
                    Toast.makeText(this, "需要开启相机的权限", Toast.LENGTH_SHORT).show();
                } else {//申请了
                    //根据状态调用相应的方法
                    Method();
                }
            }
            return;
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mCameraView != null) {
            mCameraView.release();
        }
    }

}

Camera API 5.0 以前的(目前使用)

Camera API2 5.0以后的 

 Extend拓展:

  • 1. 与Camera相类似的硬件Audio, Recorder, Video等
  • 2. 关联知识点:文件上传,权限判断等

猜你喜欢

转载自blog.csdn.net/qq_17846019/article/details/85039418