Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(305)

Side by Side Diff: webrtc/sdk/objc/Framework/Classes/RTCI420TextureCache.mm

Issue 2842453002: ObjC: Split out I420 texture uploading into separate class (Closed)
Patch Set: Make uploadFrameToTextures return void Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2016 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #import "RTCShader.h" 11 #import "RTCI420TextureCache.h"
12
13 #import "RTCShader+Private.h"
12 14
13 #include <vector> 15 #include <vector>
14 16
15 #import "RTCShader+Private.h" 17 // Two sets of 3 textures are used here, one for each of the Y, U and V planes. Having two sets
16 #import "WebRTC/RTCLogging.h" 18 // alleviates CPU blockage in the event that the GPU is asked to render to a tex ture that is already
17 #import "WebRTC/RTCVideoFrame.h" 19 // in use.
18
19 #include "webrtc/base/optional.h"
20
21 // |kNumTextures| must not exceed 8, which is the limit in OpenGLES2. Two sets
22 // of 3 textures are used here, one for each of the Y, U and V planes. Having
23 // two sets alleviates CPU blockage in the event that the GPU is asked to render
24 // to a texture that is already in use.
25 static const GLsizei kNumTextureSets = 2; 20 static const GLsizei kNumTextureSets = 2;
26 static const GLsizei kNumTexturesPerSet = 3; 21 static const GLsizei kNumTexturesPerSet = 3;
27 static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets; 22 static const GLsizei kNumTextures = kNumTexturesPerSet * kNumTextureSets;
28 23
29 // Fragment shader converts YUV values from input textures into a final RGB 24 @implementation RTCI420TextureCache {
30 // pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php.
31 static const char kI420FragmentShaderSource[] =
32 SHADER_VERSION
33 "precision highp float;"
34 FRAGMENT_SHADER_IN " vec2 v_texcoord;\n"
35 "uniform lowp sampler2D s_textureY;\n"
36 "uniform lowp sampler2D s_textureU;\n"
37 "uniform lowp sampler2D s_textureV;\n"
38 FRAGMENT_SHADER_OUT
39 "void main() {\n"
40 " float y, u, v, r, g, b;\n"
41 " y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n"
42 " u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n"
43 " v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n"
44 " u = u - 0.5;\n"
45 " v = v - 0.5;\n"
46 " r = y + 1.403 * v;\n"
47 " g = y - 0.344 * u - 0.714 * v;\n"
48 " b = y + 1.770 * u;\n"
49 " " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n"
50 " }\n";
51
52 @implementation RTCI420Shader {
53 BOOL _hasUnpackRowLength; 25 BOOL _hasUnpackRowLength;
54 GLint _currentTextureSet; 26 GLint _currentTextureSet;
55 // Handles for OpenGL constructs. 27 // Handles for OpenGL constructs.
56 GLuint _textures[kNumTextures]; 28 GLuint _textures[kNumTextures];
57 GLuint _i420Program; 29 // Used to create a non-padded plane for GPU upload when we receive padded fra mes.
58 GLuint _vertexArray;
59 GLuint _vertexBuffer;
60 GLint _ySampler;
61 GLint _uSampler;
62 GLint _vSampler;
63 // Store current rotation and only upload new vertex data when rotation
64 // changes.
65 rtc::Optional<RTCVideoRotation> _currentRotation;
66 // Used to create a non-padded plane for GPU upload when we receive padded
67 // frames.
68 std::vector<uint8_t> _planeBuffer; 30 std::vector<uint8_t> _planeBuffer;
69 } 31 }
70 32
33 - (GLuint)yTexture {
34 return _textures[_currentTextureSet * kNumTexturesPerSet];
35 }
36
37 - (GLuint)uTexture {
38 return _textures[_currentTextureSet * kNumTexturesPerSet + 1];
39 }
40
41 - (GLuint)vTexture {
42 return _textures[_currentTextureSet * kNumTexturesPerSet + 2];
43 }
44
71 - (instancetype)initWithContext:(GlContextType *)context { 45 - (instancetype)initWithContext:(GlContextType *)context {
72 if (self = [super init]) { 46 if (self = [super init]) {
73 #if TARGET_OS_IPHONE 47 #if TARGET_OS_IPHONE
74 _hasUnpackRowLength = (context.API == kEAGLRenderingAPIOpenGLES3); 48 _hasUnpackRowLength = (context.API == kEAGLRenderingAPIOpenGLES3);
75 #else 49 #else
76 _hasUnpackRowLength = YES; 50 _hasUnpackRowLength = YES;
77 #endif 51 #endif
78 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 52 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
79 if (![self setupI420Program] || ![self setupTextures] || 53
80 !RTCSetupVerticesForProgram(_i420Program, &_vertexBuffer, &_vertexArray) ) { 54 [self setupTextures];
81 RTCLog(@"Failed to initialize RTCI420Shader.");
82 self = nil;
83 }
84 } 55 }
85 return self; 56 return self;
86 } 57 }
87 58
88 - (void)dealloc { 59 - (void)dealloc {
89 glDeleteProgram(_i420Program);
90 glDeleteTextures(kNumTextures, _textures); 60 glDeleteTextures(kNumTextures, _textures);
91 glDeleteBuffers(1, &_vertexBuffer);
92 glDeleteVertexArrays(1, &_vertexArray);
93 } 61 }
94 62
95 - (BOOL)setupI420Program { 63 - (void)setupTextures {
96 _i420Program = RTCCreateProgramFromFragmentSource(kI420FragmentShaderSource);
97 if (!_i420Program) {
98 return NO;
99 }
100 _ySampler = glGetUniformLocation(_i420Program, "s_textureY");
101 _uSampler = glGetUniformLocation(_i420Program, "s_textureU");
102 _vSampler = glGetUniformLocation(_i420Program, "s_textureV");
103
104 return (_ySampler >= 0 && _uSampler >= 0 && _vSampler >= 0);
105 }
106
107 - (BOOL)setupTextures {
108 glGenTextures(kNumTextures, _textures); 64 glGenTextures(kNumTextures, _textures);
109 // Set parameters for each of the textures we created. 65 // Set parameters for each of the textures we created.
110 for (GLsizei i = 0; i < kNumTextures; i++) { 66 for (GLsizei i = 0; i < kNumTextures; i++) {
111 glBindTexture(GL_TEXTURE_2D, _textures[i]); 67 glBindTexture(GL_TEXTURE_2D, _textures[i]);
112 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 68 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
113 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
114 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
115 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
116 } 72 }
117 return YES;
118 }
119
120 - (BOOL)drawFrame:(RTCVideoFrame*)frame {
121 glUseProgram(_i420Program);
122 if (![self updateTextureDataForFrame:frame]) {
123 return NO;
124 }
125 #if !TARGET_OS_IPHONE
126 glBindVertexArray(_vertexArray);
127 #endif
128 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
129 if (!_currentRotation || frame.rotation != *_currentRotation) {
130 _currentRotation = rtc::Optional<RTCVideoRotation>(frame.rotation);
131 RTCSetVertexData(*_currentRotation);
132 }
133 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
134
135 return YES;
136 } 73 }
137 74
138 - (void)uploadPlane:(const uint8_t *)plane 75 - (void)uploadPlane:(const uint8_t *)plane
139 sampler:(GLint)sampler 76 texture:(GLuint)texture
140 offset:(GLint)offset
141 width:(size_t)width 77 width:(size_t)width
142 height:(size_t)height 78 height:(size_t)height
143 stride:(int32_t)stride { 79 stride:(int32_t)stride {
144 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + offset)); 80 glBindTexture(GL_TEXTURE_2D, texture);
145 glBindTexture(GL_TEXTURE_2D, _textures[offset]);
146 81
147 // When setting texture sampler uniforms, the texture index is used not
148 // the texture handle.
149 glUniform1i(sampler, offset);
150 const uint8_t *uploadPlane = plane; 82 const uint8_t *uploadPlane = plane;
151 if ((size_t)stride != width) { 83 if ((size_t)stride != width) {
152 if (_hasUnpackRowLength) { 84 if (_hasUnpackRowLength) {
153 // GLES3 allows us to specify stride. 85 // GLES3 allows us to specify stride.
154 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); 86 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
155 glTexImage2D(GL_TEXTURE_2D, 87 glTexImage2D(GL_TEXTURE_2D,
156 0, 88 0,
157 RTC_PIXEL_FORMAT, 89 RTC_PIXEL_FORMAT,
158 static_cast<GLsizei>(width), 90 static_cast<GLsizei>(width),
159 static_cast<GLsizei>(height), 91 static_cast<GLsizei>(height),
(...skipping 17 matching lines...) Expand all
177 0, 109 0,
178 RTC_PIXEL_FORMAT, 110 RTC_PIXEL_FORMAT,
179 static_cast<GLsizei>(width), 111 static_cast<GLsizei>(width),
180 static_cast<GLsizei>(height), 112 static_cast<GLsizei>(height),
181 0, 113 0,
182 RTC_PIXEL_FORMAT, 114 RTC_PIXEL_FORMAT,
183 GL_UNSIGNED_BYTE, 115 GL_UNSIGNED_BYTE,
184 uploadPlane); 116 uploadPlane);
185 } 117 }
186 118
187 - (BOOL)updateTextureDataForFrame:(RTCVideoFrame *)frame { 119 - (void)uploadFrameToTextures:(RTCVideoFrame *)frame {
188 GLint textureOffset = _currentTextureSet * 3; 120 _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
189 NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset");
190 121
191 const int chromaWidth = (frame.width + 1) / 2; 122 const int chromaWidth = (frame.width + 1) / 2;
192 const int chromaHeight = (frame.height + 1) / 2; 123 const int chromaHeight = (frame.height + 1) / 2;
193 if (frame.strideY != frame.width || 124 if (frame.strideY != frame.width ||
194 frame.strideU != chromaWidth || 125 frame.strideU != chromaWidth ||
195 frame.strideV != chromaWidth) { 126 frame.strideV != chromaWidth) {
196 _planeBuffer.resize(frame.width * frame.height); 127 _planeBuffer.resize(frame.width * frame.height);
197 } 128 }
198 129
199 [self uploadPlane:frame.dataY 130 [self uploadPlane:frame.dataY
200 sampler:_ySampler 131 texture:self.yTexture
201 offset:textureOffset
202 width:frame.width 132 width:frame.width
203 height:frame.height 133 height:frame.height
204 stride:frame.strideY]; 134 stride:frame.strideY];
205 135
206 [self uploadPlane:frame.dataU 136 [self uploadPlane:frame.dataU
207 sampler:_uSampler 137 texture:self.uTexture
208 offset:textureOffset + 1
209 width:chromaWidth 138 width:chromaWidth
210 height:chromaHeight 139 height:chromaHeight
211 stride:frame.strideU]; 140 stride:frame.strideU];
212 141
213 [self uploadPlane:frame.dataV 142 [self uploadPlane:frame.dataV
214 sampler:_vSampler 143 texture:self.vTexture
215 offset:textureOffset + 2
216 width:chromaWidth 144 width:chromaWidth
217 height:chromaHeight 145 height:chromaHeight
218 stride:frame.strideV]; 146 stride:frame.strideV];
219
220 _currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
221 return YES;
222 } 147 }
223 148
224 @end 149 @end
OLDNEW
« no previous file with comments | « webrtc/sdk/objc/Framework/Classes/RTCI420TextureCache.h ('k') | webrtc/sdk/objc/Framework/Classes/RTCOpenGLDefines.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698