你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> IOS:Camera的特性分析與使用3_OPENGL特效

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

編輯:IOS開發綜合

本來想用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.注意拍攝時候 寬高倒置。

 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved