/*
*
* AiyaGL.java
*
* Created by Wuwang on 2017/3/3
* Copyright © 2016年 深圳哎吖科技. All rights reserved.
*/
package com.aiyaapp.camera.sdk.widget;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.aiyaapp.camera.sdk.AiyaEffects;
import com.aiyaapp.camera.sdk.base.FrameCallback;
import com.aiyaapp.camera.sdk.base.Log;
import com.aiyaapp.camera.sdk.base.ProcessCallback;
import com.aiyaapp.camera.sdk.base.Renderer;
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;
/**
* 借助GLSurfaceView创建的GL环境,做渲染工作。不将内容渲染到GLSurfaceView
* 的Surface上,而是将内容绘制到外部提供的Surface、SurfaceHolder或者SurfaceTexture上。
*/
public class AiyaController implements GLSurfaceView.Renderer {
private Object surface;
private GLView mGLView;
private Context mContext;
private Renderer mRenderer; //用户附加的Renderer或用来监听Renderer
private AiyaEffects mEffect;
private AiyaEffectFilter mEffectFilter; //特效处理的Filter
private AFilter mShowFilter; //用来渲染输出的Filter
private Point mDataSize; //数据的大小
private Point mWindowSize; //输出视图的大小
private AtomicBoolean isParamSet=new AtomicBoolean(false);
private float[] SM=new float[16]; //用于绘制到屏幕上的变换矩阵
private int mShowType=MatrixUtils.TYPE_CENTERCROP; //输出到屏幕上的方式
private int mDirectionFlag=-1; //AiyaFilter方向flag
private float[] callbackOM=new float[16]; //用于绘制回调缩放的矩阵
//创建离屏buffer,用于最后导出数据
private int[] mExportFrame = new int[1];
private int[] mExportTexture = new int[1];
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索引
public AiyaController(Context context) {
this.mContext=context;
init();
}
public void surfaceCreated(Object nativeWindow){
this.surface=nativeWindow;
mGLView.surfaceCreated(null);
}
public void surfaceChanged(int width,int height){
this.mWindowSize.x=width;
this.mWindowSize.y=height;
mGLView.surfaceChanged(null,0,width,height);
}
public void surfaceDestroyed(){
mGLView.surfaceDestroyed(null);
}
public Object getOutput(){
return surface;
}
private void init(){
mGLView=new GLView(mContext);
//避免GLView的attachToWindow和detachFromWindow崩溃
new ViewGroup(mContext) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
}.addView(mGLView);
mEffectFilter=new AiyaEffectFilter(mContext.getResources());
mShowFilter=new NoFilter(mContext.getResources());
mEffect= AiyaEffects.getInstance();
//设置默认的DateSize,DataSize由AiyaProvider根据数据源的图像宽高进行设置
mDataSize=new Point(720,1280);
mWindowSize=new Point(720,1280);
mGLView.attachedToWindow();
}
//在Surface创建前,应该被调用
public void setDataSize(int width,int height){
mDataSize.x=width;
mDataSize.y=height;
mEffect.set(AiyaEffects.SET_IN_WIDTH,mDataSize.x);
mEffect.set(AiyaEffects.SET_IN_HEIGHT,mDataSize.y);
}
public SurfaceTexture getTexture(){
return mEffectFilter.getTexture();
}
public void setImageDirection(int flag){
this.mDirectionFlag=flag;
}
public void setRenderer(Renderer renderer){
mRenderer=renderer;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mEffectFilter.create();
mShowFilter.create();
if(!isParamSet.get()){
if(mRenderer!=null){
mRenderer.onSurfaceCreated(gl, config);
}
sdkParamSet();
}
calculateCallbackOM();
mEffectFilter.setFlag(mDirectionFlag);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
MatrixUtils.getMatrix(SM,mShowType,
mDataSize.x,mDataSize.y,width,height);
mShowFilter.setSize(width, height);
mShowFilter.setMatrix(SM);
mEffectFilter.setSize(mDataSize.x,mDataSize.y);
mShowFilter.setSize(mDataSize.x,mDataSize.y);
if(mRenderer!=null){
mRenderer.onSurfaceChanged(gl, width, height);
}
Log.e("Matrix changed:"+ Arrays.toString(SM));
deleteFrameBuffer();
GLES20.glGenFramebuffers(1,mExportFrame,0);
EasyGlUtils.genTexturesWithParameter(1,mExportTexture,0,GLES20.GL_RGBA,mDataSize.x,
mDataSize.y);
}
private void deleteFrameBuffer() {
GLES20.glDeleteFramebuffers(1, mExportFrame, 0);
GLES20.glDeleteTextures(1, mExportTexture, 0);
}
@Override
public void onDrawFrame(GL10 gl) {
if(isParamSet.get()){
EData.data.setDealStartTime(System.currentTimeMillis());
mEffectFilter.draw();
//显示传入的texture上,一般是显示在屏幕上
GLES20.glViewport(0,0,mWindowSize.x,mWindowSize.y);
mShowFilter.setMatrix(SM);
mShowFilter.setTextureId(mEffectFilter.getOutputTexture());
mShowFilter.draw();
EData.data.setDealEndTime(System.currentTimeMillis());
if(mRenderer!=null){
mRenderer.onDrawFrame(gl);
}
callbackIfNeeded();
}
}
/**
* 增加滤镜
* @param filter 滤镜
* @param isBeforeProcess 滤镜是否在加特效前增加
*/
public void addFilter(AFilter filter,boolean isBeforeProcess){
mEffectFilter.addFilter(filter,isBeforeProcess);
}
/**
* 设置输入图像与输出视图大小不同时,图像的展示方式
* @param type 展示方式,可选项为:
* {@link MatrixUtils#TYPE_CENTERCROP}、{@link MatrixUtils#TYPE_CENTERINSIDE}、
* {@link MatrixUtils#TYPE_FITEND}、{@link MatrixUtils#TYPE_FITSTART}、
* {@link MatrixUtils#TYPE_FITXY},与{@link ImageView.ScaleType}对应
*/
public void setShowType(int type){
this.mShowType=type;
if(mWindowSize.x>0&&mWindowSize.y>0){
MatrixUtils.getMatrix(SM,MatrixUtils.TYPE_CENTERCROP,
mDataSize.x,mDataSize.y,mWindowSize.x,mWindowSize.y);
mShowFilter.setMatrix(SM);
mShowFilter.setSize(mWindowSize.x,mWindowSize.y);
}
}
public void startRecord(){
isRecord=true;
}
public void stopRecord(){
isRecord=false;
}
public void takePhoto(){
isShoot=true;
}
/**
* 设置美颜等级
* @param level 美颜等级,等级为0-6
*/
public void setFairLevel(int level){
mEffect.set(AiyaEffects.SET_BEAUTY_LEVEL,level);
}
/**
* 设置特效
* @param effect 特效路径
*/
public void setEffect(String effect){
mEffect.setEffect(effect);
}
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];
}
calculateCallbackOM();
this.mFrameCallback = frameCallback;
} else {
this.mFrameCallback = null;
}
}
private void calculateCallbackOM(){
if(frameCallbackHeight>0&&frameCallbackWidth>0&&mDataSize.x>0&&mDataSize.y>0){
//计算输出的变换矩阵
MatrixUtils.getMatrix(callbackOM,MatrixUtils.TYPE_CENTERCROP,mDataSize.x, mDataSize.y,
frameCallbackWidth,
frameCallbackHeight);
MatrixUtils.flip(callbackOM,false,true);
}
}
public Point getWindowSize(){
return mWindowSize;
}
private void sdkParamSet(){
if(!isParamSet.get()&&mDataSize.x>0&&mDataSize.y>0) {
isParamSet.set(true);
mEffect.set(AiyaEffects.SET_IN_WIDTH,mDataSize.x);
mEffect.set(AiyaEffects.SET_IN_HEIGHT,mDataSize.y);
mEffect.setProcessCallback(mcallback);
mEffect.setTrackCallback(mTrackCallback);
}
}
//需要回调,则缩放图片到指定大小,读取数据并回调
private void callbackIfNeeded() {
if (mFrameCallback != null && (isRecord || isShoot)) {
indexOutput = indexOutput++ >= 2 ? 0 : indexOutput;
if (outPutBuffer[indexOutput] == null) {
outPutBuffer[indexOutput] = ByteBuffer.allocate(frameCallbackWidth *
frameCallbackHeight*4);
}
EasyGlUtils.bindFrameTexture(mExportFrame[0],mExportTexture[0]);
GLES20.glViewport(0, 0, frameCallbackWidth, frameCallbackHeight);
mShowFilter.setMatrix(callbackOM);
mShowFilter.draw();
frameCallback();
isShoot = false;
mShowFilter.setMatrix(SM);
EasyGlUtils.unBindFrameBuffer();
}
}
//读取数据并回调
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 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 void create(int width,int height){
mGLView.attachedToWindow();
surfaceCreated(surface);
surfaceChanged(width,height);
}
public void destroy(){
if(mRenderer!=null){
mRenderer.onDestroy();
}
mGLView.surfaceDestroyed(null);
mGLView.detachedFromWindow();
}
public void requestRender(){
mGLView.requestRender();
}
public void onPause(){
mGLView.onPause();
}
public void onResume(){
mGLView.onResume();
}
/** 自定义GLSurfaceView,暴露出onAttachedToWindow
* 方法及onDetachedFromWindow方法,取消holder的默认监听
* onAttachedToWindow及onDetachedFromWindow必须保证view
* 存在Parent */
private class GLView extends GLSurfaceView{
public GLView(Context context) {
super(context);
init();
}
private void init(){
getHolder().addCallback(null);
setEGLWindowSurfaceFactory(new GLSurfaceView.EGLWindowSurfaceFactory() {
@Override
public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig
config, Object window) {
return egl.eglCreateWindowSurface(display,config,surface,null);
}
@Override
public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {
egl.eglDestroySurface(display, surface);
}
});
setEGLContextClientVersion(2);
setRenderer(AiyaController.this);
setRenderMode(RENDERMODE_WHEN_DIRTY);
setPreserveEGLContextOnPause(true);
}
public void attachedToWindow(){
super.onAttachedToWindow();
}
public void detachedFromWindow(){
super.onDetachedFromWindow();
}
}
}