/* * * AiyaCameraView2.java * * Created by Wuwang on 2017/3/1 * Copyright © 2016年 深圳哎吖科技. All rights reserved. */ package com.aiyaapp.camera.sdk.widget; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.graphics.Rect; import android.hardware.Camera; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import com.aiyaapp.camera.sdk.AiyaEffects; import com.aiyaapp.camera.sdk.base.FrameCallback; import com.aiyaapp.camera.sdk.base.ProcessCallback; import com.aiyaapp.camera.sdk.base.TrackCallback; import com.aiyaapp.camera.sdk.etest.EData; import com.aiyaapp.camera.sdk.filter.AFilter; import com.aiyaapp.camera.sdk.filter.AiyaEffectFilter; import com.aiyaapp.camera.sdk.filter.EasyGlUtils; import com.aiyaapp.camera.sdk.filter.MatrixUtils; import com.aiyaapp.camera.sdk.filter.NoFilter; /** * Description: */ public class CameraView extends GLSurfaceView implements GLSurfaceView.Renderer { private AiyaEffects mEffect; private AiyaEffectFilter mEffectFilter; private AFilter mShowFilter; private static CameraController mDefaultCameraController=new CameraController(); private CameraController mCameraController=mDefaultCameraController; private int width,height; private AtomicBoolean isParamSet=new AtomicBoolean(false); private int cameraId=1; private int dataWidth,dataHeight; private float[] SM=new float[16]; //用于绘制到屏幕上的变换矩阵 private float[] callbackOM=new float[16]; //用于绘制回调缩放的矩阵 private boolean isRecord=false; //录像flag private boolean isShoot=false; //一次拍摄flag private ByteBuffer[] outPutBuffer = new ByteBuffer[3]; //用于存储回调数据的buffer private FrameCallback mFrameCallback; //回调 private int frameCallbackWidth, frameCallbackHeight; //回调数据的宽高 private int indexOutput=0; //回调数据使用的buffer索引 //创建离屏buffer,用于最后导出数据 private int[] mExportFrame = new int[1]; private int[] mExportTexture = new int[1]; private Camera mCamera; public CameraView(Context context) { this(context,null); } public CameraView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ mEffect= AiyaEffects.getInstance(); setEGLContextClientVersion(2); setRenderer(this); setRenderMode(RENDERMODE_WHEN_DIRTY); setPreserveEGLContextOnPause(true); setCameraDistance(100); mEffectFilter=new AiyaEffectFilter(getResources()); mShowFilter=new NoFilter(getResources()); } @Override public void onResume() { super.onResume(); if(isParamSet.get()){ openCamera(cameraId); } } @Override public void onPause() { super.onPause(); if(mCamera!=null){ mCamera.stopPreview(); mCamera.release(); mCamera=null; } } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { mEffectFilter.create(); if(!isParamSet.get()){ openCamera(cameraId); updateSdkParams(); if(mFrameCallback!=null){ setFrameCallback(frameCallbackWidth,frameCallbackHeight,mFrameCallback); } mEffectFilter.setSize(dataWidth,dataHeight); } mShowFilter.create(); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { this.width=width; this.height=height; MatrixUtils.getMatrix(SM,MatrixUtils.TYPE_CENTERCROP, dataWidth,dataHeight,width,height); mShowFilter.setMatrix(SM); mShowFilter.setSize(width, height); deleteFrameBuffer(); GLES20.glGenFramebuffers(1,mExportFrame,0); EasyGlUtils.genTexturesWithParameter(1,mExportTexture,0,GLES20.GL_RGBA,dataWidth,dataHeight); } @Override public void onDrawFrame(GL10 gl) { if(isParamSet.get()){ EData.data.setDealStartTime(System.currentTimeMillis()); //接收图像流,特效处理并输出一个texture mEffectFilter.draw(); //显示到屏幕上 GLES20.glViewport(0,0,width,height); mShowFilter.setMatrix(SM); mShowFilter.setTextureId(mEffectFilter.getOutputTexture()); mShowFilter.draw(); EData.data.setDealEndTime(System.currentTimeMillis()); //相机回调数据循环利用 mCameraController.dataRecycle(); callbackIfNeeded(); } } public void onDestroy(){ setPreserveEGLContextOnPause(false); onPause(); } public void switchCamera(){ cameraId=cameraId==0?1:0; openCamera(cameraId); } public int getCameraId(){ return cameraId; } public void setCameraController(CameraController controller){ this.mCameraController=controller; } public void setFairLevel(int level){ mEffect.set(AiyaEffects.SET_BEAUTY_LEVEL,level); } public void setEffect(String effect){ mEffect.setEffect(effect); } public void startRecord(){ isRecord=true; } public void stopRecord(){ isRecord=false; } public void takePhoto(){ isShoot=true; } public void setFrameCallback(int width,int height,FrameCallback frameCallback){ this.frameCallbackWidth =width; this.frameCallbackHeight = height; if (frameCallbackWidth > 0 && frameCallbackHeight > 0) { if(outPutBuffer!=null){ outPutBuffer=new ByteBuffer[3]; } MatrixUtils.getMatrix(callbackOM,MatrixUtils.TYPE_CENTERCROP,dataWidth, dataHeight, frameCallbackWidth, frameCallbackHeight); MatrixUtils.flip(callbackOM,false,true); this.mFrameCallback = frameCallback; } else { this.mFrameCallback = null; } } //需要回调,则缩放图片到指定大小,读取数据并回调 private void callbackIfNeeded() { if (mFrameCallback != null && (isRecord || isShoot)) { indexOutput = indexOutput++ >= 2 ? 0 : indexOutput; if (outPutBuffer[indexOutput] == null) { outPutBuffer[indexOutput] = ByteBuffer.allocate(frameCallbackWidth * frameCallbackHeight*4); } GLES20.glViewport(0, 0, frameCallbackWidth, frameCallbackHeight); EasyGlUtils.bindFrameTexture(mExportFrame[0],mExportTexture[0]); mShowFilter.setMatrix(callbackOM); mShowFilter.draw(); frameCallback(); isShoot = false; EasyGlUtils.unBindFrameBuffer(); mShowFilter.setMatrix(SM); } } //读取数据并回调 private void frameCallback(){ GLES20.glReadPixels(0, 0, frameCallbackWidth, frameCallbackHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, outPutBuffer[indexOutput]); mFrameCallback.onFrame(outPutBuffer[indexOutput].array(),mEffectFilter.getTexture().getTimestamp()); } private void openCamera(int cameraId){ if(mCamera!=null){ mCamera.stopPreview(); mCamera.release(); mCamera=null; } mCamera=mCameraController.openCamera(cameraId); mEffectFilter.setFlag(cameraId); dataWidth=mCamera.getParameters().getPreviewSize().height; dataHeight=mCamera.getParameters().getPreviewSize().width; mCameraController.setCameraCallback(this,mCamera,isParamSet); try { mCamera.setPreviewTexture(mEffectFilter.getTexture()); } catch (IOException e) { e.printStackTrace(); } mCameraController.preview(mCamera); } private void updateSdkParams(){ if(!isParamSet.get()&&dataWidth>0&&dataHeight>0) { isParamSet.set(true); mEffect.set(AiyaEffects.SET_IN_WIDTH,dataWidth); mEffect.set(AiyaEffects.SET_IN_HEIGHT,dataHeight); mEffect.setProcessCallback(mcallback); mEffect.setTrackCallback(mTrackCallback); } } private void deleteFrameBuffer() { GLES20.glDeleteFramebuffers(1, mExportFrame, 0); GLES20.glDeleteTextures(1, mExportTexture, 0); } private ProcessCallback mcallback = new ProcessCallback() { @Override public void onFinished() { } }; private float[] infos=new float[20]; private TrackCallback mTrackCallback=new TrackCallback() { @Override public void onTrack(int trackCode,float[] info) { EData.data.setTrackCode(trackCode); } }; public static class CameraController{ private Camera camera; private byte[][] cameraBuffers; private Queue<byte[]> mByteQueue=new ConcurrentLinkedQueue<>(); protected void setSize(int cameraId,Camera.Parameters param){ Camera.Size picSize = getPropPictureSize(param.getSupportedPictureSizes(), 1.778f, 720); Camera.Size preSize = getPropPreviewSize(param.getSupportedPreviewSizes(), 1.778f, 720); param.setPictureSize(picSize.width, picSize.height); param.setPreviewSize(preSize.width, preSize.height); } protected void otherSetting(Camera.Parameters param){ if (param.getMaxNumFocusAreas() > 0) { Rect areaRect1 = new Rect(-50, -50, 50, 50); List<Camera.Area> focusAreas = new ArrayList<>(); focusAreas.add(new Camera.Area(areaRect1, 1000)); param.setFocusAreas(focusAreas); } // if the camera support setting of metering area. if (param.getMaxNumMeteringAreas() > 0) { List<Camera.Area> meteringAreas = new ArrayList<>(); Rect areaRect1 = new Rect(-100, -100, 100, 100); meteringAreas.add(new Camera.Area(areaRect1, 1000)); param.setMeteringAreas(meteringAreas); } // Log.e("wuwang","camera isVideoStabilizationSupported:"+param // .isVideoStabilizationSupported()); // param.setVideoStabilization(true); //无效 // param.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT); //无效 // List<int[]> al=param.getSupportedPreviewFpsRange(); // for (int[] a:al){ // Log.e("previewSize","size->"+a[0]+"/"+a[1]); // } // param.setPreviewFpsRange(30000,30000); } protected void setRecordHint(Camera.Parameters param){ param.setRecordingHint(true); param.set("video-size", param.getPreviewSize().width + "x" + param.getPreviewSize().height); } public Camera openCamera(int cameraId){ camera=Camera.open(cameraId); if(camera!=null) { Camera.Parameters param = camera.getParameters(); setSize(cameraId,param); setRecordHint(param); otherSetting(param); camera.setParameters(param); } return camera; } public void setCameraCallback(final GLSurfaceView view,Camera camera, final AtomicBoolean isParamSet){ mByteQueue.clear(); int dataSize=camera.getParameters().getPreviewSize().width* camera.getParameters().getPreviewSize().height*4; if(cameraBuffers==null||cameraBuffers[0].length!=dataSize){ cameraBuffers=new byte[3][dataSize]; } for (int i=0;i<3;i++){ camera.addCallbackBuffer(cameraBuffers[i]); } camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { if(isParamSet.get()){ mByteQueue.add(data); view.requestRender(); }else{ camera.addCallbackBuffer(data); } } }); } public void preview(Camera camera){ camera.startPreview(); } public void dataRecycle(){ byte[] data=mByteQueue.poll(); if(data!=null){ camera.addCallbackBuffer(data); } } protected Camera.Size getPropPreviewSize(List<Camera.Size> list, float th, int minWidth){ Collections.sort(list, sizeComparator); int i = 0; for(Camera.Size s:list){ if((s.height >= minWidth) && equalRate(s, th)){ break; } i++; } if(i == list.size()){ i = 0; } return list.get(i); } protected Camera.Size getPropPictureSize(List<Camera.Size> list, float th, int minWidth){ Collections.sort(list, sizeComparator); int i = 0; for(Camera.Size s:list){ if((s.height >= minWidth) && equalRate(s, th)){ break; } i++; } if(i == list.size()){ i = 0; } return list.get(i); } private static boolean equalRate(Camera.Size s, float rate){ float r = (float)(s.width)/(float)(s.height); return Math.abs(r - rate) <= 0.03; } private Comparator<Camera.Size> sizeComparator=new Comparator<Camera.Size>(){ public int compare(Camera.Size lhs, Camera.Size rhs) { // TODO Auto-generated method stub if(lhs.height == rhs.height){ return 0; } else if(lhs.height > rhs.height){ return 1; } else{ return -1; } } }; } }