OpenGL Surface view

package com.android.driving.view;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.PixelFormat;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;

import com.android.driving.Constant;


/**
 * OpenGL Surface view
 */
public class VideoRendererView extends GLSurfaceView implements GLSurfaceView.Renderer
{
    private final static String TAG =  "VideoRendererViewTAG"+ Constant.EXT_TAG;
    private final int mMaxWidth = Constant.VIDEO_WIDTH_1080P;
    private final int mMaxHeight = Constant.VIDEO_HEIGHT_1080P;

    int mBufferWidthX, mBufferHeightY,  mBufferWidthUV, mBufferHeightUV;
    ByteBuffer mBuffer;
    int mBufferPositionY, mBufferPositionU, mBufferPositionV;

    private static final int FLOAT_SIZE_BYTES = 4;
    private static final int SHORT_SIZE_BYTES = 2;
    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET   = 0;
    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET    = 3;
    private final float[] TRIANFLE_VERTICES_DATA = {
            1, -1, 0, 1, 1,
            1,  1, 0, 1, 0,
            -1,  1, 0, 0, 0,
            -1, -1, 0, 0, 1
    };
    private final short[] INDICES_DATA = {
            0, 1, 2,
            2, 3, 0};

    private FloatBuffer mTriangleVertices;
    private ShortBuffer mIndices;

    private static final String VERTEX_SHADER_SOURCE =
            "attribute vec4 aPosition;\n" +
                    "attribute vec2 aTextureCoord;\n" +
                    "varying vec2 vTextureCoord;\n" +
                    "void main() {\n" +
                    "  gl_Position = aPosition;\n" +
                    "  vTextureCoord = aTextureCoord;\n" +
                    "}\n";

    private static final String FRAGMENT_SHADER_SOURCE = "precision mediump float;" +
            "varying vec2 vTextureCoord;" +
            "" +
            "uniform sampler2D SamplerY; " +
            "uniform sampler2D SamplerU;" +
            "uniform sampler2D SamplerV;" +
            "" +
            "const mat3 yuv2rgb = mat3(1, 0, 1.2802,1, -0.214821, -0.380589,1, 2.127982, 0);" +
            "" +
            "void main() {    " +
            "    vec3 yuv = vec3(1.1643 * (texture2D(SamplerY, vTextureCoord).r - 0.0625)," +
            "                    texture2D(SamplerV, vTextureCoord).r - 0.5," +
            "                    texture2D(SamplerU, vTextureCoord).r - 0.5);" +
            "    vec3 rgb = yuv * yuv2rgb;    " +
            "    gl_FragColor = vec4(rgb, 1.0);" +
            "} ";

    private int mProgram = 0;
    private int maPositionHandle;
    private int maTextureHandle;
    private int muSamplerYHandle;
    private int muSamplerUHandle;
    private int muSamplerVHandle;
    private int[] mTextureY = new int[1];
    private int[] mTextureU = new int[1];
    private int[] mTextureV = new int[1];

    private boolean mSurfaceCreated;
    private boolean mSurfaceDestroyed;
    @SuppressWarnings("unused")
    private Context mContext;

    private int mViewWidth, mViewHeight, mViewX, mViewY;
    private boolean mFullScreenRequired;
    private int mBufSize = 0 ;
    private int mCurChannel = Constant.CHANNEL_BACK;
    private Object mLock = new Object();
    private boolean mIsFront = false;

    public VideoRendererView(Context context) {
        super(context, null);
    }

    public VideoRendererView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setEGLContextClientVersion(2);
        setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        setRenderer(this);
        getHolder().setFormat(PixelFormat.TRANSLUCENT);
        getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        mContext = context;

