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

按: 最近做了一个直播的预研项目, 因此记录下直播的技术的实现,在这过程中一些问题解决的思路,以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的纹理)