package com.example.datalibrary.deptrum; 
 | 
  
 | 
import android.opengl.GLES20; 
 | 
import android.opengl.GLSurfaceView; 
 | 
import android.opengl.GLSurfaceView.Renderer; 
 | 
  
 | 
import java.nio.ByteBuffer; 
 | 
  
 | 
import javax.microedition.khronos.egl.EGLConfig; 
 | 
import javax.microedition.khronos.opengles.GL10; 
 | 
  
 | 
/** 
 | 
 * 渲染 
 | 
 */ 
 | 
public class GLFrameRenderer implements Renderer { 
 | 
    private static final int SFPS = 25; 
 | 
  
 | 
    private ISimplePlayer mParentAct; 
 | 
    private GLSurfaceView mTargetSurface; 
 | 
    private RGB24GLProgram rgbProg = new RGB24GLProgram(0); 
 | 
    private YUV420PGLProgram yuvProg = new YUV420PGLProgram(0); 
 | 
    private int mScreenWidth; 
 | 
    private int mScreenHeight; 
 | 
    private int mVideoWidth; 
 | 
    private int mVideoHeight; 
 | 
    private ByteBuffer y; 
 | 
    private ByteBuffer u; 
 | 
    private ByteBuffer v; 
 | 
    private ByteBuffer blackUV; 
 | 
    private ByteBuffer rgb24; 
 | 
  
 | 
    private int mDisplayDegrees; 
 | 
    private boolean mNeedMirror = false; 
 | 
    private long mLastFrameTime = 0; 
 | 
    private long mStanderDelta; 
 | 
    private int dataType = 0; // 0:yuv420p 1:rgb24 
 | 
  
 | 
    public GLFrameRenderer(GLSurfaceView surface) { 
 | 
        // mParentAct = callback; 
 | 
        mTargetSurface = surface; 
 | 
        mDisplayDegrees = 0; 
 | 
        mNeedMirror = false; 
 | 
        mStanderDelta = 1000 / SFPS; 
 | 
    } 
 | 
  
