渲染CVPixelBufferRef視頻幀顯示
流程
1歹苦、構(gòu)建OPenGL渲染環(huán)境
2、CVPixelBufferRef生成紋理Texture
2立倍、紋理顯示
構(gòu)建OPenGL渲染環(huán)境
1澜薄、創(chuàng)建EAGLContext上下文
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.context];
2、構(gòu)建設(shè)置CAEAGLLayer屬性
_eaglLayer = (CAEAGLLayer*) self.layer;
_eaglLayer.opaque = YES;
_eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
_eaglLayer.contentsScale = [[UIScreen mainScreen] scale];
3叉钥、綁定紋理緩沖區(qū)和幀緩沖區(qū)罢缸,并與CAEAGLLayer聯(lián)系
//1.渲染緩存區(qū), 幀緩存區(qū)對象
GLuint renderBuffer;
GLuint frameBuffer;
//2.獲取渲染緩存區(qū)名稱, 綁定渲染緩存區(qū)以及將渲染緩存區(qū)與 layer建立聯(lián)系
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
//3.獲取幀緩存區(qū)名稱, 綁定幀緩存區(qū)以及渲染緩存區(qū)附著到幀緩存區(qū)上
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer);
4、初始化紋理著色器和片元著色器投队,生成Program
NSString *fsh = [[self.filterBundle resourcePath] stringByAppendingFormat:@"/%@/%@.fsh",name,name];
NSString *vsh = [[self.filterBundle resourcePath] stringByAppendingFormat:@"/%@/%@.vsh",name,name];
GLuint program = [SKGLUtils compileShaders:vsh shaderFragment:fsh isFilePath:YES];
5枫疆、上傳圖片數(shù)據(jù),生成紋理顯示
glUseProgram(rgbaProgram);
glActiveTexture(GL_TEXTURE0);
CVOpenGLESTextureCacheCreateTextureFromImage(……)
……
glClearColor(0.1f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
CVPixelBufferRef生成紋理Texture
CVPixelBufferRef是一種像素圖片類型敷鸦,是一個(gè)C對象息楔,不是一個(gè)類寝贡,對它的操作都是C函數(shù)進(jìn)行操作。有著多種不同的數(shù)據(jù)格式值依,通過CVPixelBufferGetPixelFormatType(pixelBuffer)
來獲取圃泡,通常使用RGBA和YUV420比較常見。 由于是C對象愿险,它不受ARC去管理颇蜡,創(chuàng)建出一個(gè)對象,需要手動去釋放拯啦。(Swift語言可以不需要手動澡匪,這個(gè)或許和Swift沒有暴露指針操作有關(guān)系)。其中包含著視頻幀數(shù)據(jù)褒链,也可以理解為圖片數(shù)據(jù)唁情。
通過CVPixelBufferGetBaseAddressOfPlane可以得到每個(gè)平面的數(shù)據(jù)指針(圖片數(shù)據(jù))。在得到 Address之前需要調(diào)用CVPixelBufferLockBaseAddress甫匹,進(jìn)行l(wèi)ock下來實(shí)現(xiàn)地址映射甸鸟,同時(shí)lock也保證了沒有讀寫沖突。
將 CVPixelBufferRef 生成紋理兵迅,有兩種方法:
1抢韭、取出CVPixelBufferRef的圖片數(shù)據(jù),通過glTexImage2D(……)
進(jìn)行上傳紋理恍箭,生成紋理ID
2刻恭、使用系統(tǒng)C函數(shù)方法CVOpenGLESTextureCacheCreateTextureFromImage(……)
進(jìn)行上傳紋理
CVReturn err;
CVOpenGLESTextureRef luminanceTextureRef = NULL;
CVOpenGLESTextureRef chrominanceTextureRef = NULL;
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
videoTextureCache,
pixelBuffer,
NULL,
GL_TEXTURE_2D,
GL_RED_EXT,
frameWidth,
frameHeight,
GL_RED_EXT,
GL_UNSIGNED_BYTE,
0,
&luminanceTextureRef);
if (err) {
NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}
顯示紋理
將生成的紋理進(jìn)行啟用和綁定
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, CVOpenGLESTextureGetName(luminanceTextureRef));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
最后進(jìn)行顯示紋理
glClearColor(0.1f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
注意事項(xiàng)
1、生成的紋理在使用結(jié)束時(shí)候進(jìn)行釋放CFRelease(luminanceTextureRef);
2扯夭、使用CVOpenGLESTextureCacheCreateTextureFromImage()
的videoTextureCache
對象只需要創(chuàng)建一次鳍贾,不需要多此創(chuàng)建,不用時(shí)刪除
3交洗、渲染或者釋放時(shí)候骑科,注意在渲染線程中做操作。否則可能線程不同步問題构拳,造成野指針
4咆爽、APP在退出到后臺時(shí)候呢岗,應(yīng)該停止渲染OPenGL的操作物延。iOS不支持在后臺做OPenGL的執(zhí)行掂林,會有野指針閃退問題