| /* |
| Copyright (C) 2016 Igalia S.L. |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| Boston, MA 02110-1301, USA. |
| */ |
| |
| |
| #include "config.h" |
| #include "VideoTextureCopierGStreamer.h" |
| |
| #if USE(GSTREAMER_GL) |
| |
| #include "GLContext.h" |
| #include "ImageOrientation.h" |
| #include "TextureMapperShaderProgram.h" |
| |
| namespace WebCore { |
| |
| VideoTextureCopierGStreamer::VideoTextureCopierGStreamer(ColorConversion colorConversion) |
| { |
| GLContext* previousContext = GLContext::current(); |
| ASSERT(previousContext); |
| PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); |
| |
| m_shaderProgram = TextureMapperShaderProgram::create(TextureMapperShaderProgram::Texture); |
| |
| glGenFramebuffers(1, &m_framebuffer); |
| glGenTextures(1, &m_resultTexture); |
| |
| #if !USE(OPENGL_ES) |
| // For OpenGL > 3.2 we need to have a VAO. |
| if (GLContext::current()->version() >= 320) |
| glGenVertexArrays(1, &m_vao); |
| #endif |
| |
| static const GLfloat vertices[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; |
| glGenBuffers(1, &m_vbo); |
| glBindBuffer(GL_ARRAY_BUFFER, m_vbo); |
| glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW); |
| |
| updateColorConversionMatrix(colorConversion); |
| updateTextureSpaceMatrix(); |
| |
| previousContext->makeContextCurrent(); |
| } |
| |
| VideoTextureCopierGStreamer::~VideoTextureCopierGStreamer() |
| { |
| GLContext* previousContext = GLContext::current(); |
| PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); |
| |
| glDeleteFramebuffers(1, &m_framebuffer); |
| glDeleteBuffers(1, &m_vbo); |
| glDeleteTextures(1, &m_resultTexture); |
| #if !USE(OPENGL_ES) |
| if (m_vao) |
| glDeleteVertexArrays(1, &m_vao); |
| #endif |
| m_shaderProgram = nullptr; |
| |
| if (previousContext) |
| previousContext->makeContextCurrent(); |
| } |
| |
| void VideoTextureCopierGStreamer::updateColorConversionMatrix(ColorConversion colorConversion) |
| { |
| switch (colorConversion) { |
| case ColorConversion::ConvertBGRAToRGBA: |
| 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); |
| break; |
| case ColorConversion::ConvertARGBToRGBA: |
| 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); |
| break; |
| default: |
| RELEASE_ASSERT_NOT_REACHED(); |
| } |
| } |
| |
| void VideoTextureCopierGStreamer::updateTextureSpaceMatrix() |
| { |
| m_textureSpaceMatrix.makeIdentity(); |
| |
| switch (m_orientation) { |
| case DefaultImageOrientation: |
| break; |
| case OriginRightTop: |
| m_textureSpaceMatrix.rotate(-90); |
| m_textureSpaceMatrix.translate(-1, 0); |
| break; |
| case OriginBottomRight: |
| m_textureSpaceMatrix.rotate(180); |
| m_textureSpaceMatrix.translate(-1, -1); |
| break; |
| case OriginLeftBottom: |
| m_textureSpaceMatrix.rotate(-270); |
| m_textureSpaceMatrix.translate(0, -1); |
| break; |
| default: |
| ASSERT_NOT_REACHED(); |
| } |
| |
| if (!m_flipY) { |
| m_textureSpaceMatrix.flipY(); |
| m_textureSpaceMatrix.translate(0, -1); |
| } |
| } |
| |
| void VideoTextureCopierGStreamer::updateTransformationMatrix() |
| { |
| FloatRect targetRect = FloatRect(FloatPoint(), m_size); |
| TransformationMatrix identityMatrix; |
| m_modelViewMatrix = TransformationMatrix(identityMatrix).multiply(TransformationMatrix::rectToRect(FloatRect(0, 0, 1, 1), targetRect)); |
| |
| // Taken from TextureMapperGL. |
| const float nearValue = 9999999; |
| const float farValue = -99999; |
| |
| m_projectionMatrix = TransformationMatrix(2.0 / float(m_size.width()), 0, 0, 0, |
| 0, (-2.0) / float(m_size.height()), 0, 0, |
| 0, 0, -2.f / (farValue - nearValue), 0, |
| -1, 1, -(farValue + nearValue) / (farValue - nearValue), 1); |
| } |
| |
| bool VideoTextureCopierGStreamer::copyVideoTextureToPlatformTexture(GLuint inputTexture, IntSize& frameSize, GLuint outputTexture, GLenum outputTarget, GLint level, GLenum internalFormat, GLenum format, GLenum type, bool flipY, ImageOrientation& sourceOrientation) |
| { |
| if (!m_shaderProgram || !m_framebuffer || !m_vbo || frameSize.isEmpty()) |
| return false; |
| |
| if (m_size != frameSize) { |
| m_size = frameSize; |
| updateTransformationMatrix(); |
| } |
| |
| if (m_flipY != flipY || m_orientation != sourceOrientation) { |
| m_flipY = flipY; |
| m_orientation = sourceOrientation; |
| updateTextureSpaceMatrix(); |
| } |
| |
| // Save previous context and activate the sharing one. |
| GLContext* previousContext = GLContext::current(); |
| ASSERT(previousContext); |
| PlatformDisplay::sharedDisplayForCompositing().sharingGLContext()->makeContextCurrent(); |
| |
| // Save previous bound framebuffer, texture and viewport. |
| GLint boundFramebuffer = 0; |
| GLint boundTexture = 0; |
| GLint previousViewport[4] = { 0, 0, 0, 0}; |
| glGetIntegerv(GL_FRAMEBUFFER_BINDING, &boundFramebuffer); |
| glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); |
| glGetIntegerv(GL_VIEWPORT, previousViewport); |
| |
| // Use our own output texture if we are not given one. |
| if (!outputTexture) |
| outputTexture = m_resultTexture; |
| |
| // Set proper parameters to the output texture and allocate uninitialized memory for it. |
| glBindTexture(outputTarget, outputTexture); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| glTexImage2D(outputTarget, level, internalFormat, m_size.width(), m_size.height(), 0, format, type, nullptr); |
| |
| // Bind framebuffer to paint and attach the destination texture to it. |
| glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outputTexture, 0); |
| |
| // Set proper wrap parameter to the source texture. |
| glBindTexture(GL_TEXTURE_2D, inputTexture); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| |
| // Set the viewport. |
| glViewport(0, 0, m_size.width(), m_size.height()); |
| |
| // Set program parameters. |
| glUseProgram(m_shaderProgram->programID()); |
| glUniform1i(m_shaderProgram->samplerLocation(), 0); |
| m_shaderProgram->setMatrix(m_shaderProgram->modelViewMatrixLocation(), m_modelViewMatrix); |
| m_shaderProgram->setMatrix(m_shaderProgram->projectionMatrixLocation(), m_projectionMatrix); |
| m_shaderProgram->setMatrix(m_shaderProgram->textureSpaceMatrixLocation(), m_textureSpaceMatrix); |
| m_shaderProgram->setMatrix(m_shaderProgram->textureColorSpaceMatrixLocation(), m_colorConversionMatrix); |
| |
| // Perform the copy. |
| #if !USE(OPENGL_ES) |
| if (GLContext::current()->version() >= 320 && m_vao) |
| glBindVertexArray(m_vao); |
| #endif |
| glEnableVertexAttribArray(m_shaderProgram->vertexLocation()); |
| glBindBuffer(GL_ARRAY_BUFFER, m_vbo); |
| glVertexAttribPointer(m_shaderProgram->vertexLocation(), 2, GL_FLOAT, false, 0, 0); |
| glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
| glBindBuffer(GL_ARRAY_BUFFER, 0); |
| glDisableVertexAttribArray(m_shaderProgram->vertexLocation()); |
| glUseProgram(0); |
| |
| // Restore previous bindings and viewport. |
| glBindFramebuffer(GL_FRAMEBUFFER, boundFramebuffer); |
| glBindTexture(outputTarget, boundTexture); |
| glViewport(previousViewport[0], previousViewport[1], previousViewport[2], previousViewport[3]); |
| |
| bool ok = (glGetError() == GL_NO_ERROR); |
| |
| // Restore previous context. |
| previousContext->makeContextCurrent(); |
| return ok; |
| } |
| |
| } // namespace WebCore |
| |
| #endif // USE(GSTREAMER_GL) |