Obj-C SDK Cleanup

This CL separates the files under sdk/objc into logical directories, replacing
the previous file layout under Framework/.

A long term goal is to have some system set up to generate the files under
sdk/objc/api (the PeerConnection API wrappers) from the C++ code. In the shorter
term the goal is to abstract out shared concepts from these classes in order to
make them as uniform as possible.

The separation into base/, components/, and helpers/ are to differentiate between
the base layer's common protocols, various utilities and the actual platform
specific components.

The old directory layout that resembled a framework's internal layout is not
necessary, since it is generated by the framework target when building it.

Bug: webrtc:9627
Change-Id: Ib084fd83f050ae980649ca99e841f4fb0580bd8f
Reviewed-on: https://webrtc-review.googlesource.com/94142
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Commit-Queue: Anders Carlsson <andersc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24493}
diff --git a/sdk/objc/components/renderer/opengl/RTCI420TextureCache.mm b/sdk/objc/components/renderer/opengl/RTCI420TextureCache.mm
new file mode 100644
index 0000000..865f3a2
--- /dev/null
+++ b/sdk/objc/components/renderer/opengl/RTCI420TextureCache.mm
@@ -0,0 +1,157 @@
+/*
+ *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#import "RTCI420TextureCache.h"
+
+#if TARGET_OS_IPHONE
+#import <OpenGLES/ES3/gl.h>
+#else
+#import <OpenGL/gl3.h>
+#endif
+
+#import "base/RTCI420Buffer.h"
+#import "base/RTCVideoFrameBuffer.h"
+
+#include <vector>
+
+// Two sets of 3 textures are used here, one for each of the Y, U and V planes. Having two sets
+// alleviates CPU blockage in the event that the GPU is asked to render to a texture that is already
+// in use.
+static const GLsizei kNumTextureSets = 2;
+static const GLsizei kNumTexturesPerSet = 3;
+static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets;
+
+@implementation RTCI420TextureCache {
+  BOOL _hasUnpackRowLength;
+  GLint _currentTextureSet;
+  // Handles for OpenGL constructs.
+  GLuint _textures[kNumTextures];
+  // Used to create a non-padded plane for GPU upload when we receive padded frames.
+  std::vector<uint8_t> _planeBuffer;
+}
+
+- (GLuint)yTexture {
+  return _textures[_currentTextureSet * kNumTexturesPerSet];
+}
+
+- (GLuint)uTexture {
+  return _textures[_currentTextureSet * kNumTexturesPerSet + 1];
+}
+
+- (GLuint)vTexture {
+  return _textures[_currentTextureSet * kNumTexturesPerSet + 2];
+}
+
+- (instancetype)initWithContext:(GlContextType *)context {
+  if (self = [super init]) {
+#if TARGET_OS_IPHONE
+    _hasUnpackRowLength = (context.API == kEAGLRenderingAPIOpenGLES3);
+#else
+    _hasUnpackRowLength = YES;
+#endif
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    [self setupTextures];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  glDeleteTextures(kNumTextures, _textures);
+}
+
+- (void)setupTextures {
+  glGenTextures(kNumTextures, _textures);
+  // Set parameters for each of the textures we created.
+  for (GLsizei i = 0; i < kNumTextures; i++) {
+    glBindTexture(GL_TEXTURE_2D, _textures[i]);
+    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);
+  }
+}
+
+- (void)uploadPlane:(const uint8_t *)plane
+            texture:(GLuint)texture
+              width:(size_t)width
+             height:(size_t)height
+             stride:(int32_t)stride {
+  glBindTexture(GL_TEXTURE_2D, texture);
+
+  const uint8_t *uploadPlane = plane;
+  if ((size_t)stride != width) {
+   if (_hasUnpackRowLength) {
+      // GLES3 allows us to specify stride.
+      glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+      glTexImage2D(GL_TEXTURE_2D,
+                   0,
+                   RTC_PIXEL_FORMAT,
+                   static_cast<GLsizei>(width),
+                   static_cast<GLsizei>(height),
+                   0,
+                   RTC_PIXEL_FORMAT,
+                   GL_UNSIGNED_BYTE,
+                   uploadPlane);
+      glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+      return;
+    } else {
+      // Make an unpadded copy and upload that instead. Quick profiling showed
+      // that this is faster than uploading row by row using glTexSubImage2D.
+      uint8_t *unpaddedPlane = _planeBuffer.data();
+      for (size_t y = 0; y < height; ++y) {
+        memcpy(unpaddedPlane + y * width, plane + y * stride, width);
+      }
+      uploadPlane = unpaddedPlane;
+    }
+  }
+  glTexImage2D(GL_TEXTURE_2D,
+               0,
+               RTC_PIXEL_FORMAT,
+               static_cast<GLsizei>(width),
+               static_cast<GLsizei>(height),
+               0,
+               RTC_PIXEL_FORMAT,
+               GL_UNSIGNED_BYTE,
+               uploadPlane);
+}
+
+- (void)uploadFrameToTextures:(RTCVideoFrame *)frame {
+  _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
+
+  id<RTCI420Buffer> buffer = [frame.buffer toI420];
+
+  const int chromaWidth = buffer.chromaWidth;
+  const int chromaHeight = buffer.chromaHeight;
+  if (buffer.strideY != frame.width || buffer.strideU != chromaWidth ||
+      buffer.strideV != chromaWidth) {
+    _planeBuffer.resize(buffer.width * buffer.height);
+  }
+
+  [self uploadPlane:buffer.dataY
+            texture:self.yTexture
+              width:buffer.width
+             height:buffer.height
+             stride:buffer.strideY];
+
+  [self uploadPlane:buffer.dataU
+            texture:self.uTexture
+              width:chromaWidth
+             height:chromaHeight
+             stride:buffer.strideU];
+
+  [self uploadPlane:buffer.dataV
+            texture:self.vTexture
+              width:chromaWidth
+             height:chromaHeight
+             stride:buffer.strideV];
+}
+
+@end