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
30namespace WebCore {
31
32VideoTextureCopierGStreamer::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
60VideoTextureCopierGStreamer::~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
78void 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
92void 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
121void 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
137bool 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