package com.android.example.cameraappxjava.util;
import android.graphics.ImageFormat;
import android.media.Image;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
 *  GLES 2.0 相机渲染器:处理 YUV_420_888 预览
 *
 */
public class CameraGLRenderer implements GLSurfaceView.Renderer {
    private static final String TAG = "CameraGLRenderer";
    private static final int TEXTURE_COUNT = 3; // Y/U/V 3个纹理(GLES 2.0 支持)
    // -------------------------- 1. GLES 2.0 兼容配置(无任何不支持API) --------------------------
    /**
     * 顶点着色器(GLES 2.0 标准语法,必加精度声明)
     */
    private static final String VERTEX_SHADER =
            "attribute vec4 vPosition;\n" + // 顶点坐标(输入)
                    "attribute vec2 vTexCoord;\n" + // 纹理坐标(输入)
                    "varying vec2 texCoord;\n" + // 传递纹理坐标到片段着色器
                    "void main() {\n" +
                    " gl_Position = vPosition;\n" + // 全屏顶点位置(-1~1 覆盖屏幕)
                    " texCoord = vTexCoord;\n" + // 传递纹理坐标
                    "}";
    /**
     * 片段着色器(GLES 2.0 兼容:用 GL_LUMINANCE 单通道格式,无 GL_RED)
     */
    private static final String FRAGMENT_SHADER =
            "precision mediump float;\n" + // GLES 2.0 必须声明精度(中等精度平衡性能)
                    "varying vec2 texCoord;\n" + // 从顶点着色器接收的纹理坐标
                    "uniform sampler2D yTex;\n" + // Y通道纹理采样器(纹理单元0)
                    "uniform sampler2D uTex;\n" + // U通道纹理采样器(纹理单元1)
                    "uniform sampler2D vTex;\n" + // V通道纹理采样器(纹理单元2)
                    "void main() {\n" +
                    // GLES 2.0 兼容:读取 GL_LUMINANCE 纹理的 r 通道(亮度值)
                    " float y = texture2D(yTex, texCoord).r;\n" +
                    " float u = texture2D(uTex, texCoord).r - 0.5;\n" + // U/V 偏移 0.5(YUV 标准)
                    " float v = texture2D(vTex, texCoord).r - 0.5;\n" +
                    // BT.601 YUV转RGB 公式(手机相机通用,避免偏色)
                    " float r = y + 1.402 * v;\n" +
                    " float g = y - 0.34414 * u - 0.71414 * v;\n" +
                    " float b = y + 1.772 * u;\n" +
                    // 限制 RGB 范围 0~1(避免颜色溢出,GLES 2.0 支持 clamp 函数)
                    " r = clamp(r, 0.0, 1.0);\n" +
                    " g = clamp(g, 0.0, 1.0);\n" +
                    " b = clamp(b, 0.0, 1.0);\n" +
                    " gl_FragColor = vec4(r, g, b, 1.0);\n" + // 输出 RGB 颜色(不透明)
                    "}";
    /**
     * 全屏顶点坐标(GLES 2.0 标准坐标,顺序:左上→左下→右上→右下)
     */
    private static final float[] VERTEX_COORDS = {
            -1.0f, 1.0f, 0.0f, // 左上
            -1.0f, -1.0f, 0.0f, // 左下
            1.0f, 1.0f, 0.0f, // 右上
            1.0f, -1.0f, 0.0f // 右下
    };
    /**
     * 纹理坐标(GLES 2.0 兼容,适配竖屏预览,解决画面颠倒)
     * 映射规则:纹理坐标 → 屏幕坐标(确保竖屏显示正常)
     */
    private static final float[] TEX_COORDS = {
            0.0f, 1.0f, // 纹理左上 → 屏幕左上
            1.0f, 1.0f, // 纹理左下 → 屏幕左下
            0.0f, 0.0f, // 纹理右上 → 屏幕右上
            1.0f, 0.0f // 纹理右下 → 屏幕右下
    };
    // -------------------------- 2. 动态变量(新增:手动记录纹理尺寸,替代GL查询) --------------------------
    private int mShaderProgram; // GLES 2.0 着色器程序ID
    private int[] mTextureIds = new int[TEXTURE_COUNT]; // Y/U/V 纹理ID(GPU资源)
    private FloatBuffer mVertexBuffer; // 顶点坐标缓冲区(GLES 2.0 要求Buffer格式)
    private FloatBuffer mTexBuffer; // 纹理坐标缓冲区(GLES 2.0 要求Buffer格式)
    private int mViewWidth, mViewHeight; // GLSurfaceView 宽高(渲染视口尺寸)
    // 关键:手动记录 Y/U/V 纹理的宽高(替代 GLES 2.0 不支持的 glGetTexLevelParameteriv)
    private int mYTexWidth = 0, mYTexHeight = 0; // Y纹理尺寸
    private int mUTexWidth = 0, mUTexHeight = 0; // U纹理尺寸(Y的1/2)
    private int mVTexWidth = 0, mVTexHeight = 0; // V纹理尺寸(Y的1/2)
    // YUV 数据线程安全管理(避免相机线程与渲染线程竞争)
    private final Object mYuvLock = new Object();
    private Image mPendingImage; // 待处理的相机Image(从Camera2接收)
    private byte[] mYData, mUData, mVData; // 提取后的 Y/U/V 字节数据
    private int mYuvWidth, mYuvHeight; // 相机输出的 YUV 帧宽高
    // -------------------------- 3. 对外接口(无修改,直接复用) --------------------------
    /**
     * 设置相机预览Image(线程安全,GLES 2.0/3.0 通用)
     *
     * @param image 相机输出的 YUV_420_888 格式Image(必须关闭,避免内存泄漏)
     */
    public void setYUVData(Image image) {
        Log.w(TAG, "调用setYUVData方法");
        if (image == null || image.getFormat() != ImageFormat.YUV_420_888) {
            Log.w(TAG, "无效Image:格式非 YUV_420_888 或 Image为空");
            if (image != null) image.close(); // 必须关闭,避免相机缓冲区泄漏
            return;
        }
        synchronized (mYuvLock) {
            // 先关闭之前未处理的Image(防止缓冲区堆积导致卡顿)
            if (mPendingImage != null) {
                mPendingImage.close();
                Log.d(TAG, "关闭未处理的PendingImage,避免内存泄漏");
            }
            mPendingImage = image; // 存储新的待处理Image
            
        }
    }
    /**
     * 释放所有资源(Activity/Fragment 销毁时调用,避免内存泄漏)
     */
    public void release() {
        synchronized (mYuvLock) {
            // 1. 关闭待处理的Image
            if (mPendingImage != null) {
                mPendingImage.close();
                mPendingImage = null;
            }
            // 2. 释放CPU端 YUV 数据
            mYData = null;
            mUData = null;
            mVData = null;
            mYuvWidth = 0;
            mYuvHeight = 0;
            // 3. 重置手动记录的纹理尺寸
            mYTexWidth = mYTexHeight = 0;
            mUTexWidth = mUTexHeight = 0;
            mVTexWidth = mVTexHeight = 0;
        }
        // 4. 释放 GLES 2.0 GPU 资源(纹理+着色器程序)
        if (mTextureIds != null) {
            GLES20.glDeleteTextures(TEXTURE_COUNT, mTextureIds, 0);
            mTextureIds = null;
        }
        if (mShaderProgram != 0) {
            GLES20.glDeleteProgram(mShaderProgram);
            mShaderProgram = 0;
        }
        // 5. 释放缓冲区(帮助GC回收)
        mVertexBuffer = null;
        mTexBuffer = null;
        Log.d(TAG, "所有资源释放完成(GLES 2.0 兼容)");
    }
    // -------------------------- 4. GLES 2.0 生命周期回调(无任何不支持API) --------------------------
    /**
     * 初始化回调:GLSurfaceView 首次创建时调用(仅1次)
     * 作用:初始化OpenGL环境、编译着色器、创建纹理、准备坐标缓冲区
     */
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        Log.d(TAG, "onSurfaceCreated(GLES 2.0):初始化OpenGL环境");
        // GLES 2.0 基础配置:禁用混合(避免透明层干扰预览)、黑色背景
        GLES20.glDisable(GLES20.GL_BLEND);
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        // 准备坐标缓冲区(GLES 2.0 仅支持 Buffer 格式,不支持直接用数组)
        mVertexBuffer = createFloatBuffer(VERTEX_COORDS);
        mTexBuffer = createFloatBuffer(TEX_COORDS);
        // 编译 GLES 2.0 着色器程序(创建渲染"画笔")
        mShaderProgram = compileShaderProgram(VERTEX_SHADER, FRAGMENT_SHADER);
        if (mShaderProgram == 0) {
            Log.e(TAG, "着色器程序创建失败(GLES 2.0),预览不可用");
            return;
        }
        // 创建 Y/U/V 3个纹理(GLES 2.0 2D纹理),配置基础参数
        GLES20.glGenTextures(TEXTURE_COUNT, mTextureIds, 0);
        initTexture(mTextureIds[0]); // 初始化 Y 纹理
        initTexture(mTextureIds[1]); // 初始化 U 纹理
        initTexture(mTextureIds[2]); // 初始化 V 纹理
        Log.d(TAG, "GLES 2.0 初始化完成,纹理ID:Y=" + mTextureIds[0] + ", U=" + mTextureIds[1] + ", V=" + mTextureIds[2]);
    }
    /**
     * 尺寸变化回调:GLSurfaceView 宽高改变时调用(如屏幕旋转)
     * 作用:设置渲染视口(画面显示范围),确保全屏渲染
     */
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mViewWidth = width;
        mViewHeight = height;
        // GLES 2.0 设置视口:渲染范围 = GLSurfaceView 全屏(左上角(0,0),宽高=View宽高)
        GLES20.glViewport(0, 0, width, height);
        Log.d(TAG, "onSurfaceChanged(GLES 2.0):视口尺寸=" + width + "x" + height);
    }
    /**
     * 帧渲染回调:每帧调用1次(渲染线程执行,核心渲染逻辑)
     * 流程:处理待处理Image → 上传YUV数据到纹理 → 绑定着色器 → 执行渲染
     */
    @Override
    public void onDrawFrame(GL10 gl) {
        Log.e(TAG, "调用onDrawFrame方法");
        // 1. 处理待处理的Image(线程安全,提取Y/U/V数据)
        boolean hasNewData = processPendingImage();
        if (!hasNewData) {
            // 无新数据:清除屏幕为黑色,避免显示上一帧残留
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
            return;
        }
        // 2. 清除上一帧画面(避免画面重叠)
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        // 3. 激活 GLES 2.0 着色器程序(使用"画笔")
        GLES20.glUseProgram(mShaderProgram);
        // 4. 上传 Y/U/V 数据到对应纹理(手动判断纹理尺寸,替代GL查询)
        uploadTexture(mTextureIds[0], mYData, mYuvWidth, mYuvHeight, true); // Y纹理
        uploadTexture(mTextureIds[1], mUData, mYuvWidth / 2, mYuvHeight / 2, false); // U纹理(1/2尺寸)
        uploadTexture(mTextureIds[2], mVData, mYuvWidth / 2, mYuvHeight / 2, false); // V纹理(1/2尺寸)
        // 5. 绑定纹理到着色器采样器(让"画笔"找到"画布")
        bindTextureToSampler();
        // 6. 传递顶点/纹理坐标(告诉"画笔"画在哪里)
        passVertexAndTexCoord();
        // 7. 执行渲染:GLES 2.0 支持 GL_TRIANGLE_STRIP,4个顶点画2个三角形覆盖全屏
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX_COORDS.length / 3);
        // 8. 禁用顶点/纹理坐标输入(避免后续渲染干扰)
        int vPositionLoc = GLES20.glGetAttribLocation(mShaderProgram, "vPosition");
        int vTexCoordLoc = GLES20.glGetAttribLocation(mShaderProgram, "vTexCoord");
        GLES20.glDisableVertexAttribArray(vPositionLoc);
        GLES20.glDisableVertexAttribArray(vTexCoordLoc);
    }
    private void passVertexAndTexCoord() {
        int vPositionLoc = GLES20.glGetAttribLocation(mShaderProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(vPositionLoc);
        GLES20.glVertexAttribPointer(
                vPositionLoc,
                3,
                GLES20.GL_FLOAT,
                false,
                3 * 4,
                mVertexBuffer
        );
        int vTexCoordLoc = GLES20.glGetAttribLocation(mShaderProgram, "vTexCoord");
        GLES20.glEnableVertexAttribArray(vTexCoordLoc);
        GLES20.glVertexAttribPointer(
                vTexCoordLoc, 2,
                GLES20.GL_FLOAT,
                false,
                2 * 4,
                mTexBuffer
        );
    }
    // -------------------------- 5. GLES 2.0 辅助方法(无任何不支持API) --------------------------
    /**
     * 创建 FloatBuffer:将 Java float 数组转为 GLES 2.0 支持的 Buffer 格式
     *
     * @param array 原始 float 数组(顶点/纹理坐标)
     * @return GLES 2.0 可识别的 FloatBuffer
     */
    private FloatBuffer createFloatBuffer(float[] array) {
        if (array == null || array.length == 0) return null;
        // 1. 分配直接内存(避免JVM GC移动,提升OpenGL访问效率)
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(array.length * 4); // 1float=4字节
        // 2. 设置字节序(必须与硬件一致,否则数据错乱)
        byteBuffer.order(ByteOrder.nativeOrder());
        // 3. 转换为 FloatBuffer 并写入数据
        FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
        floatBuffer.put(array);
        // 4. 重置读指针(从缓冲区开头开始读取)
        floatBuffer.position(0);
        return floatBuffer;
    }
    /**
     * 编译 GLES 2.0 着色器程序:编译顶点+片段着色器,链接为可执行程序
     *
     * @param vertexCode   顶点着色器代码
     * @param fragmentCode 片段着色器代码
     * @return 着色器程序ID(0 表示失败)
     */
    private int compileShaderProgram(String vertexCode, String fragmentCode) {
        // 1. 编译顶点着色器(GLES 2.0)
        int vertexShader = compileSingleShader(GLES20.GL_VERTEX_SHADER, vertexCode);
        if (vertexShader == 0) return 0;
        // 2. 编译片段着色器(GLES 2.0)
        int fragmentShader = compileSingleShader(GLES20.GL_FRAGMENT_SHADER, fragmentCode);
        if (fragmentShader == 0) {
            GLES20.glDeleteShader(vertexShader); // 清理已编译的顶点着色器
            return 0;
        }
        // 3. 链接着色器程序(GLES 2.0)
        int program = GLES20.glCreateProgram();
        GLES20.glAttachShader(program, vertexShader); // 绑定顶点着色器
        GLES20.glAttachShader(program, fragmentShader); // 绑定片段着色器
        GLES20.glLinkProgram(program); // 执行链接
        // 4. 检查链接结果(GLES 2.0)
        int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
        if (linkStatus[0] != GLES20.GL_TRUE) {
            Log.e(TAG, "着色器链接失败(GLES 2.0):" + GLES20.glGetProgramInfoLog(program));
            GLES20.glDeleteProgram(program); // 清理无效程序
            program = 0;
        }
        // 5. 清理中间着色器(程序已链接,单个着色器可删除)
        GLES20.glDeleteShader(vertexShader);
        GLES20.glDeleteShader(fragmentShader);
        return program;
    }
    /**
     * 编译单个 GLES 2.0 着色器:编译顶点/片段着色器代码
     *
     * @param shaderType 着色器类型(GL_VERTEX_SHADER / GL_FRAGMENT_SHADER)
     * @param shaderCode 着色器代码
     * @return 着色器ID(0 表示失败)
     */
    private int compileSingleShader(int shaderType, String shaderCode) {
        // 1. 创建着色器对象(GLES 2.0)
        int shader = GLES20.glCreateShader(shaderType);
        if (shader == 0) {
            Log.e(TAG, "创建着色器失败(GLES 2.0),类型=" + (shaderType == GLES20.GL_VERTEX_SHADER ? "顶点" : "片段"));
            return 0;
        }
        // 2. 绑定着色器代码并编译(GLES 2.0)
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        // 3. 检查编译结果(GLES 2.0)
        int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
        if (compileStatus[0] != GLES20.GL_TRUE) {
            Log.e(TAG, (shaderType == GLES20.GL_VERTEX_SHADER ? "顶点" : "片段") + "着色器编译失败(GLES 2.0):" + GLES20.glGetShaderInfoLog(shader));
            GLES20.glDeleteShader(shader); // 清理无效着色器
            shader = 0;
        }
        return shader;
    }
    /**
     * 初始化 GLES 2.0 纹理参数:配置过滤、边缘处理,确保画面清晰无重复
     *
     * @param textureId 纹理ID(Y/U/V 纹理)
     */
    private void initTexture(int textureId) {
        if (textureId == 0) return;
        // 绑定纹理(选中GPU"画布",GLES 2.0 必须先绑定再配置)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        // 1. 纹理过滤:缩小时线性过滤(画面平滑,避免锯齿)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        // 2. 纹理过滤:放大时线性过滤(画面平滑,避免像素块)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        // 3. 纹理边缘:水平方向超出范围时"夹紧"(不重复显示,避免边缘错乱)
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        // 4. 纹理边缘:垂直方向超出范围时"夹紧"
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        // 解绑纹理(避免后续误操作其他纹理)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    }
    /**
     * 处理待处理Image:从 mPendingImage 提取 Y/U/V 数据(线程安全)
     *
     * @return true=有新数据,false=无新数据
     */
    private boolean processPendingImage() {
        Image image = null;
        synchronized (mYuvLock) {
            if (mPendingImage == null) {
                return false; // 无待处理数据
            }
            // 取出待处理Image(释放锁,避免长时间占用)
            image = mPendingImage;
            mPendingImage = null;
        }
        try {
            // 1. 提取Image的宽高和Planes(YUV_420_888 格式固定3个Planes)
            mYuvWidth = image.getWidth();
            mYuvHeight = image.getHeight();
            Log.e(TAG, "YUV的宽高:"+mYuvWidth+"×"+mYuvHeight);
            Image.Plane[] planes = image.getPlanes();
            if (planes.length < 3) {
                Log.e(TAG, "Image Planes 数量不足3,无法提取 YUV 数据");
                return false;
            }
            // 2. 提取 Y 通道数据(Plane[0]:Y通道,无交错)
            ByteBuffer yBuffer = planes[0].getBuffer();
            mYData = byteBufferToByteArray(yBuffer);
            // 3. 提取 U/V 通道数据(区分 Semi-Planar 和 Planar 模式)
            if (planes[1].getPixelStride() == 2) {
                // 模式1:Semi-Planar(UV 交错存储在 Plane[1],Plane[2] 无数据)
                ByteBuffer uvBuffer = planes[1].getBuffer();
                int uvLength = uvBuffer.remaining() / 2; // UV 总长度 = Y 长度 / 2
                mUData = new byte[uvLength];
                mVData = new byte[uvLength];
                // 提取 U(偶数索引)和 V(奇数索引)
                for (int i = 0; i < uvLength; i++) {
                    mUData[i] = uvBuffer.get(i * 2); // U:第0、2、4...字节
                    mVData[i] = uvBuffer.get(i * 2 + 1); // V:第1、3、5...字节
                }
            } else {
                // 模式2:Planar(UV 分别存储在 Plane[1] 和 Plane[2],无交错)
                ByteBuffer uBuffer = planes[1].getBuffer();
                ByteBuffer vBuffer = planes[2].getBuffer();
                mUData = byteBufferToByteArray(uBuffer);
                mVData = byteBufferToByteArray(vBuffer);
            }
            // 4. 验证 YUV 数据长度(避免后续渲染错误)
            int expectedYLength = mYuvWidth * mYuvHeight;
            int expectedUVLength = (mYuvWidth / 2) * (mYuvHeight / 2);
            if (mYData.length != expectedYLength || mUData.length != expectedUVLength || mVData.length != expectedUVLength) {
                Log.w(TAG, "YUV 数据长度不匹配,重置为正确长度");
                mYData = new byte[expectedYLength];
                mUData = new byte[expectedUVLength];
                mVData = new byte[expectedUVLength];
                return false;
            }
            Log.d(TAG, "处理 Image 完成(GLES 2.0):YUV 尺寸=" + mYuvWidth + "x" + mYuvHeight + ",数据长度 Y=" + mYData.length + ", U=" + mUData.length);
            return true;
        } catch (Exception e) {
            Log.e(TAG, "处理 Image 异常(GLES 2.0):" + e.getMessage(), e);
            return false;
        } finally {
            // 必须关闭 Image(释放相机缓冲区,避免卡顿的核心!)
            if (image != null) {
                image.close();
            }
        }
    }
    private byte[] byteBufferToByteArray(ByteBuffer buffer) {
        if (buffer == null | buffer.remaining() == 0) return new byte[0];
        int originalPos = buffer.position();
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);
        buffer.position(originalPos);
        return data;
    }
    /**
     * 上传数据到 GLES 2.0 纹理(核心:手动记录纹理尺寸,替代 GL 查询)
     *
     * @param textureId  纹理ID
     * @param data       待上传的字节数据(Y/U/V)
     * @param width      纹理宽度
     * @param height     纹理高度
     * @param isYTexture 是否为 Y 纹理(用于区分尺寸记录变量)
     */
    private void uploadTexture(int textureId, byte[] data, int width, int height, boolean isYTexture) {
        if (textureId == 0 || data == null || width <= 0 || height <= 0) {
            Log.w(TAG, "上传纹理参数无效(GLES 2.0):textureId=" + textureId + ", width=" + width + ", height=" + height);
            return;
        }
        // 绑定纹理(GLES 2.0 必须先绑定再操作)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        // 关键:设置像素对齐为 1(YUV 数据无字节对齐,避免数据错位)
        GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
        // 手动判断纹理是否已创建(替代 GLES 2.0 不支持的 glGetTexLevelParameteriv)
        boolean isTextureCreated = false;
        if (isYTexture) {
            isTextureCreated = (mYTexWidth == width && mYTexHeight == height);
        } else {
            // U/V 纹理尺寸相同,共用一套判断
            isTextureCreated = (mUTexWidth == width && mUTexHeight == height);
        }
        ByteBuffer dataBuffer = ByteBuffer.wrap(data);
        if (!isTextureCreated) {
            // 首次创建纹理:调用 glTexImage2D(分配GPU内存)
            GLES20.glTexImage2D(
                    GLES20.GL_TEXTURE_2D, 0, // 2D纹理,基础层级(固定为0)
                    GLES20.GL_LUMINANCE, // GLES 2.0 核心:单通道亮度格式
                    width, height, 0, // 纹理宽高,边界宽度(必须为0)
                    GLES20.GL_LUMINANCE, // 数据格式:与内部格式一致
                    GLES20.GL_UNSIGNED_BYTE, // 数据类型:无符号字节(YUV 数据类型)
                    dataBuffer // 待上传的 Y/U/V 数据
            );
            // 更新手动记录的纹理尺寸(下次判断用)
            if (isYTexture) {
                mYTexWidth = width;
                mYTexHeight = height;
                Log.d(TAG, "创建 Y 纹理(GLES 2.0):尺寸=" + width + "x" + height);
            } else {
                mUTexWidth = width;
                mUTexHeight = height;
                Log.d(TAG, "创建 U/V 纹理(GLES 2.0):尺寸=" + width + "x" + height);
            }
        } else {
            // 复用纹理:调用 glTexSubImage2D(仅更新数据,不重新分配GPU内存,效率更高)
            GLES20.glTexSubImage2D(
                    GLES20.GL_TEXTURE_2D, 0, // 2D纹理,基础层级
                    0, 0, // 数据起始坐标(x=0, y=0,全屏更新)
                    width, height, // 数据宽高(与纹理尺寸一致)
                    GLES20.GL_LUMINANCE, // 数据格式:与创建时一致
                    GLES20.GL_UNSIGNED_BYTE, // 数据类型:与创建时一致
                    dataBuffer // 待更新的 Y/U/V 数据
            );
        }
        // 解绑纹理(避免后续误操作)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    }
    /**
     * 绑定纹理到 GLES 2.0 着色器采样器:将 Y/U/V 纹理与着色器的 uniform 变量关联
     */
    private void bindTextureToSampler() {
        // 1. 绑定 Y 纹理到采样器 yTex(纹理单元0)
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0); // 激活纹理单元0(GLES 2.0 必须先激活)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[0]); // 绑定 Y 纹理
        // 关联采样器:将纹理单元0 与 着色器的 yTex 变量绑定
        int yTexLoc = GLES20.glGetUniformLocation(mShaderProgram, "yTex");
        GLES20.glUniform1i(yTexLoc, 0);
        // 2. 绑定 U 纹理到采样器 uTex(纹理单元1)
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1); // 激活纹理单元1
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[1]); // 绑定 U 纹理
        int uTexLoc = GLES20.glGetUniformLocation(mShaderProgram, "uTex");
        GLES20.glUniform1i(uTexLoc, 1);
        // 3. 绑定 V 纹理到采样器 vTex(纹理单元2)
        GLES20.glActiveTexture(GLES20.GL_TEXTURE2); //激活纹理单元2
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIds[2]);
        int vTexLoc = GLES20.glGetUniformLocation(mShaderProgram, "vTex");
        GLES20.glUniform1i(vTexLoc, 2);
        // 添加错误检查
        if (yTexLoc == -1 || uTexLoc == -1 || vTexLoc == -1) {
            Log.e(TAG, "纹理采样器绑定失败: "
                    + "yTex=" + yTexLoc + " uTex=" + uTexLoc + " vTex=" + vTexLoc);
        }
    }
}
我给代码发给你,结合这两部分代码你来找出问题
					最新发布