1 | /* |
2 | Copyright (C) 2016 Igalia S.L. |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | |
21 | #include "config.h" |
22 | #include "VideoTextureCopierGStreamer.h" |
23 | |
24 | #if USE(GSTREAMER_GL) |
25 | |
26 | #include "GLContext.h" |
27 | #include "ImageOrientation.h" |
28 | #include "TextureMapperShaderProgram.h" |
29 | |
30 | namespace WebCore { |
31 | |
32 | VideoTextureCopierGStreamer::VideoTextureCopierGStreamer(ColorConversion colorConversion) |
33 | { |
34 | GLContext* previousContext = GLContext::current(); |
35 | ASSERT(previousContext); |
36 | PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); |
37 | |
38 | m_shaderProgram = TextureMapperShaderProgram::create(TextureMapperShaderProgram::Texture); |
39 | |
40 | glGenFramebuffers(1, &m_framebuffer); |
41 | glGenTextures(1, &m_resultTexture); |
42 | |
43 | #if !USE(OPENGL_ES) |
44 | // For OpenGL > 3.2 we need to have a VAO. |
45 | if (GLContext::current()->version() >= 320) |
46 | glGenVertexArrays(1, &m_vao); |
47 | #endif |
48 | |
49 | static const GLfloat vertices[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; |
50 | glGenBuffers(1, &m_vbo); |
51 | glBindBuffer(GL_ARRAY_BUFFER, m_vbo); |
52 | glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW); |
53 | |
54 | updateColorConversionMatrix(colorConversion); |
55 | updateTextureSpaceMatrix(); |
56 | |
57 | previousContext->makeContextCurrent(); |
58 | } |
59 | |
60 | VideoTextureCopierGStreamer::~VideoTextureCopierGStreamer() |
61 | { |
62 | GLContext* previousContext = GLContext::current(); |
63 | PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); |
64 | |
65 | glDeleteFramebuffers(1, &m_framebuffer); |
66 | glDeleteBuffers(1, &m_vbo); |
67 | glDeleteTextures(1, &m_resultTexture); |
68 | #if !USE(OPENGL_ES) |
69 | if (m_vao) |
70 | glDeleteVertexArrays(1, &m_vao); |
71 | #endif |
72 | m_shaderProgram = nullptr; |
73 | |
74 | if (previousContext) |
75 | previousContext->makeContextCurrent(); |
76 | } |
77 | |
78 | void VideoTextureCopierGStreamer::updateColorConversionMatrix(ColorConversion colorConversion) |
79 | { |
80 | switch (colorConversion) { |
81 | case ColorConversion::ConvertBGRAToRGBA: |
82 | m_colorConversionMatrix.setMatrix(0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); |
83 | break; |
84 | case ColorConversion::ConvertARGBToRGBA: |
85 | m_colorConversionMatrix.setMatrix(0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0); |
86 | break; |
87 | default: |
88 | RELEASE_ASSERT_NOT_REACHED(); |
89 | } |
90 | } |
91 | |
92 | void VideoTextureCopierGStreamer::updateTextureSpaceMatrix() |
93 | { |
94 | m_textureSpaceMatrix.makeIdentity(); |
95 | |
96 | switch (m_orientation) { |
97 | case DefaultImageOrientation: |
98 | break; |
99 | case OriginRightTop: |
100 | m_textureSpaceMatrix.rotate(-90); |
101 | m_textureSpaceMatrix.translate(-1, 0); |
102 | break; |
103 | case OriginBottomRight: |
104 | m_textureSpaceMatrix.rotate(180); |
105 | m_textureSpaceMatrix.translate(-1, -1); |
106 | break; |
107 | case OriginLeftBottom: |
108 | m_textureSpaceMatrix.rotate(-270); |
109 | m_textureSpaceMatrix.translate(0, -1); |
110 | break; |
111 | default: |
112 | ASSERT_NOT_REACHED(); |
113 | } |
114 | |
115 | if (!m_flipY) { |
116 | m_textureSpaceMatrix.flipY(); |
117 | m_textureSpaceMatrix.translate(0, -1); |
118 | } |
119 | } |
120 | |
121 | void VideoTextureCopierGStreamer::updateTransformationMatrix() |
122 | { |
123 | FloatRect targetRect = FloatRect(FloatPoint(), m_size); |
124 | TransformationMatrix identityMatrix; |
125 | m_modelViewMatrix = TransformationMatrix(identityMatrix).multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect)); |
126 | |
127 | // Taken from TextureMapperGL. |
128 | const float nearValue = 9999999; |
129 | const float farValue = -99999; |
130 | |
131 | m_projectionMatrix = TransformationMatrix(2.0 / float(m_size.width()), 0, 0, 0, |
132 | 0, (-2.0) / float(m_size.height()), 0, 0, |
133 | 0, 0, -2.f / (farValue - nearValue), 0, |
134 | -1, 1, -(farValue + nearValue) / (farValue - nearValue), 1); |
135 | } |
136 | |
137 | bool VideoTextureCopierGStreamer::copyVideoTextureToPlatformTexture(GLuint inputTexture, IntSize& frameSize, GLuint outputTexture, GLenum outputTarget, GLint level, GLenum internalFormat, GLenum format, GLenum type, bool flipY, ImageOrientation& sourceOrientation) |
138 | { |
139 | if (!m_shaderProgram || !m_framebuffer || !m_vbo || frameSize.isEmpty()) |
140 | return false; |
141 | |
142 | if (m_size != frameSize) { |
143 | m_size = frameSize; |
144 | updateTransformationMatrix(); |
145 | } |
146 | |
147 | if (m_flipY != flipY || m_orientation != sourceOrientation) { |
148 | m_flipY = flipY; |
149 | m_orientation = sourceOrientation; |
150 | updateTextureSpaceMatrix(); |
151 | } |
152 | |
153 | // Save previous context and activate the sharing one. |
154 | GLContext* previousContext = GLContext::current(); |
155 | ASSERT(previousContext); |
156 | PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); |
157 | |
158 | // Save previous bound framebuffer, texture and viewport. |
159 | GLint boundFramebuffer = 0; |
160 | GLint boundTexture = 0; |
161 | GLint previousViewport[4] = { 0, 0, 0, 0}; |
162 | glGetIntegerv(GL_FRAMEBUFFER_BINDING, &boundFramebuffer); |
163 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); |
164 | glGetIntegerv(GL_VIEWPORT, previousViewport); |
165 | |
166 | // Use our own output texture if we are not given one. |
167 | if (!outputTexture) |
168 | outputTexture = m_resultTexture; |
169 | |
170 | // Set proper parameters to the output texture and allocate uninitialized memory for it. |
171 | glBindTexture(outputTarget, outputTexture); |
172 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
173 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
174 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
175 | glTexImage2D(outputTarget, level, internalFormat, m_size.width(), m_size.height(), 0, format, type, nullptr); |
176 | |
177 | // Bind framebuffer to paint and attach the destination texture to it. |
178 | glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); |
179 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outputTexture, 0); |
180 | |
181 | // Set proper wrap parameter to the source texture. |
182 | glBindTexture(GL_TEXTURE_2D, inputTexture); |
183 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
184 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
185 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
186 | |
187 | // Set the viewport. |
188 | glViewport(0, 0, m_size.width(), m_size.height()); |
189 | |
190 | // Set program parameters. |
191 | glUseProgram(m_shaderProgram->programID()); |
192 | glUniform1i(m_shaderProgram->samplerLocation(), 0); |
193 | m_shaderProgram->setMatrix(m_shaderProgram->modelViewMatrixLocation(), m_modelViewMatrix); |
194 | m_shaderProgram->setMatrix(m_shaderProgram->projectionMatrixLocation(), m_projectionMatrix); |
195 | m_shaderProgram->setMatrix(m_shaderProgram->textureSpaceMatrixLocation(), m_textureSpaceMatrix); |
196 | m_shaderProgram->setMatrix(m_shaderProgram->textureColorSpaceMatrixLocation(), m_colorConversionMatrix); |
197 | |
198 | // Perform the copy. |
199 | #if !USE(OPENGL_ES) |
200 | if (GLContext::current()->version() >= 320 && m_vao) |
201 | glBindVertexArray(m_vao); |
202 | #endif |
203 | glEnableVertexAttribArray(m_shaderProgram->vertexLocation()); |
204 | glBindBuffer(GL_ARRAY_BUFFER, m_vbo); |
205 | glVertexAttribPointer(m_shaderProgram->vertexLocation(), 2, GL_FLOAT, false, 0, 0); |
206 | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
207 | glBindBuffer(GL_ARRAY_BUFFER, 0); |
208 | glDisableVertexAttribArray(m_shaderProgram->vertexLocation()); |
209 | glUseProgram(0); |
210 | |
211 | // Restore previous bindings and viewport. |
212 | glBindFramebuffer(GL_FRAMEBUFFER, boundFramebuffer); |
213 | glBindTexture(outputTarget, boundTexture); |
214 | glViewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]); |
215 | |
216 | bool ok = (glGetError() == GL_NO_ERROR); |
217 | |
218 | // Restore previous context. |
219 | previousContext->makeContextCurrent(); |
220 | return ok; |
221 | } |
222 | |
223 | } // namespace WebCore |
224 | |
225 | #endif // USE(GSTREAMER_GL) |
226 | |