xinglin 发表于 2015-1-27 18:27:54

opengl 渲染yuv数据

先帖一下代码public class VideoView extends GLSurfaceView implements GLSurfaceView.Renderer
{
      private int w, h;
      public VideoView(Context context, AttributeSet attrs)
      {
      super(context, attrs);
      setEGLContextClientVersion(2);        // 设置opengl es2 版本
      setRenderer(this);                                // 设置渲染
      getHolder().setFormat(PixelFormat.RGB_565); //
      setRenderMode(RENDERMODE_WHEN_DIRTY);                // 需要时渲
                w = getWidth();
                h = getHeight();
      }

      public VideoView(Context context, AttributeSet attrs, int defStyle)
      {
      super(context);
      }
       
      @Override
      public void onSurfaceCreated(GL10 gl, EGLConfig config)
      {
                int nRe = H264Decoder.GetObj().InitGl(0, 0, w, h);                // 初化始openggl
      }

      @Override
      public void onSurfaceChanged(GL10 gl, int width, int height)
      {
                w = width;
                h = height;
                Log.d("==========", "width:" + w + "   height:" + h);
                H264Decoder.GetObj().ChangedGl(0, 0, w, h);                        // 窗口发生变化时调整opengl
      }
       
      @Override
      public void onDrawFrame(GL10 gl)
      {
                H264Decoder.GetObj().Draw(0, 0, w, h);        // 渲染图片(调用requestRender()此方法通知开始渲染)
      }
}




static void MemCpyYuv()
{
      int w = param.pCodecCtx->width;
      int h = param.pCodecCtx->height;
      int y = param.pFrame->linesize;
      int uv = param.pFrame->linesize;

      if (g_YuvBuff.pszY == NULL)
                g_YuvBuff.pszY = (unsigned char*)malloc(w * h);

      if (g_YuvBuff.pszY)
      {
                unsigned char* p = g_YuvBuff.pszY;
                unsigned char* d = param.pFrame->data;
                for (int i = 0; i < h; ++i)
                {
                        memcpy(p, d, w);
                        p += w;
                        d += y;
                }
      }

      int uvw = (w >> 1);
      int uvh = (h >> 1);

      if (g_YuvBuff.pszU == NULL)
                g_YuvBuff.pszU = (unsigned char*)malloc((w >> 1) * (h >> 1));

      if (g_YuvBuff.pszU)
      {
                unsigned char* p = g_YuvBuff.pszU;
                unsigned char* d = param.pFrame->data;
                for (int i = 0; i < uvh; ++i)
                {
                        memcpy(p, d, uvw);
                        p += uvw;
                        d += uv;
                }
      }

      if (g_YuvBuff.pszV == NULL)
      g_YuvBuff.pszV = (unsigned char*)malloc((w >> 1) * (h >> 1));

      if (g_YuvBuff.pszV)
      {
                unsigned char* p = g_YuvBuff.pszV;
                unsigned char* d = param.pFrame->data;
                for (int i = 0; i < uvh; ++i)
                {
                        memcpy(p, d, uvw);
                        p += uvw;
                        d += uv;
                }
      }
}

void SaveImage(JNIEnv * env, jobject obj)
{
        int y = g_nWidth * g_nHeight;
        int uv = (g_nWidth >> 1) * (g_nHeight >> 1);
        pszYuv = (unsigned char*) malloc(y + uv + uv/*g_nWidth * g_nHeight * 3 >> 1*/);
        if (!pszYuv)
                return ;
       
        memcpy(pszYuv, g_YuvBuff.pszY, y);
        memcpy(pszYuv + y, g_YuvBuff.pszU, uv);
        memcpy(pszYuv + y + uv, g_YuvBuff.pszV, uv);

        jclass cls = env->GetObjectClass(obj);
        jmethodID callback = env->GetMethodID(cls, "SaveImage", "()V");
        env->CallVoidMethod(obj, callback);
        env->DeleteLocalRef(cls);
}

