频道栏目
首页 > 资讯 > IOS > 正文

IOS:Camera的特性分析与使用3_OPENGL特效

15-07-17        来源:[db:作者]  
收藏   我要投稿

本来想用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 // 创建并初始化这个工程对象

对应代码如下:

 

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

+ (Class)layerClass

{

return [CAEAGLLayer class];

}

- (BOOL)initializeBuffers

{

// 设置oglContext为当前上下文

if ([EAGLContext currentContext] != oglContext) {

if ([EAGLContext setCurrentContext:oglContext]) {

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

}

}

 

BOOL success = YES;

// 设置图层的frame和bounds

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,

};

// 创建并初始化这个工程对象

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.0f, 1.0f,

1.0f, 1.0f

};

等比例拉伸

 

GLfloat squareVertices1[8] = {

-0.5625f, -1.0f,

0.5625f, -1.0f,

-0.5625f, 1.0f,

0.5625f, 1.0f

};

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

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

 

相关TAG标签
上一篇:apk签名命令总结
下一篇:Windows App开发之应用布局与基本导航
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站