| Index: webrtc/sdk/objc/Framework/Classes/RTCNativeNV12Shader.mm
 | 
| diff --git a/webrtc/sdk/objc/Framework/Classes/RTCNativeNV12Shader.mm b/webrtc/sdk/objc/Framework/Classes/RTCNativeNV12Shader.mm
 | 
| index 0e221bfd112606090915f69862611e8a7223f50d..c0769c05cda4f3e169bee3a29cbfd8c28ddc299f 100644
 | 
| --- a/webrtc/sdk/objc/Framework/Classes/RTCNativeNV12Shader.mm
 | 
| +++ b/webrtc/sdk/objc/Framework/Classes/RTCNativeNV12Shader.mm
 | 
| @@ -10,12 +10,7 @@
 | 
|  
 | 
|  #import "RTCShader.h"
 | 
|  
 | 
| -// Native CVPixelBufferRef rendering is only supported on iPhone because it
 | 
| -// depends on CVOpenGLESTextureCacheCreate.
 | 
| -#if TARGET_OS_IPHONE
 | 
| -
 | 
| -#import <CoreVideo/CVOpenGLESTextureCache.h>
 | 
| -
 | 
| +#import "RTCNV12TextureCache.h"
 | 
|  #import "RTCShader+Private.h"
 | 
|  #import "WebRTC/RTCLogging.h"
 | 
|  #import "WebRTC/RTCVideoFrame.h"
 | 
| @@ -47,7 +42,7 @@ static const char kNV12FragmentShaderSource[] =
 | 
|    GLuint _nv12Program;
 | 
|    GLint _ySampler;
 | 
|    GLint _uvSampler;
 | 
| -  CVOpenGLESTextureCacheRef _textureCache;
 | 
| +  RTCNV12TextureCache *_textureCache;
 | 
|    // Store current rotation and only upload new vertex data when rotation
 | 
|    // changes.
 | 
|    rtc::Optional<RTCVideoRotation> _currentRotation;
 | 
| @@ -55,7 +50,8 @@ static const char kNV12FragmentShaderSource[] =
 | 
|  
 | 