jint decoder(JNIEnv * env, jobject obj, jbyteArray buffer, jint length, jint nOffset, jint nDPI, int nSaveImage)
{
        switch (nDPI)
        {
        case 0:
                if (g_nFrameDrop < 8)
                {
                        ++ g_nFrameDrop;
                        return 0;
                }
        break;
        case 1:
                if (g_nFrameDrop < 5)
                {
                        ++ g_nFrameDrop;
                        return 0;
                }
        break;
        case 2:
                if (g_nFrameDrop < 3)
                {
                        ++ g_nFrameDrop;
                        return 0;
                }
        break;
        case 3:
        break;
        }

        jbyte* jbyteArrayTemp = env->GetByteArrayElements(buffer, NULL);
        uint8_t* pDataFlag = (uint8_t *) jbyteArrayTemp + nOffset;
        uint16_t bufSize = (uint16_t) length;
       
        while (bufSize > 0)
        {
                int size = 0;
                uint8_t * pBuf = NULL;
                int nLen = av_parser_parse2(param.pCodecParser,
                                param.pCodecCtx, &pBuf, &size, (uint8_t*) pDataFlag,
                                bufSize, AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);

                bufSize -= nLen;
                pDataFlag += nLen;

                if (size > 0)
                {
                        param.pkt.data = pBuf;
                        param.pkt.size = size;
                        int nFrameFinished = 0;
                        int len = avcodec_decode_video2(param.pCodecCtx, param.pFrame, &nFrameFinished, &param.pkt);

                        if (nFrameFinished > 0)
                        {
//                                int nDecodeYUVLen = (param.pCodecCtx->width * param.pCodecCtx->height * 3) >> 1;
                               
                                if (param.bFirst == 0)
                                {
                                        g_nWidth = param.pCodecCtx->width;
                                        g_nHeight = param.pCodecCtx->height;
//                                        CreateTexture(0, g_nWidth, g_nHeight, g_YuvBuff.pszY);
//                                        CreateTexture(1, g_nWidth, g_nHeight, g_YuvBuff.pszU);
//                                        CreateTexture(2, g_nWidth, g_nHeight, g_YuvBuff.pszV);
                                        callbackCreateBitmap(env, obj, g_nWidth, g_nHeight);
                                        param.bFirst = 1;
                                }

                                MemCpyYuv();

                                if (1 == nSaveImage)
                                {
                                        SaveImage(env, obj);
                                }

                                g_bIsDraw = 0;
                                callbackInvalidate(env, obj);
                        }
                        av_free_packet(&param.pkt);
                }
        }
       
        env->ReleaseByteArrayElements(buffer, jbyteArrayTemp, 0);
        return 0;
}

GLuint g_ShaderPro; // 着色程序句柄

// 纹理
static GLuint g_nTextureY = -1;
static GLuint g_nTextureU = -1;
static GLuint g_nTextureV = -1;

// 2D纹理地址
static GLuint g_dwSamplerY;
static GLuint g_dwSamplerU;
static GLuint g_dwSamplerV;

// 片元地址
static GLuint g_dwPosition;                        // 顶点坐标
static GLuint g_dwTexCoordIn;                // 纹理坐标

static GLuint g_nV = -1;                // 顶点缓存
static GLuint g_nC = -1;                // 纹理缓存

static int g_nWidth;
static int g_nHeight;

static int g_bIsDraw = 0;

// 顶点着色代码,这里就是把yuv转化为rgb565
#define FRAGMENT_SHADER        "varying lowp vec2 TexCoordOut;\n" \
                                                  "uniform sampler2D SamplerY;\n" \
                                                  "uniform sampler2D SamplerU;\n" \
                                                  "uniform sampler2D SamplerV;\n" \
                                                  "void main()\n" \
                                                  "{\n" \
                                                  "mediump vec3 yuv;\n" \
                                                  "lowp vec3 rgb;\n" \
                                                  "yuv.x = texture2D(SamplerY, TexCoordOut).r;\n" \
                                                  "yuv.y = texture2D(SamplerU, TexCoordOut).r - 0.5;\n" \
                                                  "yuv.z = texture2D(SamplerV, TexCoordOut).r - 0.5;\n" \
                                                  "rgb = mat3(1, 1, 1, 0, -0.39465, 2.03211, 1.13983, -0.58060, 0) * yuv;\n" \
                                                "gl_FragColor = vec4(rgb, 1);\n" \
                                                "}\n"

