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

來源:互聯網
上載者:User

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 // 建立並初始化這個工程對象

對應代碼如下:

 

//在使用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.注意拍攝時候 寬高倒置。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.