1/* 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#import "RTCNV12TextureCache.h" 12 13#import "base/RTCVideoFrame.h" 14#import "base/RTCVideoFrameBuffer.h" 15#import "components/video_frame_buffer/RTCCVPixelBuffer.h" 16 17@implementation RTCNV12TextureCache { 18 CVOpenGLESTextureCacheRef _textureCache; 19 CVOpenGLESTextureRef _yTextureRef; 20 CVOpenGLESTextureRef _uvTextureRef; 21} 22 23- (GLuint)yTexture { 24 return CVOpenGLESTextureGetName(_yTextureRef); 25} 26 27- (GLuint)uvTexture { 28 return CVOpenGLESTextureGetName(_uvTextureRef); 29} 30 31- (instancetype)initWithContext:(EAGLContext *)context { 32 if (self = [super init]) { 33 CVReturn ret = CVOpenGLESTextureCacheCreate( 34 kCFAllocatorDefault, NULL, 35#if COREVIDEO_USE_EAGLCONTEXT_CLASS_IN_API 36 context, 37#else 38 (__bridge void *)context, 39#endif 40 NULL, &_textureCache); 41 if (ret != kCVReturnSuccess) { 42 self = nil; 43 } 44 } 45 return self; 46} 47 48- (BOOL)loadTexture:(CVOpenGLESTextureRef *)textureOut 49 pixelBuffer:(CVPixelBufferRef)pixelBuffer 50 planeIndex:(int)planeIndex 51 pixelFormat:(GLenum)pixelFormat { 52 const int width = CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex); 53 const int height = CVPixelBufferGetHeightOfPlane(pixelBuffer, planeIndex); 54 55 if (*textureOut) { 56 CFRelease(*textureOut); 57 *textureOut = nil; 58 } 59 CVReturn ret = CVOpenGLESTextureCacheCreateTextureFromImage( 60 kCFAllocatorDefault, _textureCache, pixelBuffer, NULL, GL_TEXTURE_2D, pixelFormat, width, 61 height, pixelFormat, GL_UNSIGNED_BYTE, planeIndex, textureOut); 62 if (ret != kCVReturnSuccess) { 63 if (*textureOut) { 64 CFRelease(*textureOut); 65 *textureOut = nil; 66 } 67 return NO; 68 } 69 NSAssert(CVOpenGLESTextureGetTarget(*textureOut) == GL_TEXTURE_2D, 70 @"Unexpected GLES texture target"); 71 glBindTexture(GL_TEXTURE_2D, CVOpenGLESTextureGetName(*textureOut)); 72 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 75 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 76 return YES; 77} 78 79- (BOOL)uploadFrameToTextures:(RTC_OBJC_TYPE(RTCVideoFrame) *)frame { 80 NSAssert([frame.buffer isKindOfClass:[RTC_OBJC_TYPE(RTCCVPixelBuffer) class]], 81 @"frame must be CVPixelBuffer backed"); 82 RTC_OBJC_TYPE(RTCCVPixelBuffer) *rtcPixelBuffer = (RTC_OBJC_TYPE(RTCCVPixelBuffer) *)frame.buffer; 83 CVPixelBufferRef pixelBuffer = rtcPixelBuffer.pixelBuffer; 84 return [self loadTexture:&_yTextureRef 85 pixelBuffer:pixelBuffer 86 planeIndex:0 87 pixelFormat:GL_LUMINANCE] && 88 [self loadTexture:&_uvTextureRef 89 pixelBuffer:pixelBuffer 90 planeIndex:1 91 pixelFormat:GL_LUMINANCE_ALPHA]; 92} 93 94- (void)releaseTextures { 95 if (_uvTextureRef) { 96 CFRelease(_uvTextureRef); 97 _uvTextureRef = nil; 98 } 99 if (_yTextureRef) { 100 CFRelease(_yTextureRef); 101 _yTextureRef = nil; 102 } 103} 104 105- (void)dealloc { 106 [self releaseTextures]; 107 if (_textureCache) { 108 CFRelease(_textureCache); 109 _textureCache = nil; 110 } 111} 112 113@end 114