一切尽在效果图~实现一些好玩的,相机、直播,都可以 。。
相机的surface
package com.gmz.mycanera;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
/**
* 作者:haoran on https://github.com/woaigmz 2017/7/14.
* 邮箱:1549112908@qq.com
* 说明:
*/
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private static final String TAG = "CameraSurfaceView";
private Context mContext;
private SurfaceHolder holder;
private Camera mCamera;
private int mScreenWidth;
private int mScreenHeight;
public CameraSurfaceView(Context context) {
this(context, null);
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
getScreenMetrix(context);
initView();
}
private void getScreenMetrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
private void initView() {
holder = getHolder();//获得surfaceHolder引用
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
if (mCamera == null) {
mCamera = Camera.open();//开启相机
try {
mCamera.setPreviewDisplay(holder);//摄像头画面显示在Surface上
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
//设置参数并开始预览
setCameraParams(mCamera, mScreenWidth, mScreenHeight);
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
mCamera.stopPreview();//停止预览
mCamera.release();//释放相机资源
mCamera = null;
holder = null;
}
@Override
public void onAutoFocus(boolean success, Camera Camera) {
if (success) {
Log.i(TAG, "onAutoFocus success="+success);
}
}
// 拍照瞬间调用
private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
Log.i(TAG,"shutter");
}
};
// 获得没有压缩过的图片数据
private Camera.PictureCallback raw = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
Log.i(TAG, "raw");
}
};
//创建jpeg图片回调数据对象
private Camera.PictureCallback jpeg = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
BufferedOutputStream bos = null;
Bitmap bm = null;
try {
// 获得图片
bm = BitmapFactory.decodeByteArray(data, 0, data.length);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Log.i(TAG, "Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory());
String filePath = "/sdcard/dyk"+System.currentTimeMillis()+".jpg";//照片保存路径
File file = new File(filePath);
if (!file.exists()){
file.createNewFile();
}
bos = new BufferedOutputStream(new FileOutputStream(file));
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩到流中
}else{
Toast.makeText(mContext,"没有检测到内存卡", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.flush();//输出
bos.close();//关闭
bm.recycle();// 回收bitmap空间
mCamera.stopPreview();// 关闭预览
mCamera.startPreview();// 开启预览
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
public Camera getCamera() {
return mCamera;
}
public void setAutoFocus(){
mCamera.autoFocus(this);
}
public void takePicture(){
//设置参数,并拍照
setCameraParams(mCamera, mScreenWidth, mScreenHeight);
// 当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览
mCamera.takePicture(null, null, jpeg);
}
private void setCameraParams(Camera camera, int width, int height) {
Log.i(TAG,"setCameraParams width="+width+" height="+height);
Camera.Parameters parameters = mCamera.getParameters();
// 获取摄像头支持的PictureSize列表
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
for (Camera.Size size : pictureSizeList) {
Log.i(TAG, "pictureSizeList size.width=" + size.width + " size.height=" + size.height);
}
/**从列表中选取合适的分辨率*/
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
Log.i(TAG, "null == picSize");
picSize = parameters.getPictureSize();
}
Log.i(TAG, "picSize.width=" + picSize.width + " picSize.height=" + picSize.height);
// 根据选出的PictureSize重新设置SurfaceView大小
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width,picSize.height);
this.setLayoutParams(new FrameLayout.LayoutParams((int) (height*(h/w)), height));
// 获取摄像头支持的PreviewSize列表
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
for (Camera.Size size : previewSizeList) {
Log.i(TAG, "previewSizeList size.width=" + size.width + " size.height=" + size.height);
}
Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
if (null != preSize) {
Log.i(TAG, "preSize.width=" + preSize.width + " preSize.height=" + preSize.height);
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality(100); // 设置照片质量
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
}
mCamera.cancelAutoFocus();//自动对焦。
mCamera.setDisplayOrientation(90);// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示
mCamera.setParameters(parameters);
}
/**
* 从列表中选取合适的分辨率
* 默认w:h = 4:3
* <p>注意:这里的w对应屏幕的height
* h对应屏幕的width<p/>
*/
private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
Log.i(TAG, "screenRatio=" + screenRatio);
Camera.Size result = null;
for (Camera.Size size : pictureSizeList) {
float currentRatio = ((float) size.width) / size.height;
if (currentRatio - screenRatio == 0) {
result = size;
break;
}
}
if (null == result) {
for (Camera.Size size : pictureSizeList) {
float curRatio = ((float) size.width) / size.height;
if (curRatio == 4f / 3) {// 默认w:h = 4:3
result = size;
break;
}
}
}
return result;
}
}
3d模型的glsurface
package com.gmz.mycanera;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* 作者:haoran on https://github.com/woaigmz 2017/7/14.
* 邮箱:1549112908@qq.com
* 说明:
*/
public class OpenGL3DRendererTex implements GLSurfaceView.Renderer {
FloatBuffer _mCubeVertexBuffer;
FloatBuffer _mCubeTexBuffer;
Context _context;
public OpenGL3DRendererTex(Context context) {
_context = context;
} //立方体顶点坐标
private float box[] = {
// FRONT
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// BACK
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// LEFT
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
// RIGHT
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// TOP
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// BOTTOM
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f
};
private float texCoords[] = {
// FRONT
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
// BACK
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
// LEFT
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
// RIGHT
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
// TOP
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
// BOTTOM
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
private float rotx;
private float roty;
private float rotz;
public void onDrawFrame(GL10 gl) {
//清除屏幕
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置模型矩阵
gl.glLoadIdentity();
//开启顶点坐标功能
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//设置顶点坐标
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _mCubeVertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, _mCubeTexBuffer);
//保存matrix当前状态
gl.glPushMatrix();
//向屏幕移入5个单位
gl.glTranslatef(0.0f, 0.0f, -5.0f);
//设置旋转轴,以x轴旋转
gl.glRotatef(rotx, 1, 0, 0);
//设置旋转轴,以y轴旋转
gl.glRotatef(roty, 0, 1, 0);
//设置旋转轴,以z轴旋转
gl.glRotatef(rotz, 0, 0, 1);
/***************************************/
float fscale = 1.0f;
gl.glScalef(fscale, fscale, fscale);
//大小
//----------------------------------------//
//绘制第一个立方体面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
//绘制第二个立方体面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
//绘制第三个立方体面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
//绘制第四个立方体面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
//绘制第五个立方体面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
//绘制第六个立方体面
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
//将matrix回复成上面push时的matrix
// gl.glPopMatrix();
//关闭设置顶点功能
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//使旋转角度不断变化
rotx += 0.2f;
roty += 0.3f;
rotz += 0.4f;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
// TODO Auto-generated method stub
//将顶点坐标转换为native 类型的数据
_mCubeVertexBuffer = createFloatBuffer(box);
_mCubeTexBuffer = createFloatBuffer(texCoords);
//开启纹理功能
gl.glEnable(GL10.GL_TEXTURE_2D);
//加载纹理********************************************
loadBitmapTex(gl, R.mipmap.ic_launcher);
//平滑着色
gl.glShadeModel(GL10.GL_SMOOTH);
//设置黑色背景
//gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
//设置深度缓存
gl.glClearDepthf(1.0f);
//启动深度测试
gl.glEnable(GL10.GL_DEPTH_TEST);
//深度测试的类型
gl.glDepthFunc(GL10.GL_LEQUAL);
//告诉系统对透视进行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
private void loadBitmapTex(GL10 gl, int res) {
//将图片资源转换为位图资源
Bitmap bmp = BitmapFactory.decodeResource(_context.getResources(), res);
//定义1个长度的数组
int mTextureID[] = new int[1];
//将纹理号保存到mTextureID
gl.glGenTextures(1, mTextureID, 0);
//绑定纹理号到纹理目标
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID[0]);
//创建纹理
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
//设定纹理过滤器
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
bmp.recycle();
return;
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
float ratio = (float) width / height;
//设置场景大小
gl.glViewport(0, 0, width, height);
//设置投影矩阵
gl.glMatrixMode(GL10.GL_PROJECTION);
//重置模型矩阵
gl.glLoadIdentity();
//设置窗口比例和透视图
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
//设置模型矩阵
gl.glMatrixMode(GL10.GL_MODELVIEW);
//重置模型矩阵
gl.glLoadIdentity();
}
public static FloatBuffer createFloatBuffer(float data[])
{
ByteBuffer vbb = ByteBuffer.allocateDirect(data.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer outBuffer = vbb.asFloatBuffer();
outBuffer.put(data).position(0);
return outBuffer;
}
}
MainActivity
package com.gmz.mycanera;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
private FrameLayout fl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 全屏显示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setZOrderOnTop(true);
glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
glSurfaceView.setRenderer(new OpenGL3DRendererTex(this));
glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);//设置透明
setContentView(R.layout.activity_main);
fl = (FrameLayout) findViewById(R.id.fl);
fl.addView(new CameraSurfaceView(this));
fl.addView(glSurfaceView);
}
}
权限
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
OK!