欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

mac下用OpenGL进行视频渲染

程序员文章站 2022-03-18 17:02:04
...

跨平台的视频渲染的解决方案可用SDL,OpenGL等进行渲染,下面介绍在MACOS下OpenGL的渲染方式:

#ifndef MacRender_h
#define MacRender_h
#define GL_SILENCE_DEPRECATION
#include <OpenGL/gl.h>
#import <Cocoa/Cocoa.h>

 class MacRenderGL
  {
  public:
      enum IMAGE_TYPE {
          IMAGE_TYPE_RGB = 1,
          IMAGE_TYPE_YUV = 2
      };
      explicit MacRenderGL(IMAGE_TYPE type = IMAGE_TYPE_YUV);
      ~MacRenderGL() override;
      
      bool init(HWND hwnd);
      
      virtual void loadYuv(const uint8_t* Y, const uint8_t* U, const uint8_t* V, int width, int height);
      virtual void loadRGB(const uint8_t *data, int width, int height);
      
      virtual void setDisplayMode(RENDER_MODE mode);
      virtual void setMirror(bool useMirror);
      virtual void setIsLocalRender(bool bLocal);
      
      void clean() override;
      
  private:
      IMAGE_TYPE   imageType_;
      RENDER_MODE  renderMode_;
      bool bInit_;
      uint8_t *buffer_;
      GLuint texture_;
      size_t width_,height_,bufffer_size_;
      int windowWidth,windowHeight;
      NSOpenGLContext *context_;
      NSView * nsview_;
      void ResizeViewport(size_t width,size_t height);
      void ResizeVideo(size_t width,size_t height);
      void Yuv420toRgb32(const uint8_t* srcY, const uint8_t* srcU,
                       const uint8_t* srcV,int width,int height,uint8_t* RGB32);
      
      bool useMirror_;
  };


