自定义照相机(一)

现在网上有很多博客对于Android自定义照相机这一块都有很透彻的讲解,不过为了留下自己对于Android自定义相机的理解,还是打算写几篇博客来记录它。本篇博客讲到的自定义照相机使用的是Android提供的旧版API即Camera,图像预览使用的是TextureView控件。

一、自定义相机要求

目前市面上的绝大部分手机应该都会支持拍照功能,但是为了适配所有情况并避免自己的应用安装到不支持拍照的手机上,那么需要在清单文件的manifest节点下添加如下代码:

<uses-feature android:name="android.hardware.Camera" android:required="true"/>

同时还需要如下权限:

//使用相机的权限
<uses-permission android:name="android.permission.CAMERA"/>
//往内存卡里面写的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
//读取内存卡的权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
//使用相机录制视频的权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

二、判断当前设备关于摄像头硬件的支持

2.1 是否支持前置拍照

   /**
     * 摄像机是否支持前置拍照
     *
     * @return
     */
    public static boolean isSupportFrontCamera() {
    //获取当前摄像头的数量
        final int cameraCount = Camera.getNumberOfCameras();
        Camera.CameraInfo info = new Camera.CameraInfo();
        for (int i = 0; i < cameraCount; i++) {
            Camera.getCameraInfo(i, info); //获取摄像头的信息
            if (info.facing == 1) {  //1 代表前置,0代表后置
                return true;
            }
        }
        return false;
    }

2.2 是否支持闪光

   /**
     * 是否支持闪光
     *
     * @param context
     * @return
     */
    public static boolean isSupportFlashCamera(Context context) {
        FeatureInfo[] features = context.getPackageManager().getSystemAvailableFeatures();
        for (FeatureInfo info : features) {
            if (PackageManager.FEATURE_CAMERA_FLASH.equals(info.name))
                return true;
        }
        return false;
    }

三、实现拍照

提到拍照那就避免不了图像的实时预览,本篇博客的图像预览采用的是TextureView。目前对TextureView的理解也就停留在会用上,所以这里就不做详细的介绍了。同时在Demo中自定义了一个相机的管理类CameraManager来维护Camera的使用。
3.1打开相机
在Activity生命周期的onResume()中来打开相机,打开相机的代码如下:

 @Override
    protected void onResume() {
        super.onResume();
        if (tvTexture.isAvailable()) {
            //路径不为空,优先播放视频
            if (recorderPath != null) {
                playerManager.playMedia(new Surface(tvTexture.getSurfaceTexture()), recorderPath);
            } else {
            //使用管理类来打开相机
                cameraManager.openCamera(this, tvTexture.getSurfaceTexture(),
                        tvTexture.getWidth(), tvTexture.getHeight());
            }
        } else {
        //给TextureView对象设置SurfaceTextureListener的监听
            tvTexture.setSurfaceTextureListener(this);
        }
    }

3.2 画面的缩放和聚焦
这里自定义了一个CameraView(继承至View)覆盖在TextureView上,通过重写CameraView的onTouch()方法捕获用户点击屏幕的位置来调用Camera相应的API来实现相机的聚焦和画面的缩放。其实也可以不写CameraView,直接继承TextureView同时重写它的onTouch()方法也可以达到同样的效果(翻看TextureView的源码可以发现它继承于View但并没有重写View的onTouch()方法),但是为了以后使用SurfaceView时容易拆分这里就重写了CameraView。

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        //保证拍照或者录制完视频后触摸CameraView不在进行聚焦或缩放
        if (!isEnabled()) {
            return super.onTouchEvent(event);
        }
        int action = MotionEventCompat.getActionMasked(event);
        if (event.getPointerCount() == 1 && action == MotionEvent.ACTION_UP) {
            float x = event.getX();
            float y = event.getY();
            //自定义方法,设置当前触摸点
            setFoucsPoint(x, y);
            if (listener != null) {
               //通过监听触摸点来进行聚焦
                listener.handleFocus(x, y);
            }
        } else if (event.getPointerCount() >= 2) {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_POINTER_DOWN:
                    //自定义方法,计算两指之间的距离
                    oldDist = getFingerSpacing(event);
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (event.getPointerCount() < 2)
                        return true;
                    float newDist = getFingerSpacing(event);
                    if (this.listener != null) {
                        //通过监听触摸点来进行缩放
                        this.listener.handleZoom(false, oldDist, newDist);
                        oldDist = newDist;
                    }

                    break;
            }
        }
        return true;
    }

3.3 拍照

   /**
     * 拍照
     */
    public void takePhoto(Camera.PictureCallback callback) {
        if (mCamera != null) {
            try {
            //这里的三个参数意思特别简单翻看API很容易就查找到了,这里就不做介绍
                mCamera.takePicture(null, null, callback);
            } catch (Exception e) {
                Toast.makeText(context, "拍摄失败", Toast.LENGTH_SHORT).show();
            }
        }
    }

四、实现录制视频

4.1 开始录制

 /**
     * 开始录制视频
     */
    public void startMediaRecord(String savePath) {
        if (mCamera == null || mProfile == null)
            return;
        //录制视频时必须调用,目的是解锁方便其他进程调用
        mCamera.unlock();
        if (mMediaRecorder == null) {
            mMediaRecorder = new MediaRecorder();
            //设置视频回放的输出方向,其参数必须是0,90,180,270中的一个
            mMediaRecorder.setOrientationHint(90);
        }
        if (isCameraFrontFacing()) {
            mMediaRecorder.setOrientationHint(270);
        }
        mMediaRecorder.reset();
        mMediaRecorder.setCamera(mCamera);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        mMediaRecorder.setProfile(mProfile);
        mMediaRecorder.setOutputFile(savePath);
        try {
            mMediaRecorder.prepare();
            mMediaRecorder.start();
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

4.2 结束录制

   /**
     * 停止录制
     */
    public void stopMediaRecord() {
        this.cameraType = 0;
        //停止录制
        stopRecorder();
        //释放资源
        releaseMediaRecorder();
    }

五、效果图如下所示

未拍照或录像时相机效果图如下所示:


这里写图片描述

拍照或录像完成时效果图如下所示:

这里写图片描述


本Demo大部分是借鉴了极光IM的开源代码,在此特别感谢极光。
Demo源码地址如下所示:
https://github.com/Duckdan/DefineCameraDemo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值