OLD | NEW |
---|---|
(Empty) | |
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 "RTCDefaultShaderDelegate.h" | |
12 | |
13 #if TARGET_OS_IPHONE | |
14 #import <OpenGLES/ES3/gl.h> | |
15 #else | |
16 #import <OpenGL/gl3.h> | |
17 #endif | |
18 | |
19 #import "RTCOpenGLDefines.h" | |
20 #import "RTCShader.h" | |
21 #import "WebRTC/RTCLogging.h" | |
22 | |
23 #include "webrtc/base/optional.h" | |
24 | |
25 static const int kYTextureUnit = 0; | |
26 static const int kUTextureUnit = 1; | |
27 static const int kVTextureUnit = 2; | |
28 static const int kUvTextureUnit = 1; | |
29 | |
30 // Fragment shader converts YUV values from input textures into a final RGB | |
31 // pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php. | |
32 static const char kI420FragmentShaderSource[] = | |
33 SHADER_VERSION | |
34 "precision highp float;" | |
35 FRAGMENT_SHADER_IN " vec2 v_texcoord;\n" | |
36 "uniform lowp sampler2D s_textureY;\n" | |
37 "uniform lowp sampler2D s_textureU;\n" | |
38 "uniform lowp sampler2D s_textureV;\n" | |
39 FRAGMENT_SHADER_OUT | |
40 "void main() {\n" | |
41 " float y, u, v, r, g, b;\n" | |
42 " y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n" | |
43 " u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n" | |
44 " v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n" | |
45 " u = u - 0.5;\n" | |
46 " v = v - 0.5;\n" | |
47 " r = y + 1.403 * v;\n" | |
48 " g = y - 0.344 * u - 0.714 * v;\n" | |
49 " b = y + 1.770 * u;\n" | |
50 " " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n" | |
51 " }\n"; | |
52 | |
53 static const char kNV12FragmentShaderSource[] = | |
54 SHADER_VERSION | |
55 "precision mediump float;" | |
56 FRAGMENT_SHADER_IN " vec2 v_texcoord;\n" | |
57 "uniform lowp sampler2D s_textureY;\n" | |
58 "uniform lowp sampler2D s_textureUV;\n" | |
59 FRAGMENT_SHADER_OUT | |
60 "void main() {\n" | |
61 " mediump float y;\n" | |
62 " mediump vec2 uv;\n" | |
63 " y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n" | |
64 " uv = " FRAGMENT_SHADER_TEXTURE "(s_textureUV, v_texcoord).ra -\n" | |
65 " vec2(0.5, 0.5);\n" | |
66 " " FRAGMENT_SHADER_COLOR " = vec4(y + 1.403 * uv.y,\n" | |
67 " y - 0.344 * uv.x - 0.714 * uv.y,\n" | |
68 " y + 1.770 * uv.x,\n" | |
69 " 1.0);\n" | |
70 " }\n"; | |
71 | |
72 @implementation RTCDefaultShaderDelegate { | |
73 GLuint _vertexBuffer; | |
74 GLuint _vertexArray; | |
75 // Store current rotation and only upload new vertex data when rotation change s. | |
76 rtc::Optional<RTCVideoRotation> _currentRotation; | |
77 | |
78 GLuint _i420Program; | |
79 GLuint _nv12Program; | |
80 } | |
81 | |
82 - (void)dealloc { | |
83 glDeleteProgram(_i420Program); | |
84 glDeleteProgram(_nv12Program); | |
85 glDeleteBuffers(1, &_vertexBuffer); | |
86 glDeleteVertexArrays(1, &_vertexArray); | |
87 } | |
88 | |
89 - (BOOL)setupI420Program { | |
90 _i420Program = RTCCreateProgramFromFragmentSource(kI420FragmentShaderSource); | |
daniela-webrtc
2017/05/11 17:31:20
Should we check if the program already exists? If
magjed_webrtc
2017/05/25 14:26:45
Added assert and changed the name.
| |
91 if (!_i420Program) { | |
92 return NO; | |
93 } | |
94 GLint ySampler = glGetUniformLocation(_i420Program, "s_textureY"); | |
95 GLint uSampler = glGetUniformLocation(_i420Program, "s_textureU"); | |
96 GLint vSampler = glGetUniformLocation(_i420Program, "s_textureV"); | |
97 | |
98 if (ySampler < 0 || uSampler < 0 || vSampler < 0) { | |
99 RTCLog(@"Failed to get uniform variable locations in I420 shader"); | |
100 glDeleteProgram(_i420Program); | |
101 _i420Program = 0; | |
102 return NO; | |
103 } | |
104 | |
105 glUseProgram(_i420Program); | |
106 glUniform1i(ySampler, kYTextureUnit); | |
107 glUniform1i(uSampler, kUTextureUnit); | |
108 glUniform1i(vSampler, kVTextureUnit); | |
109 | |
110 return YES; | |
111 } | |
112 | |
113 - (BOOL)setupNV12Program { | |
114 _nv12Program = RTCCreateProgramFromFragmentSource(kNV12FragmentShaderSource); | |
daniela-webrtc
2017/05/11 17:31:20
^
magjed_webrtc
2017/05/25 14:26:45
Done.
| |
115 if (!_nv12Program) { | |
116 return NO; | |
117 } | |
118 GLint ySampler = glGetUniformLocation(_nv12Program, "s_textureY"); | |
119 GLint uvSampler = glGetUniformLocation(_nv12Program, "s_textureUV"); | |
120 | |
121 if (ySampler < 0 || uvSampler < 0) { | |
122 RTCLog(@"Failed to get uniform variable locations in NV12 shader"); | |
123 glDeleteProgram(_nv12Program); | |
124 _nv12Program = 0; | |
125 return NO; | |
126 } | |
127 | |
128 glUseProgram(_nv12Program); | |
129 glUniform1i(ySampler, kYTextureUnit); | |
130 glUniform1i(uvSampler, kUvTextureUnit); | |
131 | |
132 return YES; | |
133 } | |
134 | |
135 - (BOOL)prepareVertexBufferWithRotation:(RTCVideoRotation)rotation { | |
136 if (!_vertexBuffer && !RTCCreateVertexBuffer(&_vertexBuffer, &_vertexArray)) { | |
137 RTCLog(@"Failed to setup vertex buffer"); | |
138 return NO; | |
139 } | |
140 #if !TARGET_OS_IPHONE | |
141 glBindVertexArray(_vertexArray); | |
142 #endif | |
143 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); | |
144 if (!_currentRotation || rotation != *_currentRotation) { | |
145 _currentRotation = rtc::Optional<RTCVideoRotation>(rotation); | |
146 RTCSetVertexData(*_currentRotation); | |
147 } | |
148 return YES; | |
149 } | |
150 | |
151 - (void)videoView:(RTCVideoView *)videoView | |
152 didReceiveFrameWithRotation:(RTCVideoRotation)rotation | |
153 yPlane:(GLuint)yPlane | |
154 uPlane:(GLuint)uPlane | |
155 vPlane:(GLuint)vPlane { | |
156 if (![self prepareVertexBufferWithRotation:rotation]) { | |
157 return; | |
158 } | |
159 | |
160 if (!_i420Program && ![self setupI420Program]) { | |
161 RTCLog(@"Failed to setup I420 program"); | |
162 return; | |
163 } | |
164 | |
165 glUseProgram(_i420Program); | |
166 | |
167 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kYTextureUnit)); | |
168 glBindTexture(GL_TEXTURE_2D, yPlane); | |
169 | |
170 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kUTextureUnit)); | |
171 glBindTexture(GL_TEXTURE_2D, uPlane); | |
172 | |
173 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kVTextureUnit)); | |
174 glBindTexture(GL_TEXTURE_2D, vPlane); | |
175 | |
176 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | |
177 } | |
178 | |
179 - (void)videoView:(RTCVideoView *)videoView | |
180 didReceiveFrameWithRotation:(RTCVideoRotation)rotation | |
181 yPlane:(GLuint)yPlane | |
182 uvPlane:(GLuint)uvPlane { | |
183 if (![self prepareVertexBufferWithRotation:rotation]) { | |
184 return; | |
185 } | |
186 | |
187 if (!_nv12Program && ![self setupNV12Program]) { | |
188 RTCLog(@"Failed to setup NV12 shader"); | |
189 return; | |
190 } | |
191 | |
192 glUseProgram(_nv12Program); | |
193 | |
194 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kYTextureUnit)); | |
195 glBindTexture(GL_TEXTURE_2D, yPlane); | |
196 | |
197 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kUvTextureUnit)); | |
198 glBindTexture(GL_TEXTURE_2D, uvPlane); | |
199 | |
200 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | |
201 } | |
202 | |
203 @end | |
OLD | NEW |