|  - (instancetype)initWithContext:(GlContextType *)context {
 | 
|    if (self = [super init]) {
 | 
| -    if (![self setupNV12Program] || ![self setupTextureCacheWithContext:context] ||
 | 
| +    _textureCache = [[RTCNV12TextureCache alloc] initWithContext:context];
 | 
| +    if (!_textureCache || ![self setupNV12Program] ||
 | 
|          !RTCSetupVerticesForProgram(_nv12Program, &_vertexBuffer, nullptr)) {
 | 
|        RTCLog(@"Failed to initialize RTCNativeNV12Shader.");
 | 
|        self = nil;
 | 
| @@ -67,10 +63,6 @@ static const char kNV12FragmentShaderSource[] =
 | 
|  - (void)dealloc {
 | 
|    glDeleteProgram(_nv12Program);
 | 
|    glDeleteBuffers(1, &_vertexBuffer);
 | 
| -  if (_textureCache) {
 | 
| -    CFRelease(_textureCache);
 | 
| -    _textureCache = nullptr;
 | 
| -  }
 | 
|  }
 | 
|  
 | 
|  - (BOOL)setupNV12Program {
 | 
| @@ -84,75 +76,21 @@ static const char kNV12FragmentShaderSource[] =
 | 
|    return (_ySampler >= 0 && _uvSampler >= 0);
 | 
|  }
 | 
|  
 | 
| -- (BOOL)setupTextureCacheWithContext:(GlContextType *)context {
 | 
| -  CVReturn ret = CVOpenGLESTextureCacheCreate(
 | 
| -      kCFAllocatorDefault, NULL,
 | 
| -#if COREVIDEO_USE_EAGLCONTEXT_CLASS_IN_API
 | 
| -      context,
 | 
| -#else
 | 
| -      (__bridge void *)context,
 | 
| -#endif
 | 
| -      NULL, &_textureCache);
 | 
| -  return ret == kCVReturnSuccess;
 | 
| -}
 | 
| -
 | 
|  - (BOOL)drawFrame:(RTCVideoFrame *)frame {
 | 
| -  CVPixelBufferRef pixelBuffer = frame.nativeHandle;
 | 
| -  RTC_CHECK(pixelBuffer);
 | 
|    glUseProgram(_nv12Program);
 | 
| -  const OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer);
 | 
| -  RTC_CHECK(pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ||
 | 
| -            pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
 | 
| -      << "Unsupported native pixel format: " << pixelFormat;
 | 
| +  if (![_textureCache uploadFrameToTextures:frame]) {
 | 
| +    return NO;
 | 
| +  }
 | 
|  
 | 
|    // Y-plane.
 | 
| -  const int lumaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
 | 
| -  const int lumaHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
 | 
| -
 | 
| -  CVOpenGLESTextureRef lumaTexture = nullptr;
 | 
|    glActiveTexture(GL_TEXTURE0);
 | 
|    glUniform1i(_ySampler, 0);
 | 
| -  CVReturn ret = CVOpenGLESTextureCacheCreateTextureFromImage(
 | 
| -      kCFAllocatorDefault, _textureCache, pixelBuffer, NULL, GL_TEXTURE_2D,
 | 
| -      RTC_PIXEL_FORMAT, lumaWidth, lumaHeight, RTC_PIXEL_FORMAT,
 | 
| -      GL_UNSIGNED_BYTE, 0, &lumaTexture);
 | 
| -  if (ret != kCVReturnSuccess) {
 | 
| -    CFRelease(lumaTexture);
 | 
| -    return NO;
 | 
| -  }
 | 
| -
 | 
| -  RTC_CHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
 | 
| -               CVOpenGLESTextureGetTarget(lumaTexture));
 | 
| -  glBindTexture(GL_TEXTURE_2D, CVOpenGLESTextureGetName(lumaTexture));
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
| +  glBindTexture(GL_TEXTURE_2D, _textureCache.yTexture);
 | 
|  
 | 
|    // UV-plane.
 | 
| -  const int chromaWidth = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
 | 
| -  const int chromeHeight = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
 | 
| -
 | 
| -  CVOpenGLESTextureRef chromaTexture = nullptr;
 | 
|    glActiveTexture(GL_TEXTURE1);
 | 
|    glUniform1i(_uvSampler, 1);
 | 
| -  ret = CVOpenGLESTextureCacheCreateTextureFromImage(
 | 
| -      kCFAllocatorDefault, _textureCache, pixelBuffer, NULL, GL_TEXTURE_2D,
 | 
| -      GL_LUMINANCE_ALPHA, chromaWidth, chromeHeight, GL_LUMINANCE_ALPHA,
 | 
| -      GL_UNSIGNED_BYTE, 1, &chromaTexture);
 | 
| -  if (ret != kCVReturnSuccess) {
 | 
| -    CFRelease(chromaTexture);
 | 
| -    CFRelease(lumaTexture);
 | 
| -    return NO;
 | 
| -  }
 | 
| -
 | 
| -  RTC_CHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
 | 
| -               CVOpenGLESTextureGetTarget(chromaTexture));
 | 
| -  glBindTexture(GL_TEXTURE_2D, CVOpenGLESTextureGetName(chromaTexture));
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
| +  glBindTexture(GL_TEXTURE_2D, _textureCache.uvTexture);
 | 
|  
 | 
|    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
 | 
|    if (!_currentRotation || frame.rotation != *_currentRotation) {
 | 
| @@ -161,11 +99,9 @@ static const char kNV12FragmentShaderSource[] =
 | 
|    }
 | 
|    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 | 
|  
 | 
| -  CFRelease(chromaTexture);
 | 
| -  CFRelease(lumaTexture);
 | 
| +  [_textureCache releaseTextures];
 | 
|  
 | 
|    return YES;
 | 
|  }
 | 
|  
 | 
|  @end
 | 
| -#endif  // TARGET_OS_IPHONE
 | 
| 
 |