// 顶点纹理坐标代码
#define VERTEX_SHWDER        "attribute vec4 Position;\n" \
                                                "attribute vec2 TexCoordIn;\n" \
                                                "varying vec2 TexCoordOut;\n" \
                                                "void main()\n" \
                                                "{\n" \
                                                "gl_Position = Position;\n" \
                                                "TexCoordOut = TexCoordIn;\n" \
                                                "}\n"


static int LoadShader(int nType, const char* pszShader)
{
        int s = glCreateShader(nType);                                // 设置着色类型
        glShaderSource(s, 1, &pszShader, NULL);                // 设置着色代码
        glCompileShader(s);                                                        // 编译代码

        int nCompStatus;
        glGetShaderiv(s, GL_COMPILE_STATUS, &nCompStatus);// 获得编译是否成功

        if (nCompStatus != GL_TRUE)
        {
                char szBuf;
                glGetShaderInfoLog(s, 256, &nCompStatus, szBuf);
                LOGE("%s", szBuf);
                glDeleteShader(s);
                return -1;
        }
        return s;
}

jint InitGl(JNIEnv * env, jobject obj, jint x, jint y, jint w, jint h)
{
        LOGI("================== %s ==========", __FUNCTION__);
        glViewport(x, y, w, h);                                // 设置视口

        // 着色器创建
        int v = LoadShader(GL_VERTEX_SHADER, VERTEX_SHWDER);
        if (v == -1)
        {
                LOGE(" %s build vertex failed %d ===\n%s", __FUNCTION__, v, VERTEX_SHWDER);
                return -1;
        }
        int f = LoadShader(GL_FRAGMENT_SHADER, FRAGMENT_SHADER);
        if (f == -1)
        {
                LOGE(" %s build fragment failed %d ===\n%s", __FUNCTION__, f, FRAGMENT_SHADER);
                return -1;
        }

        g_ShaderPro = glCreateProgram();                // 创建着色程序
        glAttachShader(g_ShaderPro, v);                        // 将顶点着色链接到着色容器
        glAttachShader(g_ShaderPro, f);                        // 将片元着色链接到着色容器
        glLinkProgram(g_ShaderPro);                                // 链接着色程序

        int nLinkStatus;
        glGetProgramiv(g_ShaderPro, GL_LINK_STATUS, &nLinkStatus);                // 获得着色程序是否成功
        if (nLinkStatus != GL_TRUE)
        {
                char szBuf;
                glGetProgramInfoLog(g_ShaderPro, 256, &nLinkStatus, szBuf);
                LOGE(" %s build link program failed %s", __FUNCTION__, szBuf);
                glDeleteShader(g_ShaderPro);
                return -1;
        }

        g_dwPosition = glGetAttribLocation(g_ShaderPro, "aPosition");                        // 位置
        g_dwTexCoordIn = glGetAttribLocation(g_ShaderPro, "TexCoordIn");                // 坐标
        LOGI("******************* %s ************** g_dwPosition = %dg_dwTexCoordIn=%d", __FUNCTION__, g_dwPosition, g_dwTexCoordIn);
        return 0;
}

