美文网首页
直播技术笔记(1)——camera的纹理

直播技术笔记(1)——camera的纹理

作者: golden_age | 来源:发表于2016-08-22 12:15 被阅读0次

    按: 最近做了一个直播的预研项目, 因此记录下直播的技术的实现,在这过程中一些问题解决的思路,以android平台的实现说明。

    项目结构

    • unity纹理插件和视频采集(视频源)
      VideoSourceCamera
    • 麦克风采集(音频源)
      AudioSourceMIC
    • 视频编码
      VideoEncoder
    • 音频编码
      AudioEncoder
    • FLV编码(混合)
      MuxerFLV
    • http流上传(上传源)
      PublisherHttp
    • 流视频播放(回放)
      play
    • OpenGL图形图象处理

    从本篇文章开始将会介绍这几个组件的实现细节,相互依赖关系的处理方式。

    (1) —— unity纹理插件

    我们的直播项目服务于unity,而unity是一个跨平台的游戏引擎,底层根据不同平台,采用了directx, opengl, opengles, 因此需要实现不同平台的图形插件。
    (unity的图形插件文档)
    https://docs.unity3d.com/Manual/NativePluginInterface.html
    在anroid平台下的直播,unity图形插件作用主要是渲染线程通知,
    因为无论视频采集,创建surface, 图像处理(shader),还是编码视频纹理传入,都需要工作在unity的渲染线程下,

    • unity创建纹理,将纹理ID传递到直播插件。

    • 打开camera设备,准备好采集surface,
      mCameraGLTexture =
      new GLTexture(width, height, GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_RGBA);
      note: camera surface是一种特殊类型的纹理,通过GLES11Ext.GL_TEXTURE_EXTERNAL_OES参数创建

    • 回调通知每一帧数据准备完成
      public void onFrameAvailable(final SurfaceTexture surfaceTexture)
      {
      //这里将采集线程的图象push到渲染线程处理
      getProcessor().append (new Task() {
      @Override
      public void run() {
      surfaceTexture.updateTexImage();
      }
      });
      }

      camera surface也需要做特殊纹理声明

        #extension GL_OES_EGL_image_external : require
        precision mediump float;
        uniform samplerExternalOES uTexture0;
        varying vec2 texCoordinate;
        void main(){
            gl_FragColor = texture2D(uTexture0, texCoordinate);
        }
      
    • 将camera surface纹理写入到 unity的纹理,
      将一张纹理写入到另一纹理,可以两种办法,

      • 通过glReadPixels, 但这样会导致巨大的内存拷贝,CPU压力。

      • 渲染到纹理(render to texture)
        mTextureCanvas = new GLRenderTexture(mGLTexture);//声明rendertexture

          void renderCamera2Texture()
          {
              mTextureCanvas.begin();
              cameraDrawObject.draw();
              mTextureCanvas.end();
          }
        

        GLRenderTexture的实现, 如下
        GLRenderTexture(GLTexture tex)
        {
        mTex = tex;
        int fboTex = tex.getTextureID();
        GLES20.glGenFramebuffers(1, bufferObjects, 0);
        GLHelper.checkGlError("glGenFramebuffers");
        fobID = bufferObjects[0];

              //创建render buffer
              GLES20.glGenRenderbuffers(1, bufferObjects, 0);
              renderBufferId = bufferObjects[0];
              //绑定Frame buffer
              GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fobID);
              GLHelper.checkGlError("glBindFramebuffer");
              //Bind render buffer and define buffer dimension
              GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBufferId);
              GLHelper.checkGlError("glBindRenderbuffer");
              GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, tex.getWidth(), tex.getHeight());
              GLHelper.checkGlError("glRenderbufferStorage");
              //设置为framebuffer为texutre类型
              GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fboTex, 0);
              GLHelper.checkGlError("glFramebufferTexture2D");
              //设置depthbuffer
              GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, renderBufferId);
              GLHelper.checkGlError("glFramebufferRenderbuffer");
              //we are done, reset
              GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, 0);
              GLHelper.checkGlError("glBindRenderbuffer");
              GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
              GLHelper.checkGlError("glBindFramebuffer");
          }
          
          void begin()
          {
              GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fobID);
              GLHelper.checkGlError("glBindFramebuffer");
              GLES20.glViewport(0, 0, mTex.getWidth(), mTex.getHeight());
              GLHelper.checkGlError("glViewport");
          }
          
          void end()
          {
              GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
          }
        
    • 美颜
      通过shader实现实时的美颜效果,美白,磨皮
      (美颜效果的原理可参考)
      http://meituplus.com/?p=101
      (更多的实时shader处理可参考)
      https://github.com/wuhaoyu1990/MagicCamera

    相关文章

      网友评论

          本文标题:直播技术笔记(1)——camera的纹理

          本文链接:https://www.haomeiwen.com/subject/bizwsttx.html