 | 
    public void setResolution(int nWidth, int nHeight) { 
 | 
        mScreenWidth = nWidth; 
 | 
        mScreenHeight = nHeight; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
 | 
        // Utils.LOGD("GLFrameRenderer :: onSurfaceCreated"); 
 | 
        if (!rgbProg.isProgramBuilt()) { 
 | 
            rgbProg.buildProgram(); 
 | 
        } 
 | 
        if (!yuvProg.isProgramBuilt()) { 
 | 
            yuvProg.buildProgram(); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void onSurfaceChanged(GL10 gl, int width, int height) { 
 | 
        // Utils.LOGD("GLFrameRenderer :: onSurfaceChanged"); 
 | 
        GLES20.glViewport(0, 0, width, height); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void onDrawFrame(GL10 gl) { 
 | 
        synchronized (this) { 
 | 
            if (mLastFrameTime == 0) { 
 | 
                mLastFrameTime = System.currentTimeMillis(); 
 | 
            } else { 
 | 
                long currentTime = System.currentTimeMillis(); 
 | 
                long delta = currentTime - mLastFrameTime; 
 | 
                if (delta < mStanderDelta) { 
 | 
                    try { 
 | 
                        Thread.sleep(mStanderDelta - delta); 
 | 
                    } catch (InterruptedException e) { 
 | 
                        e.printStackTrace(); 
 | 
                    } 
 | 
                } 
 | 
                mLastFrameTime = currentTime; 
 | 
            } 
 | 
            switch (dataType) { 
 | 
                case 0: { 
 | 
                    // 绿帧则不渲染 
 | 
                    if (y != null) { 
 | 
                        if (isNullFrame(y, u, v)) { 
 | 
                            return; 
 | 
                        } else { 
 | 
                            y.position(0); 
 | 
                            u.position(0); 
 | 
                            v.position(0); 
 | 
                            yuvProg.buildTextures(y, u, v, mVideoWidth, mVideoHeight); 
 | 
                            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
 | 
                            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 
 | 
                            yuvProg.drawFrame(); 
 | 
                        } 
 | 
                    } 
 | 
                    break; 
 | 
                } 
 | 
                case 1: { 
 | 
                    if (rgb24 != null) { 
 | 
                        rgb24.position(0); 
 | 
                        rgbProg.buildTextures(rgb24, mVideoWidth, mVideoHeight, false); 
 | 
                        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 
 | 
                        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 
 | 
                        rgbProg.drawFrame(); 
 | 
                    } 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    public void clear() { 
 | 
        switch (dataType) { 
 | 
            case 0: { 
 | 
                if (y == null || u == null || v == null) { 
 | 
                    return; 
 | 
                } 
 | 
                int size = this.mVideoWidth * this.mVideoHeight; 
 | 
                byte[] b = new byte[size]; 
 | 
                initBlackUV(); 
 | 
                synchronized (this) { 
 | 
                    y.clear(); 
 | 
                    u.clear(); 
 | 
                    v.clear(); 
 | 
                    y.put(b); 
 | 
                    blackUV.position(0); 
 | 
                    u.put(blackUV); 
 | 
                    blackUV.position(0); 
 | 
                    v.put(blackUV); 
 | 
                } 
 | 
                mTargetSurface.requestRender(); 
 | 
                break; 
 | 
            } 
 | 
            case 1: { 
 | 
                rgb24.clear(); 
 | 
                rgb24.put(new byte[rgb24.capacity()]); 
 | 
                mTargetSurface.requestRender(); 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * this method will be called from native code, it happens when the video is about to play or the 
 | 
     * video size changes. 
 | 
     */ 
 | 
    public void update(int w, int h, int dataType) { 
 | 
        this.dataType = dataType; 
 | 
        // Utils.LOGD("INIT E"); 
 | 
        if (w > 0 && h > 0) { 
 | 
  
 | 
            if (mScreenWidth > 0 && mScreenHeight > 0) { 
 | 
                float f1 = 1f * mScreenHeight / mScreenWidth; 
 | 
                float f2 = 1f * h / w; 
 | 
                if (f1 == f2) { 
 | 
                    rgbProg.createBuffers(RGB24GLProgram.squareVertices); 
 | 
                    yuvProg.createBuffers(YUV420PGLProgram.squareVertices); 
 | 
                } else if (f1 < f2) { 
 | 
                    float widScale = f1 / f2; 
 | 
                    rgbProg.createBuffers( 
 | 
                            new float[]{ 
 | 
                                    -widScale, -1.0f, widScale, -1.0f, -widScale, 1.0f, widScale, 1.0f, 
 | 
                            }); 
 | 
                    yuvProg.createBuffers( 
 | 
                            new float[]{ 
 | 
                                    -widScale, -1.0f, widScale, -1.0f, -widScale, 1.0f, widScale, 1.0f, 
 | 
                            }); 
 | 
                } else { 
 | 
                    float heightScale = f2 / f1; 
 | 
                    rgbProg.createBuffers( 
 | 
                            new float[]{ 
 | 
                                    -1.0f, -heightScale, 1.0f, -heightScale, -1.0f, heightScale, 1.0f, heightScale, 
 | 
                            }); 
 | 
                    yuvProg.createBuffers( 
 | 
                            new float[]{ 
 | 
                                    -1.0f, -heightScale, 1.0f, -heightScale, -1.0f, heightScale, 1.0f, heightScale, 
 | 
                            }); 
 | 
                } 
 | 
            } 
 | 
  
 | 
            if (w != mVideoWidth && h != mVideoHeight) { 
 | 
                this.mVideoWidth = w; 
 | 
                this.mVideoHeight = h; 
 | 
                int yarraySize = w * h; 
 | 
                if (dataType == 0) { 
 | 
                    int uvarraySize = yarraySize / 4; 
 | 
                    synchronized (this) { 
 | 
                        y = ByteBuffer.allocate(yarraySize); 
 | 
                        u = ByteBuffer.allocate(uvarraySize); 
 | 
                        v = ByteBuffer.allocate(uvarraySize); 
 | 
                    } 
 | 
                } else if (dataType == 1) { 
 | 
                    synchronized (this) { 
 | 
                        rgb24 = ByteBuffer.allocate(yarraySize * 3); 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        // mParentAct.onPlayStart(); 
 | 
        // Utils.LOGD("INIT X"); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * this method will be called from native code, it's used for passing yuv data to me. 
 | 
     */ 
 | 
    public void update(byte[] ydata, byte[] udata, byte[] vdata) { 
 | 
        synchronized (this) { 
 | 
            y.clear(); 
 | 
            u.clear(); 
 | 
            v.clear(); 
 | 
            y.put(ydata, 0, ydata.length); 
 | 
            u.put(udata, 0, udata.length); 
 | 
            v.put(vdata, 0, vdata.length); 
 | 
        } 
 | 
        // request to render 
 | 
        mTargetSurface.requestRender(); 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * @param dataType 0:yuv420p 1:rgb24 
 | 
     */ 
 | 
    public void update(byte[] data, int dataType) { 
 | 
        this.dataType = dataType; 
 | 
        int size = this.mVideoWidth * this.mVideoHeight; 
 | 
        synchronized (this) { 
 | 
            switch (this.dataType) { 
 | 
                case 0: { 
 | 
                    y.clear(); 
 | 
                    u.clear(); 
 | 
                    v.clear(); 
 | 
                    y.put(data, 0, size); 
 | 
                    u.put(data, size, size / 4); 
 | 
                    v.put(data, size * 5 / 4, size / 4); 
 | 
                    break; 
 | 
                } 
 | 
                case 1: { 
 | 
                    if (rgb24 == null) { 
 | 
                        rgb24 = ByteBuffer.allocate(size * 3); 
 | 
                    } 
 | 
                    rgb24.clear(); 
 | 
                    rgb24.put(data, 0, size * 3); 
 | 
                    break; 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        // request to render 
 | 
        mTargetSurface.requestRender(); 
 | 
    } 
 | 
  
 | 
    /* 
 | 
     * 取图像四角与中心判定 
 | 
     * */ 
 | 
    private boolean isNullFrame(ByteBuffer y, ByteBuffer u, ByteBuffer v) { 
 | 
        switch (dataType) { 
 | 
            case 0: { 
 | 
                int size = mVideoWidth * mVideoHeight; 
 | 
                if (y == null 
 | 
                        || u == null 
 | 
                        || v == null 
 | 
                        || y.capacity() < size 
 | 
                        || u.capacity() < size / 4 
 | 
                        || v.capacity() < size / 4) { 
 | 
                    return true; 
 | 
                } 
 | 
                int ypos = y.position(); 
 | 
                int upos = u.position(); 
 | 
                int vpos = v.position(); 
 | 
                int[] points = {0, mVideoWidth - 2, size / 2, size - mScreenWidth + 2, size - 2}; 
 | 
                int flag = 2; // 最少两点为绿则判断为绿帧 
 | 
  
 | 
                for (int i = 0; i < 5; i++) { 
 | 
                    if (y.get(points[i]) == 0 && u.get(points[i] / 4) == 0 && v.get(points[i] / 4) == 0) { 
 | 
                        flag--; 
 | 
                        if (flag <= 0) { 
 | 
                            y.position(ypos); 
 | 
                            u.position(upos); 
 | 
                            v.position(vpos); 
 | 
                            return true; 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
                y.position(ypos); 
 | 
                u.position(upos); 
 | 
                v.position(vpos); 
 | 
                return false; 
 | 
            } 
 | 
            case 1: { 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
        return false; 
 | 
    } 
 | 
  
 | 
    private void initBlackUV() { 
 | 
        int size = mVideoWidth * mVideoHeight; 
 | 
        if (blackUV == null || blackUV.capacity() < size / 4) { 
 | 
            blackUV = ByteBuffer.allocate(size / 4); 
 | 
            blackUV.position(0); 
 | 
            for (int i = 0; i < size / 4; i++) { 
 | 
                blackUV.put((byte) 128); 
 | 
            } 
 | 
            blackUV.position(0); 
 | 
        } else { 
 | 
            blackUV.position(0); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * this method will be called from native code, it's used for passing play state to activity. 
 | 
     */ 
 | 
    public void updateState(int state) { 
 | 
        // Utils.LOGD("updateState E = " + state); 
 | 
        if (mParentAct != null) { 
 | 
            mParentAct.onReceiveState(state); 
 | 
        } 
 | 
        // Utils.LOGD("updateState X"); 
 | 
    } 
 | 
  
 | 
    public void setDisplayOrientation(int displayOrientation) { 
 | 
        mDisplayDegrees = displayOrientation; 
 | 
        rgbProg.setDisplayOrientation(displayOrientation, mNeedMirror); 
 | 
        yuvProg.setDisplayOrientation(displayOrientation, mNeedMirror); 
 | 
    } 
 | 
  
 | 
    public void displayMirror(boolean mirror) { 
 | 
        mNeedMirror = mirror; 
 | 
        rgbProg.setDisplayOrientation(mDisplayDegrees, mNeedMirror); 
 | 
        yuvProg.setDisplayOrientation(mDisplayDegrees, mNeedMirror); 
 | 
    } 
 | 
  
 | 
    public void release() { 
 | 
        rgbProg.releaseProgram(); 
 | 
        yuvProg.releaseProgram(); 
 | 
    } 
 | 
} 
 |