zoukankan      html  css  js  c++  java
  • IOS:Camera的特性分析与使用3_OPENGL特效

    本来想用2个篇幅结束Camera软件部分的介绍,后来发现,很重要的一点OpenGL还没介绍,所以又添加了这一篇。

    这篇主要描写叙述一下几个方面的内容:

    (1)录像界面OPENGL展示

    (2)录像实时特效处理

    (3)视频等比例缩放、旋转 如:等比例、16:9 4:3 1:1等

    这个部分我思来想去缺失不太好讲,设计到的知识太多,尤其是OpenGL的一些专业知识,通过一篇博客普及OpenGL的知识显然不科学,所以仅仅能了解一个流程。至于里面究竟是怎么回事,请大家找本OpenGL的书看看,我想等这几个博客完工之后,也写几篇OpenGL的博客呵呵。

    我们的整个流程是。首先从AVCaptureSession拿到视频拍摄时候的数据流,然后特效处理(特效这块能够參考还有一个Image&Animation专栏),然后初始化OpenGL開始进行纹理贴图。

    (1)怎样拿到视频数据流?

    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

    {

        if ( videooutput == captureOutput ) {

            OSStatus err = CMBufferQueueEnqueue(previewBufferQueue, sampleBuffer);

            if ( !err ) {

                dispatch_async(dispatch_get_main_queue(), ^{

                    CMSampleBufferRef sbuf = (CMSampleBufferRef)CMBufferQueueDequeueAndRetain(previewBufferQueue);

                    if (sbuf) {

                        CVImageBufferRef pixBuf = CMSampleBufferGetImageBuffer(sbuf);

                        if (effectflag) {

                            特效处理

                        }

                            OpenGL纹理展示

                        CFRelease(sbuf);

                    }

                });

            }

        }

    }

    AVCaptureSession初始化完毕之后我们能够设置一个回调方法,在这个回调方法中,能够非常方便的拿到我们须要处理的图像数据。

    (2)怎样进行图片的特效处理

    这又是一个很复杂的内容。我也专门为此写了另外一篇博客:

    这中间牵扯到各种图像处理算法,neon、汇编优化,ARM内部寄存器的使用等等。

    这里我们仅仅说怎样吧ImageBuffer转化为RGBA像素:

    unsigned char *pixel = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBuffer);

    这里pixel存放的就是图片的RGBA像素值。

    (3)OpenGL纹理贴图

    3.1//在使用Opengles的时候须要重构CAEAGLLayer图层

    + (Class)layerClass

    {

        return [CAEAGLLayer class];

    }

    3.2//      设置CAEAGLLayer

            CAEAGLLayer*eaglLayer = (CAEAGLLayer *)self.layer;

    3.3设置CAEAGLLayer层的属性RGBA8

    3.4//      使用opengl2.0 创建图像绘制上下文

            oglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    3.5//  设置oglContext为当前上下文

    3.2 //   glEnable(GL_DEPTH_TEST)用来开启更新深度缓冲区的功能

    3.3 //  创建帧缓冲区

    3.4 //  讲帧缓冲区绑定在画图管线上

    3.5 //  创建画图缓冲区

    3.6 //  讲画图缓冲区绑定在管线上

    3.7 //  为画图缓冲区(或者叫渲染缓冲区分配空间)

    3.8 //  获取当前画图缓冲区(渲染缓冲区的)宽和高

    3.9 //  讲渲染缓冲区与帧缓冲区绑定在一起

    3.10 //  检查当前帧缓冲区的状态是否有效

    3.11 //  创建一个opengl的纹理对象

    3.12 //  载入定点和片段着色器

    3.13 //  创建并初始化这个project对象

    相应代码例如以下:

    //在使用Opengles的时候须要重构CAEAGLLayer图层

    + (Class)layerClass

    {

        return [CAEAGLLayer class];

    }

    - (BOOL)initializeBuffers

    {

        //  设置oglContext为当前上下文

        if ([EAGLContext currentContext] != oglContext) {

            if ([EAGLContext setCurrentContext:oglContext]) {

                NSLog(@"setCurrentContext error... ...");

            }

        }

        

    BOOL success = YES;

        //  设置图层的framebounds

        CGRect rtFullscreem = [[UIScreen mainScreen] bounds];

        CGRect rtCurrframe = self.layer.frame;

        CGRect rtCurrbounds = self.layer.bounds;

        self.layer.frame = rtFullscreem;

        self.layer.bounds = rtFullscreem;

        

    NSLog(@"size{%f %f %f %f}", rtFullscreem.origin.x, rtFullscreem.origin.x, rtFullscreem.size.width, rtFullscreem.size.height);

        

        //    glEnable(GL_DEPTH_TEST) 用来开启更新深度缓冲区的功能,也就是。假设通过比較后深度值发生变化了,会进行更新深度缓冲区的操作。启动它,OpenGL就能够跟踪再Z轴上的像素,这样,它仅仅会再那个像素前方没有东西时。才会绘画这个像素。

        //  一般这个功能开启之后绘制3D效果比較好

    glDisable(GL_DEPTH_TEST);

        //  创建帧缓冲区

        glGenFramebuffers(1, &frameBufferHandle);

        //  讲帧缓冲区绑定在画图管线上

        glBindFramebuffer(GL_FRAMEBUFFER, frameBufferHandle);

        //  创建画图缓冲区

        glGenRenderbuffers(1, &colorBufferHandle);

        //  讲画图缓冲区绑定在管线上

        glBindRenderbuffer(GL_RENDERBUFFER, colorBufferHandle);

        

        //  为画图缓冲区(或者叫渲染缓冲区分配空间)

        [oglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer];

        

        //  获取当前画图缓冲区(渲染缓冲区的)宽和高

    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &renderBufferWidth);

        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &renderBufferHeight);

        //  讲渲染缓冲区与帧缓冲区绑定在一起

        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);

        //  检查当前帧缓冲区的状态是否有效

    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {

            NSLog(@"Failure with framebuffer generation 0x%X", glCheckFramebufferStatus(GL_FRAMEBUFFER));

    success = NO;

    }

        

        //  Create a new CVOpenGLESTexture cache

        //  创建一个opengl的纹理对象

    //  oglContext 中创建纹理对象

        CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, oglContext, NULL, &videoTextureCache);

        if (err) {

            NSLog(@"Error at CVOpenGLESTextureCacheCreate %d", err);

            success = NO;

        }

        

        // Load vertex and fragment shaders

        //  载入定点和片段着色器

        const GLchar *vertSrc = str_passThrough_v;//[self readFile:@"passThrough.vsh"];

        const GLchar *fragSrc = str_passThrough_f;//  [self readFile:@"passThrough.fsh"];

        

        // attributes

        GLint attribLocation[NUM_ATTRIBUTES] = {

            ATTRIB_VERTEX, ATTRIB_TEXTUREPOSITON,

        };

        GLchar *attribName[NUM_ATTRIBUTES] = {

            "position", "textureCoordinate",

        };

        //  创建并初始化这个project对象

        glueCreateProgram(vertSrc, fragSrc,

                          NUM_ATTRIBUTES, (const GLchar **)&attribName[0], attribLocation,

                          0, 0, 0, // we don't need to get uniform locations in this example

                          &passThroughProgram);

        

        if (!passThroughProgram)

            success = NO;

        

        self.layer.frame = rtCurrframe;

        self.layer.bounds = rtCurrbounds;

        return success;

    }

    最后我们再来看看怎样对所播放的视频屏幕进行等比例缩放,16:9等缩放

    这里我们首先须要设置一个属性:

    glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);

    textureVertices 是一个数组。用于进行纹理贴图时画面设置:

    全屏幕播放

    GLfloat squareVertices0[8] = {

            -1.0f, -1.0f,

            1.0f, -1.0f,

            -1.0f1.0f,

            1.0f1.0f

    };

    等比例拉伸

        GLfloat squareVertices1[8] = {

            -0.5625f, -1.0f,

            0.5625f, -1.0f,

            -0.5625f1.0f,

            0.5625f1.0f

    };

    这个数据是啥意思呢?看以下两个图


    屏幕拍摄为1920*1080,所以1080/1920=0.5625.注意拍摄时候 宽高倒置。

  • 相关阅读:
    react的50个面试题
    什么是宏队列跟微队列
    宏队列与微队列
    数组都有哪些方法
    vuex 跟 vue属性
    高阶组件
    如何创建视图簇(View cluster)-SE54/SM34
    ◆◆0如何从维护视图(Maintenace view)中取数据-[VIEW_GET_DATA]
    ◆◆0如何在SM30维护表时自动写入表字段的默认值-事件(EVENT)
    ◆◆0SAP Query 操作教程
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/6766977.html
Copyright © 2011-2022 走看看