前言
通过前面几篇,利用SurfaceView显示Camera的图像已经没什么问题了,接下来我们就要打磨一下细节,主要就是手机旋转的问题,考虑到我们会用横屏和竖屏的不同的情况。
横竖屏问题
用我们前面的DEMO后,因为默认的打开后就是竖屏,所以进入后图像没有问题,如下
但是我们切换到横屏后,图像就显示不对了,如下
原来的代码中我们也只是解决了默认竖屏的问题
在StartCamera中,设置了直接旋转90度(不过我们改为SurfaceTexture这样显示后,这个没什么用了)
然后生成图像的方法nv21ToBitmap中加入了旋转90度
实现思路
代码实现
首先把setDisplayOrientation这个屏蔽掉了,因为已经没用了
获取到手机当前的旋转角度
想要获取手机的当前旋转角度,就要用到WindowManager,所以我们要加入WindowManager的定义,还要加入一个默认的角度值。然后在构造函数中获取到当前windowmanager。
根据当前旋转的角度修改生成图像的角度
记得当时有三个重写的参数surfaceCreated,surfaceChanged和surfaceDestoryed,其中我们在surfaceCreated中加入了打开Camera,在surfaceDestoryed中加入了关闭Camera,而surfaceChanged中什么也没写,这次这个方法就被我们用到了。
@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的图像处理,这里做一个备份吧。
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-