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); | |
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 glDeleteProgram(_i420Program); | |
sakal
2017/05/11 10:45:47
Log error?
magjed_webrtc
2017/05/11 12:38:06
Done.
| |
100 _i420Program = 0; | |
101 return NO; | |
102 } | |
103 | |
104 glUseProgram(_i420Program); | |
105 glUniform1i(ySampler, kYTextureUnit); | |
106 glUniform1i(uSampler, kUTextureUnit); | |
107 glUniform1i(vSampler, kVTextureUnit); | |
108 | |
109 return YES; | |
110 } | |
111 | |
112 - (BOOL)setupNV12Program { | |
113 _nv12Program = RTCCreateProgramFromFragmentSource(kNV12FragmentShaderSource); | |
114 if (!_nv12Program) { | |
115 return NO; | |
116 } | |
117 GLint ySampler = glGetUniformLocation(_nv12Program, "s_textureY"); | |
118 GLint uvSampler = glGetUniformLocation(_nv12Program, "s_textureUV"); | |
119 | |
120 if (ySampler < 0 || uvSampler < 0) { | |
121 glDeleteProgram(_nv12Program); | |
122 _nv12Program = 0; | |
123 return NO; | |
124 } | |
125 | |
126 glUseProgram(_nv12Program); | |
127 glUniform1i(ySampler, kYTextureUnit); | |
128 glUniform1i(uvSampler, kUvTextureUnit); | |
129 | |
130 return YES; | |
131 } | |
132 | |
133 - (BOOL)prepareVertexBufferWithRotation:(RTCVideoRotation)rotation { | |
134 if (!_vertexBuffer && !RTCCreateVertexBuffer(&_vertexBuffer, &_vertexArray)) { | |
135 RTCLog(@"Failed to setup vertex buffer"); | |
136 return NO; | |
137 } | |
138 #if !TARGET_OS_IPHONE | |
139 glBindVertexArray(_vertexArray); | |
140 #endif | |
141 glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); | |
142 if (!_currentRotation || rotation != *_currentRotation) { | |
143 _currentRotation = rtc::Optional<RTCVideoRotation>(rotation); | |
144 RTCSetVertexData(*_currentRotation); | |
145 } | |
146 return YES; | |
147 } | |
148 | |
149 - (void)videoView:(RTCVideoView *)videoView | |
150 didReceiveFrameWithRotation:(RTCVideoRotation)rotation | |
151 yPlane:(GLuint)yPlane | |
152 uPlane:(GLuint)uPlane | |
153 vPlane:(GLuint)vPlane { | |
154 if (![self prepareVertexBufferWithRotation:rotation]) { | |
155 return; | |
156 } | |
157 | |
158 if (!_i420Program && ![self setupI420Program]) { | |
159 RTCLog(@"Failed to setup I420 program"); | |
160 return; | |
161 } | |
162 | |
163 glUseProgram(_i420Program); | |
164 | |
165 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kYTextureUnit)); | |
166 glBindTexture(GL_TEXTURE_2D, yPlane); | |
167 | |
168 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kUTextureUnit)); | |
169 glBindTexture(GL_TEXTURE_2D, uPlane); | |
170 | |
171 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kVTextureUnit)); | |
172 glBindTexture(GL_TEXTURE_2D, vPlane); | |
173 | |
174 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | |
175 } | |
176 | |
177 - (void)videoView:(RTCVideoView *)videoView | |
178 didReceiveFrameWithRotation:(RTCVideoRotation)rotation | |
179 yPlane:(GLuint)yPlane | |
180 uvPlane:(GLuint)uvPlane { | |
181 if (![self prepareVertexBufferWithRotation:rotation]) { | |
182 return; | |
183 } | |
184 | |
185 if (!_nv12Program && ![self setupNV12Program]) { | |
186 RTCLog(@"Failed to setup NV12 shader"); | |
187 return; | |
188 } | |
189 | |
190 glUseProgram(_nv12Program); | |
191 | |
192 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kYTextureUnit)); | |
193 glBindTexture(GL_TEXTURE_2D, yPlane); | |
194 | |
195 glActiveTexture(static_cast<GLenum>(GL_TEXTURE0 + kUvTextureUnit)); | |
196 glBindTexture(GL_TEXTURE_2D, uvPlane); | |
197 | |
198 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | |
199 } | |
200 | |
201 @end | |
OLD | NEW |