前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android利用SurfaceView显示Camera图像爬坑记(四)

Android利用SurfaceView显示Camera图像爬坑记(四)

作者头像
Vaccae
发布2019-07-25 11:47:48
2.6K0
发布2019-07-25 11:47:48
举报
文章被收录于专栏:微卡智享

前言

通过前面几篇,利用SurfaceView显示Camera的图像已经没什么问题了,接下来我们就要打磨一下细节,主要就是手机旋转的问题,考虑到我们会用横屏和竖屏的不同的情况。

横竖屏问题

用我们前面的DEMO后,因为默认的打开后就是竖屏,所以进入后图像没有问题,如下

但是我们切换到横屏后,图像就显示不对了,如下

原来的代码中我们也只是解决了默认竖屏的问题

在StartCamera中,设置了直接旋转90度(不过我们改为SurfaceTexture这样显示后,这个没什么用了)

然后生成图像的方法nv21ToBitmap中加入了旋转90度

实现思路

  1. 获取到手机当前的旋转角度
  2. 根据当前旋转的角度修改生成图像的角度
  3. 生成的图像后加入角度旋转

代码实现

首先把setDisplayOrientation这个屏蔽掉了,因为已经没用了

获取到手机当前的旋转角度

想要获取手机的当前旋转角度,就要用到WindowManager,所以我们要加入WindowManager的定义,还要加入一个默认的角度值。然后在构造函数中获取到当前windowmanager。

根据当前旋转的角度修改生成图像的角度

记得当时有三个重写的参数surfaceCreated,surfaceChanged和surfaceDestoryed,其中我们在surfaceCreated中加入了打开Camera,在surfaceDestoryed中加入了关闭Camera,而surfaceChanged中什么也没写,这次这个方法就被我们用到了。

代码语言:javascript
复制
    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        int angel = windowManager.getDefaultDisplay().getRotation();
        switch (angel) {
            case Surface.ROTATION_0:
                rotatedegree=90;
                break;
            case Surface.ROTATION_90:
                rotatedegree=0;
                break;
            case Surface.ROTATION_180:
                rotatedegree=270;
                break;
            case Surface.ROTATION_270:
                rotatedegree=180;
                break;
            default:
                rotatedegree=0;
                break;
        }
    }

上面就是通过判断手机旋转角度,改变我们定义的retatedegree的值,这个是我根据旋转的情况自己算出来的,生成图像旋转的角度。

生成的图像后加入角度旋转

最后在我们nv21ToBitmap中的旋转角度改为我们已经定义的retatedegree

视频效果

基本到这,我们这个SurfaceView调Camera的类就完成了,这里我把整个类的代码放到这里,后面可能会在这上面加入通过OpenCV NDK的图像处理,这里做一个备份吧。

代码语言:javascript
复制
package dem.vac.surfaceviewdemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * 作者:Vaccae
 * 邮箱:3657447@qq.com
 * 创建时间:2019-06-12 15:42
 * 功能模块说明:
 */
public class VaccaeSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    //Camera相关
    //设置摄像头ID,我们默认为后置
    private int mCameraIndex=Camera.CameraInfo.CAMERA_FACING_BACK;
    //定义摄像机
    private Camera camera;
    //定义Camera的回调方法
    private Camera.PreviewCallback previewCallback=new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] bytes, Camera camera) {
            synchronized (this) {
                int width=camera.getParameters().getPreviewSize().width;
                int height=camera.getParameters().getPreviewSize().height;
                Log.d("frame", "width:"+width+" height:"+height);
                Canvas canvas=holder.lockCanvas();
                if (canvas != null) {
                    Log.i("frame", "canvas width:" + canvas.getWidth() + " height:" + canvas.getHeight());
                    canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
                    Bitmap cacheBitmap=nv21ToBitmap(bytes, width, height);

                    RectF rectF=new RectF(0, 0, canvas.getWidth(), canvas.getHeight());
                    canvas.drawBitmap(cacheBitmap, null, rectF, null);

                    holder.unlockCanvasAndPost(canvas);
                }
            }
        }
    };

    //定义SurfaceHolder
    private SurfaceHolder holder;
    //定义SurfaceTexture;
    private SurfaceTexture surfaceTexture;

    //WindowManager 用于获取摄像机方向
    private WindowManager windowManager;
    //当前相机角度
    private int rotatedegree=0;


    //构造函数
    public VaccaeSurfaceView(Context context) {
        super(context);

        //获取WindowManager
        windowManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        //实例化Surfacetexture
        surfaceTexture=new SurfaceTexture(2);
        //获取Holder
        holder=getHolder();
        //加入SurfaceHolder.Callback在类中implements
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        //保持屏幕常亮
        holder.setKeepScreenOn(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //开启摄像机
        startCamera(mCameraIndex);
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        int angel = windowManager.getDefaultDisplay().getRotation();
        switch (angel) {
            case Surface.ROTATION_0:
                rotatedegree=90;
                break;
            case Surface.ROTATION_90:
                rotatedegree=0;
                break;
            case Surface.ROTATION_180:
                rotatedegree=270;
                break;
            case Surface.ROTATION_270:
                rotatedegree=180;
                break;
            default:
                rotatedegree=0;
                break;
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        //关闭摄像机
        stopCamera();
    }

    //region 开启关闭Camera
    //开启摄像机
    private void startCamera(int mCameraIndex) {
        // 初始化并打开摄像头
        if (camera == null) {
            try {
                camera=Camera.open(mCameraIndex);
            } catch (Exception e) {
                return;
            }
            //获取Camera参数
            Camera.Parameters params=camera.getParameters();
            if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                // 自动对焦
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            }
            params.setPreviewFormat(ImageFormat.NV21); // 设置预览图片格式
            params.setPictureFormat(ImageFormat.JPEG); // 设置拍照图片格式

            camera.setParameters(params);

            try {
                camera.setPreviewCallback(previewCallback);
                camera.setPreviewTexture(surfaceTexture);
//                camera.setPreviewDisplay(holder);
                //旋转90度
//                camera.setDisplayOrientation(90);
                camera.startPreview();
            } catch (Exception ex) {
                ex.printStackTrace();
                camera.release();
                camera=null;
            }
        }
    }

    //关闭摄像机
    private void stopCamera() {
        if (camera != null) {
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera=null;
        }

    }
    //endregion

    private Bitmap nv21ToBitmap(byte[] nv21, int width, int height) {
        Bitmap bitmap=null;
        try {
            YuvImage image=new YuvImage(nv21, ImageFormat.NV21, width, height, null);
            ByteArrayOutputStream stream=new ByteArrayOutputStream();
            image.compressToJpeg(new Rect(0, 0, width, height), 80, stream);
            //将rawImage转换成bitmap
            BitmapFactory.Options options=new BitmapFactory.Options();
            options.inPreferredConfig=Bitmap.Config.ARGB_8888;
            bitmap=BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size(), options);

            //加入图像旋转
            Matrix m=new Matrix();
            m.postRotate(rotatedegree);
            bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
                    m, true);

            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }



}

-END-

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档