        mTriangleVertices = ByteBuffer.allocateDirect(TRIANFLE_VERTICES_DATA.length
                * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTriangleVertices.put(TRIANFLE_VERTICES_DATA).position(0);

        mIndices = ByteBuffer.allocateDirect(INDICES_DATA.length
                * SHORT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asShortBuffer();
        mIndices.put(INDICES_DATA).position(0);
        mBufferWidthX = 0;
        mBufferHeightY = 0;
        if(Constant.CUT_YUV_SHOW){
            mBufSize = mMaxWidth * mMaxHeight * 3 / 2;
            mBuffer = ByteBuffer.allocateDirect(mBufSize);
        }else {
            mBufSize = mMaxWidth * mMaxHeight * 3 / 2;
            mBuffer = ByteBuffer.allocateDirect(mBufSize);
        }
    }

    public void setParams(boolean isFront,boolean fullScreenRequired, ByteBuffer buffer, int bufferWidth, int bufferHeight) {
        mFullScreenRequired = fullScreenRequired;
        mIsFront = isFront;
        if(mIsFront){
            mCurChannel = Constant.CHANNEL_FRONT;
        }else {
            mCurChannel = Constant.CHANNEL_BACK;
        }
        setBuffer(buffer, bufferWidth, bufferHeight);
    }
    /*public void notifyVideoSizeChange(boolean fullScreenRequired, ByteBuffer buffer, int newW, int newH) {
        Log.d(TAG,"notifyVideoSizeChange newW="+newW+"; newH="+newH);
        setParams(fullScreenRequired, buffer, newW, newH);
        //mBuffer = ByteBuffer.allocate(mBufferWidthX*mBufferHeightY*3/2);
    }*/
    public void setBuffer(ByteBuffer buffer, int bufferWidth, int bufferHeight){
        /*if((bufferWidth == mBufferWidthX) && (bufferHeight == mBufferHeightY)){
            return;
        }*/
        mBufferWidthX    = bufferWidth;
        mBufferHeightY   = bufferHeight;



        //int length = mBufferWidthX * mBufferHeightY * 3 / 2;
        //byte buf[] = new byte[length];
        //mBuffer          = ByteBuffer.wrap(buf);
        //mBuffer = buffer;

        mBufferWidthUV   = (mBufferWidthX >> 1);
        mBufferHeightUV  = (mBufferHeightY >> 1);

        mBufferPositionY = 0;
        mBufferPositionU = (mBufferWidthX * mBufferHeightY);
        mBufferPositionV = (mBufferPositionU + (mBufferWidthUV * mBufferHeightUV));

        synchronized (mLock){
            mValidDataList.clear();
            mEmptyDataList.clear();
            for(int i = 0; i < 3; i++){
                byte data[] = new byte[mBufSize];
                mEmptyDataList.add(data);
            }

            //默认输入一帧黑图
            byte buf[] = mEmptyDataList.remove(0);
            for(int i = 0; i < mBufferHeightY; i++){
                buf[i] = 16;
            }
            int vLength = mBufferWidthUV * mBufferHeightUV;
            byte blackU = (byte) 128;
            byte blackV = blackU;
            for(int i = 0; i < vLength; i++){
                buf[mBufferPositionU + i] = blackU;
            }
            for(int i = 0; i < vLength; i++){
                buf[mBufferPositionV + i] = blackV;
            }
            mValidDataList.add(buf);

            Log.d(TAG,"setBuffer bufferWidth = " + bufferWidth + " bufferHeight = " + bufferHeight + " mBufSize = " + mBufSize
                    + " mEmptyDataList.size = " + mEmptyDataList.size() );
        }
    }

    @Override
    public void onDrawFrame(GL10 glUnused) {
        if (mProgram == 0) {
            Log.i(TAG, "onDrawFrame mProgram = " + mProgram);
            return;
        }
        if(mIsFront){
            Log.i(TAG, "onDrawFrame mIsFront =true; mProgram = " + mProgram);
        }else {
            Log.i(TAG, "onDrawFrame mIsFront =false; mProgram = " + mProgram);
        }

        GLES20.glViewport(mViewX, mViewY, mViewWidth, mViewHeight);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        GLES20.glUseProgram(mProgram);
        checkGlError("glUseProgram");
        byte[] newData = null;
        synchronized (mLock){
            if (mValidDataList.isEmpty()) {
                return;
            }
            /*if (mBuffer == null)
            {
                mBuffer = ByteBuffer.allocateDirect(mBufferWidthX*mBufferHeightY*3/2);
            }else{
                if(mBuffer.capacity() != mBufferWidthX*mBufferHeightY*3/2){
                    //正常情况下,不会执行到此
                    mValidDataList.clear();
                    mEmptyDataList.clear();
                    Log.d(TAG,"onDrawFrame ERROR mValidDataList.clear(); mEmptyDataList.clear()");
                    return;
                    //mBuffer = ByteBuffer.allocateDirect(mBufferWidthX*mBufferHeightY*3/2);
                }

            }*/
            newData = mValidDataList.remove(0);//mValidDataList.get(0);
        }
        /*Log.d(TAG,"onDrawFrame mBuffer.capacity()="+mBuffer.capacity()+"; =="+mBufferWidthX*mBufferHeightY*3/2+";W="+mBufferWidthX+";H="+mBufferHeightY+";newData.size="
        +newData.length);*/
        /*if(mBuffer.capacity() != newData.length){
            //正常情况下,不会执行到此
            Log.e(TAG,"onDrawFrame ERROR mBuffer.capacity()="+mBuffer.capacity()+"; newData.length=="+newData.length);
            throw new RuntimeException();
        }*/
        //mBuffer.rewind();
        mBuffer.clear();
        mBuffer.put(newData);

        if(mBuffer != null){
            synchronized(this){
                GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
                GLES20.glBindTexture(  GLES20.GL_TEXTURE_2D, mTextureY[0]);
                GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mBufferWidthX, mBufferHeightY, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, mBuffer.position(mBufferPositionY));
                GLES20.glUniform1i(muSamplerYHandle, 0);

                GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
                GLES20.glBindTexture(  GLES20.GL_TEXTURE_2D, mTextureU[0]);
                GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mBufferWidthUV, mBufferHeightUV, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, mBuffer.position(mBufferPositionU));
                GLES20.glUniform1i(muSamplerUHandle, 1);

                GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
                GLES20.glBindTexture(  GLES20.GL_TEXTURE_2D, mTextureV[0]);
                GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, mBufferWidthUV, mBufferHeightUV, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, mBuffer.position(mBufferPositionV));
                GLES20.glUniform1i(muSamplerVHandle, 2);
            }
        }

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, INDICES_DATA.length, GLES20.GL_UNSIGNED_SHORT, mIndices);

        synchronized (mLock) {
            mEmptyDataList.add(newData);
        }
    }

    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        setViewport(width, height);
        // GLU.gluPerspective(glUnused, 45.0f, (float)width/(float)height, 0.1f, 100.0f);
    }

    public boolean isReady(){
        return (mSurfaceCreated && !mSurfaceDestroyed);
    }

    public boolean isDestroyed(){
        return mSurfaceDestroyed;
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mSurfaceCreated   = false;
        mSurfaceDestroyed = true;
        super.surfaceDestroyed(holder);
        Log.i(TAG, "surfaceDestroyed mProgram = " + mProgram);
    }

    public void clearBuf(){
        synchronized (mLock) {
            mEmptyDataList.clear();
            mValidDataList.clear();

            Log.i(TAG, "clearBuf myTid = " + android.os.Process.myTid() + " mValidDataList.size = "
                + mValidDataList.size() + " mEmptyDataList.size = " + mEmptyDataList.size());
        }

    }

    public void release(){
        Log.i(TAG, "release myTid = " + android.os.Process.myTid() + " mProgram = " + mProgram
                + " mPixelShader = " + mPixelShader + " mVertexShader = " + mVertexShader);
        if(mProgram != 0){
            GLES20.glDeleteProgram(mProgram);
            GLES20.glDeleteTextures(1, mTextureY, 0);
            GLES20.glDeleteTextures(1, mTextureU, 0);
            GLES20.glDeleteTextures(1, mTextureV, 0);
            mProgram = 0;
        }

        if(mPixelShader != 0){
            GLES20.glDeleteShader(mPixelShader);
            mPixelShader = 0;
        }

        if(mVertexShader != 0){
            GLES20.glDeleteShader(mVertexShader);
            mVertexShader = 0;
        }
    }

    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
        createTexture();

        mSurfaceCreated = true;
        setViewport(getWidth(), getHeight());
    }

    private void createTexture(){
        if(mProgram != 0){
            Log.d(TAG, "createTexture already create");
            return;
        }
        GLES20.glEnable( GLES20.GL_BLEND);
        GLES20.glDisable(GLES20.GL_DEPTH_TEST);
        GLES20.glDisable(GLES20.GL_DITHER);
        GLES20.glDisable(GLES20.GL_STENCIL_TEST);
        GLES20.glDisable(GL10.GL_DITHER);

        String extensions = GLES20.glGetString(GL10.GL_EXTENSIONS);

        // Ignore the passed-in GL10 interface, and use the GLES20
        // class's static methods instead.
        mProgram = createProgram(VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE);
        if (mProgram == 0) {
            Log.d(TAG, "createTexture Program fail");
            return;
        }
        Log.d(TAG, "createTexture + myTid = " +android.os.Process.myTid() + " mProgram = " +mProgram);

        maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        checkGlError("glGetAttribLocation aPosition");
        if (maPositionHandle == -1) {
            throw new RuntimeException("Could not get attrib location for aPosition");
        }
        maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
        checkGlError("glGetAttribLocation aTextureCoord");
        if (maTextureHandle == -1) {
            throw new RuntimeException("Could not get attrib location for aTextureCoord");
        }

        muSamplerYHandle = GLES20.glGetUniformLocation(mProgram, "SamplerY");
        if (muSamplerYHandle == -1) {
            throw new RuntimeException("Could not get uniform location for SamplerY");
        }
        muSamplerUHandle = GLES20.glGetUniformLocation(mProgram, "SamplerU");
        if (muSamplerUHandle == -1) {
            throw new RuntimeException("Could not get uniform location for SamplerU");
        }
        muSamplerVHandle = GLES20.glGetUniformLocation(mProgram, "SamplerV");
        if (muSamplerVHandle == -1) {
            throw new RuntimeException("Could not get uniform location for SamplerV");
        }

        mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
        checkGlError("glVertexAttribPointer maPosition");

        mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
        GLES20.glEnableVertexAttribArray(maPositionHandle);
        checkGlError("glEnableVertexAttribArray maPositionHandle");
        GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
        checkGlError("glVertexAttribPointer maTextureHandle");
        GLES20.glEnableVertexAttribArray(maTextureHandle);
        checkGlError("glEnableVertexAttribArray maTextureHandle");
        GLES20.glGenTextures(1, mTextureY, 0);
        GLES20.glBindTexture(  GLES20.GL_TEXTURE_2D, mTextureY[0]);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,     GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,     GLES20.GL_CLAMP_TO_EDGE);

        GLES20.glGenTextures(1, mTextureU, 0);
        GLES20.glBindTexture(  GLES20.GL_TEXTURE_2D, mTextureU[0]);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,     GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,     GLES20.GL_CLAMP_TO_EDGE);

        GLES20.glGenTextures(1, mTextureV, 0);
        GLES20.glBindTexture(  GLES20.GL_TEXTURE_2D, mTextureV[0]);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,     GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,     GLES20.GL_CLAMP_TO_EDGE);
    }



    private int mVertexShader = 0;
    private int mPixelShader = 0;
    private int createProgram(String vertexSource, String fragmentSource) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0) {
            Log.d(TAG, "createProgram vertexShader fail");
            return 0;
        }
        mVertexShader= vertexShader;
        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0) {
            Log.d(TAG, "createProgram pixelShader fail");
            return 0;
        }
        mPixelShader = pixelShader;
        int program = GLES20.glCreateProgram();
        if (program != 0) {
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            GLES20.glLinkProgram(program);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {
                Log.e(TAG, "Could not link program: ");
                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    private int loadShader(int shaderType, String source) {
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {
            GLES20.glShaderSource(shader, source);
            GLES20.glCompileShader(shader);
            int[] compiled = new int[1];
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {
                Log.e(TAG, "Could not compile shader " + shaderType + ":");
                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    private void setViewport(int width, int height){
        if(mFullScreenRequired){
            mViewWidth = width;
            mViewHeight = height;
            mViewX = mViewY = 0;
            if(mIsFront){
                mViewX = mViewY = 0;
            }else{
                mViewY = 0;
                mViewX = 0;
            }

        } else{
            float fRatio = ((float) mBufferWidthX / (float) mBufferHeightY);
            mViewWidth = (int) ((float) width / fRatio) > height ? (int) ((float) height * fRatio) : width;
            mViewHeight = (int) (mViewWidth / fRatio) > height ? height : (int) (mViewWidth / fRatio);
            mViewX = ((width - mViewWidth) >> 1);
            mViewY = ((height - mViewHeight) >> 1);
            if(mIsFront){
                mViewX = mViewY = 0;
            }else{
                mViewY = 0;
                mViewX = 0;
                //this.getPivotX()
            }
        }
        Log.i(TAG, "setViewport mViewWidth = " + mViewWidth + " mViewHeight = " + mViewHeight+"; width="+width+"; height="+height+"; mIsFront= "+mIsFront
        +"; mViewX="+mViewX);
    }
    private void checkGlError(String op) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    private final static int BUFFER_COUNT_MIN  = 1;

    private Vector<byte[]> mValidDataList = new Vector<byte[]>();
    private Vector<byte[]>  mEmptyDataList = new Vector<byte[]>();
    public void newDataArrived(final byte[] data, int channel) {
        /*if(channel != mCurChannel){
            return;
        }*/


        byte[] newData;
        synchronized (mLock){
            if (mEmptyDataList.size() > 0)
            {
                newData = mEmptyDataList.remove(0);
            }
            else
            {
                //Log.d(TAG,"newDataArrived data.size="+data.length+";mEmptyDataList.size=="+mEmptyDataList.size());
                //if(mValidDataList.size() >= 2){
                return;
                //}

                //newData = new byte[data.length];
            }
        }

        Log.d(TAG,"newDataArrived data.size="+data.length+";newData.size="+newData.length+"; mValidDataList.size="+mValidDataList.size() + " mEmptyDataList.size = " + mEmptyDataList.size()
        +";mCurChannel="+mCurChannel+"; channel="+channel);
        if(Constant.CUT_YUV_SHOW){
            if(mIsFront) {
                Cut_YV12(data, 0, 0, mBufferWidthX*2, mBufferHeightY, newData, mBufferWidthX, mBufferHeightY);
            }else{
                //显示后半部分
                Cut_YV12(data, mBufferWidthX , 0, mBufferWidthX*2, mBufferHeightY, newData, mBufferWidthX, mBufferHeightY);
            }
        }else {
            System.arraycopy(data, 0, newData, 0, data.length);
        }
        mValidDataList.add(newData);
        this.requestRender();
    }

    public void switchView(){
        if(mCurChannel == Constant.CHANNEL_FRONT){
            mCurChannel = Constant.CHANNEL_BACK;
        }else {
            mCurChannel = Constant.CHANNEL_FRONT;
        }
    }

    static void Cut_YV12(byte[] Src,int x,int y,int srcWidth,int srcHeight,byte[] Dst,int desWidth,int desHeight)//图片按位置裁剪
    {
        //得到B图像所在A的坐标
        int nIndex=0;
        int BPosX=x ;//列
        int BPosY=y;//行
        for(int i=0;i<desHeight;i++)//
        {
            //memcpy(Dst+desWidth*i,Src+(srcWidth*BPosY)+BPosX+nIndex,desWidth);
            //arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
            System.arraycopy(Src, (srcWidth*BPosY)+BPosX+nIndex, Dst, desWidth*i, desWidth);
            nIndex+=(srcWidth);
        }

        nIndex=0;
        //BYTE *pUSour=Src+srcWidth*srcHeight;
        //BYTE *pUDest=Dst+desWidth*desHeight;
        int posUSour = srcWidth*srcHeight;
        int posUDest = desWidth*desHeight;
        for(int i=0;i<desHeight/2;i++)//
        {
            //memcpy(pUDest+desWidth/2*i,pUSour+(srcWidth/2*BPosY/2)+BPosX/2+nIndex,desWidth/2);
            System.arraycopy(Src, posUSour+ (srcWidth/2*BPosY/2)+BPosX/2+nIndex, Dst, posUDest+ desWidth/2*i, desWidth/2);
            nIndex+=(srcWidth/2);
        }

        nIndex=0;
        //BYTE *pVSour=Src+srcWidth*srcHeight*5/4;
        //BYTE *pVDest=Dst+desWidth*desHeight*5/4;
        posUSour = srcWidth*srcHeight*5/4;
        posUDest = desWidth*desHeight*5/4;
        for(int i=0;i<desHeight/2;i++)//
        {
            //memcpy(pVDest+desWidth/2*i,pVSour+(srcWidth/2*BPosY/2)+BPosX/2+nIndex,desWidth/2);
            System.arraycopy(Src, posUSour+ (srcWidth/2*BPosY/2)+BPosX/2+nIndex, Dst, posUDest+ desWidth/2*i, desWidth/2);
            nIndex+=(srcWidth/2);
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gnimey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值