| 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 | |