MacRenderGL::MacRenderGL(IMAGE_TYPE type):imageType_(type),renderMode_(RENDER_MODE_NORM),
    bInit_(false),buffer_(nullptr),texture_(0),width_(0),height_(0),bufffer_size_(0),windowWidth(0),
    windowHeight(0),nsview_(nullptr),useMirror_(true){
        
    }
    MacRenderGL::~MacRenderGL() {
        if(!bInit_)
            return;
        bInit_ = false;
        
        delete [] buffer_;
        buffer_ = nullptr;
        
        //glDeleteTextures(1,&texture_);
    }
    
    bool MacRenderGL::init(HWND hwnd) {
        
        if(bInit_)
            return false;
        
        nsview_ = (__bridge NSView *) hwnd;
        
        NSRect Rect = nsview_.frame;//[nsview_ visibleRect];
        windowWidth = Rect.size.width;
        windowHeight = Rect.size.height;
        
        NSRect viewFrame = NSMakeRect(0, 0, Rect.size.width, Rect.size.height);
        NSOpenGLView *view = [[NSOpenGLView alloc] initWithFrame:viewFrame pixelFormat:nil];
        context_ = [view openGLContext];
        
        [nsview_ addSubview:view];
        [context_ makeCurrentContext];
        
        glGenTextures(1, &texture_);
        ResizeViewport(windowWidth,windowHeight);
        
        bInit_ = true;
        return true;
    }
    
    void MacRenderGL::loadYuv(const uint8_t* Y, const uint8_t* U, const uint8_t* V, int width, int height) {
        [context_ makeCurrentContext];
        if(width_ != width || height != height_) {
            ResizeVideo(width,height);
        }
        
        Yuv420toRgb32(Y, U, V, width, height, buffer_);
        
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, texture_);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_RGBA,GL_UNSIGNED_INT_8_8_8_8,buffer_);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        glBegin(GL_QUADS);
        {
            
            //NSRect Rect = [nsview_ visibleRect];
            if(windowWidth != nsview_.frame.size.width || windowHeight != nsview_.frame.size.height) {
                ResizeViewport(nsview_.frame.size.width,nsview_.frame.size.height);
            }
            
            float x = 0,x2 = windowWidth,y = 0,y2 = windowHeight;
            
            if (width > height)
            {
                //等比例缩放
                float aspect = (float)windowWidth/ windowHeight;
                
                if (aspect > 1.0f)
                {
                    y = 0;
                    y2 = y + windowHeight;
                    
                    float NewWidth = (float)width * windowHeight / height;
                    
                    x = (windowWidth - NewWidth) / 2;
                    x2 = x + NewWidth;
                    
                    if (NewWidth > windowWidth)
                    {
                        x = 0;
                        x2 = windowWidth;
                        
                        float NewHeight = (float)height * windowWidth/ width;
                        
                        y = (windowHeight- NewHeight) / 2;
                        y2 = y + NewHeight;
                    }
                }
                else
                {
                    x = 0;
                    x2 = windowWidth;
                    
                    float NewHeight = (float)height * windowWidth / width;
                    
                    y = (windowHeight - NewHeight) / 2;
                    y2 = y + NewHeight;
                    
                    if (NewHeight > windowHeight)
                    {
                        y = 0;
                        y2 = y + windowHeight;
                        
                        float NewWidth = (float)width * windowHeight / height;
                        
                        x = (windowWidth - NewWidth) / 2;
                        x2 = x + NewWidth;
                    }
                }
            }
            else
            {
                int w = (float)windowHeight * width / height;
                
                int RenderSide = 1;
                
                if (w < windowWidth)
                {
                    if (RenderSide == 0) //居左
                    {
                        x = 0;
                        x2 = x + w;
                    }
                    else if (RenderSide == 1) //居中
                    {
                        x = (windowWidth- w) / 2;
                        x2 = x + w;
                    }
                    else  //居右
                    {
                        x = windowWidth - w;
                        x2 = x + w;
                    }
                }
                else
                {
                    x = 0;
                    x2 = windowWidth;
                    
                    float NewHeight = (float)height * windowWidth/ width;
                    
                    y = (windowHeight- NewHeight) / 2;
                    y2 = y + NewHeight;
                    
                    if (NewHeight > windowHeight)
                    {
                        y = 0;
                        y2 = y + windowHeight;
                        
                        float NewWidth = (float)width * windowHeight / height;
                        
                        x = (windowWidth- NewWidth) / 2;
                        x2 = x + NewWidth;
                    }
                }
                
            }
            
            if(renderMode_ == RENDER_MODE_HIDDEN) {
                //clip
                x = y = 0;
                if(x2 == windowWidth) {
                    
                    float newWidth = (float)width * windowHeight / height;
                    
                    x2 = newWidth;
                    y2 = windowWidth;
                    
                } else if(y2 == windowHeight) {
                    
                    float newHeight = (float)height * windowWidth/ width;
                    
                    x2 = windowWidth;
                    y2 = newHeight;
                }
                
            }
            
            if(!useMirror_) {
                
                glTexCoord2f(0.0f, 0.0f);
                glVertex3f(x / windowWidth, y / windowHeight, 0.0f);
                
                glTexCoord2f(0.0f, 1.0f);
                glVertex3f(x / windowWidth, y2 / windowHeight, 0.0f);
                
                glTexCoord2f(1.0f, 1.0f);
                glVertex3f(x2 / windowWidth, y2 / windowHeight, 0.0f);
                
                glTexCoord2f(1.0f, 0.0f);
                glVertex3f(x2 / windowWidth, y / windowHeight, 0.0f);
                
            } else {
                
                glTexCoord2f(0.0f, 0.0f);
                glVertex3f(x2 / windowWidth, y / windowHeight, 0.0f);
                
                glTexCoord2f(0.0f, 1.0f);
                glVertex3f(x2 / windowWidth, y2 / windowHeight, 0.0f);
                
                glTexCoord2f(1.0f, 1.0f);
                glVertex3f(x / windowWidth, y2 / windowHeight, 0.0f);
                
                glTexCoord2f(1.0f, 0.0f);
                glVertex3f(x / windowWidth, y / windowHeight, 0.0f);
            }
            
        }
        glEnd();
        
        glBindTexture(GL_TEXTURE_2D, 0);
        glFlush();
        
    }
    void MacRenderGL::loadRGB(const uint8_t *data, int width, int height) {
        
    }
    
    void MacRenderGL::setDisplayMode(RENDER_MODE mode) {
        renderMode_ = mode;
    }
    
    void MacRenderGL::setMirror(bool useMirror) {
        useMirror_ = useMirror;
    }
    
	void MacRenderGL::setIsLocalRender(bool bLocal)
	{
		if(!bLocal) {
			useMirror_ = false;
		}
	}


    void MacRenderGL::clean() {
        
    }
    
    void MacRenderGL::ResizeViewport(size_t width,size_t height) {
        
        glViewport(0, 0, width, height);
        
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glOrtho(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f);
        glMatrixMode(GL_MODELVIEW);
        windowHeight = height;
        windowWidth = width;
    }
    
    void MacRenderGL::ResizeVideo(size_t width,size_t height) {
        if(bInit_) {
            
            width_ = width;
            height_ = height;
            
            bufffer_size_ = width_ * height_ * 4;
            
            if(buffer_)
                delete [] buffer_;
            
            buffer_ = new uint8_t[bufffer_size_];
            
            memset(buffer_,0,bufffer_size_);
            
            glBindTexture(GL_TEXTURE_2D, texture_);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL,0);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width_, height_, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, buffer_);
 
        }
    }
    
    void MacRenderGL::Yuv420toRgb32(const uint8_t* srcY, const uint8_t* srcU,
                             const uint8_t* srcV,int width,int height,
                                  uint8_t* RGB32) {
        
        int Y, U, V, R, G, B;
        int i, j;
        int cwidth = width >> 1;
        
        for (i = 0; i < height; ++i)
        {
            for (j = 0; j < width; ++j)
            {
                Y = *(srcY + i * width + j);
                U = *(srcU + (i >> 1) * cwidth + (j >> 1));
                V = *(srcV + (i >> 1) * cwidth + (j >> 1));
                R = Y + 1.403 * (V - 128);
                G = Y - 0.344 * (U - 128) - 0.714 * (V - 128);
                B = Y + 1.772 * (U - 128);
                
                if (R <= 0 || R >= 255)
                {
                    R = (R <= 0) ? 0 : 255;
                }
                if (G <= 0 || G >= 255)
                {
                    G = (G <= 0) ? 0 : 255;
                }
                if (B <= 0 || B >= 255)
                {
                    B = (B <= 0) ? 0 : 255;
                }
                
                *(RGB32 + (i* width + j) * 4) = 255;
                *(RGB32 + (i * width + j) * 4 + 1) = B;
                *(RGB32 + (i * width + j) * 4 + 2) = G;
                *(RGB32 + (i* width + j) * 4 + 3) = R;
                
                
            }
        }
    }

#endif /* MacRender_h */
相关标签: 渲染