// 窗口发生了变化
void ChangedGl(JNIEnv * env, jobject obj, jint left, jint top, jint right, jint bottom)
{
        LOGI("================== %s ==========", __FUNCTION__);
        g_dwSamplerY = glGetUniformLocation(g_ShaderPro, "SamplerY");// 获得着色器地址值
        g_dwSamplerU = glGetUniformLocation(g_ShaderPro, "SamplerU");
        g_dwSamplerV = glGetUniformLocation(g_ShaderPro, "SamplerV");

        LOGI("******************* %s ---------- g_dwSamplerY = %dg_dwSamplerU = %d g_dwSamplerV = %d", __FUNCTION__, g_dwSamplerY, g_dwSamplerU, g_dwSamplerV);

      //这里的顶点坐标有些和纹理坐不对映,是图片的原因
        float fV[] =
        {
                {-1.0f, -1.0f},         // 左下角
                {1.0f, -1.0f},                 // 右下角
                {-1.0f, 1.0f},                 // 左上角
                {1.0f, 1.0f},                // 右上角
        };

        float fC[] =
        {
                {0.0f, 1.0f},                 // 左上角
                {1.0f, 1.0f},                 // 右上角
                {0.0f, 0.0f},                 // 左下角
                {1.0f, 0.0f}                // 右下角
        };

        // 设置顶点坐标缓存
        if (-1 != g_nV)
                glDeleteBuffers(1, &g_nV);
        glGenBuffers(1, &g_nV);// 生成gpu顶点坐标内存地址
        glBindBuffer(GL_ARRAY_BUFFER, g_nV); // 绑定地址告诉opengl服务器要操作这个地址
        glBufferData(GL_ARRAY_BUFFER, sizeof(fV), fV, GL_STATIC_DRAW);//考呗数据

      // 纹理坐标缓存
        if (-1 != g_nC)
                glDeleteBuffers(1, &g_nC);
        glGenBuffers(1, &g_nC); //
        glBindBuffer(GL_ARRAY_BUFFER, g_nC);
        glBufferData(GL_ARRAY_BUFFER, sizeof(fC), fC, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

      // 生成纹理数据地址
        if (-1 != g_nTextureY)
                glDeleteTextures(1, &g_nTextureY);
        glGenTextures(1, &g_nTextureY);

        if (-1 != g_nTextureU)
                glDeleteTextures(1, &g_nTextureU);
        glGenTextures(1, &g_nTextureU);

        if (-1 != g_nTextureV)
                glDeleteTextures(1, &g_nTextureV);
        glGenTextures(1, &g_nTextureV);
       // 设置视口大小
        glViewport(left, top, right, bottom);
        LOGI("******************* %s ************** g_nTextureY = %dg_nTextureU = %d g_nTextureV = %d", __FUNCTION__, g_nTextureY, g_nTextureU, g_nTextureV);
}

void Draw(JNIEnv * env, jobject obj, jint left, jint top, jint right, jint bottom)
{
        if (0 == param.bFirst || 1 == g_bIsDraw)
                return ;

        g_bIsDraw = 1;
//        LOGI(" left=%d, top=%d, right=%d, bottom=%d", left, top, right, bottom);
        glViewport(left, top, right, bottom);
        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glUseProgram(g_ShaderPro); // 启动着色程序

        glActiveTexture(GL_TEXTURE0); // 激活0层纹理
        glBindTexture(GL_TEXTURE_2D, g_nTextureY); // 绑定纹理ID
        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, g_nWidth, g_nHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszY);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        // GL_LUMINANCE 按照亮度值存储纹理单元
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_nWidth, g_nHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszY);
        glUniform1i(g_dwSamplerY, 0);

        int uvw = g_nWidth >> 1;
        int uvh = g_nHeight >> 1;
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, g_nTextureU);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvw, uvh, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszU);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uvw, uvh, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszU);
        glUniform1i(g_dwSamplerU, 1);

        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, g_nTextureV);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvw, uvh, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszV);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uvw, uvh, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszV);
        glUniform1i(g_dwSamplerV, 2);

       // 将顶点坐标从gpu内存考呗到gpu渲染顶点处
        glBindBuffer(GL_ARRAY_BUFFER, g_nV);
        glVertexAttribPointer(g_dwPosition, 2, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(g_dwPosition);

      // 纹理和顶点一样的原理
        glBindBuffer(GL_ARRAY_BUFFER, g_nC);
        glVertexAttribPointer(g_dwTexCoordIn, 2, GL_FLOAT, GL_FALSE, 0, 0);
        glEnableVertexAttribArray(g_dwTexCoordIn);
       // 启动渲染
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
}






这里没有什么好说的,看代码应该也明白了。我碰到的问题是
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, g_nTextureV);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, uvw, uvh, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, g_YuvBuff.pszV);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

这一部分代码放到窗口变化时只想做一次操作,但在绘制时glTexSubImage2D函数出错说没有在之前调用过glTexImage2D函数对g_nTextureV做处理。


如上面有说不对的请大神指点。


页: [1]
查看完整版本: opengl 渲染yuv数据