diff options
Diffstat (limited to 'media/tools/player_x11/gles_video_renderer.cc')
-rw-r--r-- | media/tools/player_x11/gles_video_renderer.cc | 239 |
1 files changed, 183 insertions, 56 deletions
diff --git a/media/tools/player_x11/gles_video_renderer.cc b/media/tools/player_x11/gles_video_renderer.cc index 85e4329..a275366 100644 --- a/media/tools/player_x11/gles_video_renderer.cc +++ b/media/tools/player_x11/gles_video_renderer.cc @@ -5,6 +5,7 @@ #include "media/tools/player_x11/gles_video_renderer.h" #include <dlfcn.h> +#include <EGL/eglext.h> #include <X11/Xutil.h> #include <X11/extensions/Xrender.h> #include <X11/extensions/Xcomposite.h> @@ -18,7 +19,9 @@ GlesVideoRenderer* GlesVideoRenderer::instance_ = NULL; GlesVideoRenderer::GlesVideoRenderer(Display* display, Window window) - : display_(display), + : egl_create_image_khr_(NULL), + egl_destroy_image_khr_(NULL), + display_(display), window_(window), new_frame_(false), egl_display_(NULL), @@ -43,6 +46,14 @@ void GlesVideoRenderer::OnStop() { // calls may fail. Need to fix them. eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + for (size_t i = 0; i < egl_frames_.size(); ++i) { + scoped_refptr<media::VideoFrame> frame = egl_frames_[i].first; + if (frame->private_buffer()) + egl_destroy_image_khr_(egl_display_, frame->private_buffer()); + if (egl_frames_[i].second) + glDeleteTextures(1, &egl_frames_[i].second); + } + egl_frames_.clear(); eglDestroyContext(egl_display_, egl_context_); eglDestroySurface(egl_display_, egl_surface_); } @@ -70,6 +81,14 @@ static const float kTextureCoords[8] = { 1, 1, }; +// Texture Coordinates mapping the entire texture for EGL image. +static const float kTextureCoordsEgl[8] = { + 0, 1, + 0, 0, + 1, 1, + 1, 0, +}; + // Pass-through vertex shader. static const char kVertexShader[] = "precision highp float; precision highp int;\n" @@ -103,6 +122,16 @@ static const char kFragmentShader[] = " gl_FragColor = vec4(rgb, 1);\n" "}\n"; +// Color shader for EGLImage. +static const char kFragmentShaderEgl[] = + "varying vec2 interp_tc;\n" + "\n" + "uniform sampler2D tex;\n" + "\n" + "void main() {\n" + " gl_FragColor = texture2D(tex, interp_tc);\n" + "}\n"; + // Buffer size for compile errors. static const unsigned int kErrorSize = 4096; @@ -149,8 +178,23 @@ void GlesVideoRenderer::Paint() { scoped_refptr<media::VideoFrame> video_frame; GetCurrentFrame(&video_frame); - if (!video_frame) + if (!video_frame.get()) { return; + } + + if (uses_egl_image_) { + if (media::VideoFrame::TYPE_EGL_IMAGE == video_frame->type()) { + + GLuint texture = FindTexture(video_frame); + if (texture) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + eglSwapBuffers(egl_display_, egl_surface_); + } + } + return; + } // Convert YUV frame to RGB. DCHECK(video_frame->format() == media::VideoFrame::YV12 || @@ -200,6 +244,17 @@ void GlesVideoRenderer::Paint() { eglSwapBuffers(egl_display_, egl_surface_); } +// find if texture exists corresponding to video_frame +GLuint GlesVideoRenderer::FindTexture( + scoped_refptr<media::VideoFrame> video_frame) { + for (size_t i = 0; i < egl_frames_.size(); ++i) { + scoped_refptr<media::VideoFrame> frame = egl_frames_[i].first; + if (video_frame->private_buffer() == frame->private_buffer()) + return egl_frames_[i].second; + } + return NULL; +} + bool GlesVideoRenderer::InitializeGles() { // Resize the window to fit that of the video. XResizeWindow(display_, window_, width_, height_); @@ -288,6 +343,127 @@ bool GlesVideoRenderer::InitializeGles() { eglQuerySurface(egl_display_, egl_surface_, EGL_HEIGHT, &height); glViewport(0, 0, width_, height_); + if (uses_egl_image_) { + CreateTextureAndProgramEgl(); + return true; + } + + CreateTextureAndProgramYuv2Rgb(); + + // We are getting called on a thread. Release the context so that it can be + // made current on the main thread. + // TODO(hclam): Fix this if neccessary. Currently the following call fails + // for some drivers. + // eglMakeCurrent(egl_display_, EGL_NO_SURFACE, + // EGL_NO_SURFACE, EGL_NO_CONTEXT); + return true; +} + +void GlesVideoRenderer::CreateShader(GLuint program, + GLenum type, + const char* source, + int size) { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, &size); + glCompileShader(shader); + int result = GL_FALSE; + glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + if (!result) { + char log[kErrorSize]; + int len; + glGetShaderInfoLog(shader, kErrorSize - 1, &len, log); + log[kErrorSize - 1] = 0; + LOG(FATAL) << log; + } + glAttachShader(program, shader); + glDeleteShader(shader); +} + +void GlesVideoRenderer::LinkProgram(GLuint program) { + glLinkProgram(program); + int result = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &result); + if (!result) { + char log[kErrorSize]; + int len; + glGetProgramInfoLog(program, kErrorSize - 1, &len, log); + log[kErrorSize - 1] = 0; + LOG(FATAL) << log; + } + glUseProgram(program); + glDeleteProgram(program); +} + +void GlesVideoRenderer::CreateTextureAndProgramEgl() { + if (!egl_create_image_khr_) + egl_create_image_khr_ = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC> + (eglGetProcAddress("eglCreateImageKHR")); + if (!egl_destroy_image_khr_) + egl_destroy_image_khr_ = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC> + (eglGetProcAddress("eglDestroyImageKHR")); + // TODO(wjia): get count from decoder. + for (int i = 0; i < 4; i++) { + GLuint texture; + EGLint attrib = EGL_NONE; + EGLImageKHR egl_image; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width_, + height_, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + egl_image = egl_create_image_khr_( + egl_display_, + egl_context_, + EGL_GL_TEXTURE_2D_KHR, + reinterpret_cast<EGLClientBuffer>(texture), + &attrib); + + scoped_refptr<media::VideoFrame> video_frame; + const base::TimeDelta kZero; + media::VideoFrame:: CreatePrivateFrame( + media::VideoFrame::TYPE_EGL_IMAGE, + media::VideoFrame::RGB565, + width_, height_, kZero, kZero, + egl_image, + &video_frame); + egl_frames_.push_back(std::make_pair(video_frame, texture)); + GetDecoder()->FillThisBuffer(video_frame); + } + + GLuint program = glCreateProgram(); + + // Create shader for EGL image + CreateShader(program, GL_VERTEX_SHADER, + kVertexShader, sizeof(kVertexShader)); + CreateShader(program, GL_FRAGMENT_SHADER, + kFragmentShaderEgl, sizeof(kFragmentShaderEgl)); + LinkProgram(program); + + // Bind parameters. + glUniform1i(glGetUniformLocation(program, "tex"), 0); + + int pos_location = glGetAttribLocation(program, "in_pos"); + glEnableVertexAttribArray(pos_location); + glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); + + int tc_location = glGetAttribLocation(program, "in_tc"); + glEnableVertexAttribArray(tc_location); + glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, + kTextureCoordsEgl); +} + +void GlesVideoRenderer::CreateTextureAndProgramYuv2Rgb() { // Create 3 textures, one for each plane, and bind them to different // texture units. glGenTextures(media::VideoFrame::kNumYUVPlanes, textures_); @@ -313,52 +489,11 @@ bool GlesVideoRenderer::InitializeGles() { GLuint program = glCreateProgram(); // Create our YUV->RGB shader. - GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); - const char* vs_source = kVertexShader; - int vs_size = sizeof(kVertexShader); - glShaderSource(vertex_shader, 1, &vs_source, &vs_size); - glCompileShader(vertex_shader); - int result = GL_FALSE; - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &result); - if (!result) { - char log[kErrorSize]; - int len; - glGetShaderInfoLog(vertex_shader, kErrorSize - 1, &len, log); - log[kErrorSize - 1] = 0; - LOG(FATAL) << log; - } - glAttachShader(program, vertex_shader); - glDeleteShader(vertex_shader); - - GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); - const char* ps_source = kFragmentShader; - int ps_size = sizeof(kFragmentShader); - glShaderSource(fragment_shader, 1, &ps_source, &ps_size); - glCompileShader(fragment_shader); - result = GL_FALSE; - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &result); - if (!result) { - char log[kErrorSize]; - int len; - glGetShaderInfoLog(fragment_shader, kErrorSize - 1, &len, log); - log[kErrorSize - 1] = 0; - LOG(FATAL) << log; - } - glAttachShader(program, fragment_shader); - glDeleteShader(fragment_shader); - - glLinkProgram(program); - result = GL_FALSE; - glGetProgramiv(program, GL_LINK_STATUS, &result); - if (!result) { - char log[kErrorSize]; - int len; - glGetProgramInfoLog(program, kErrorSize - 1, &len, log); - log[kErrorSize - 1] = 0; - LOG(FATAL) << log; - } - glUseProgram(program); - glDeleteProgram(program); + CreateShader(program, GL_VERTEX_SHADER, + kVertexShader, sizeof(kVertexShader)); + CreateShader(program, GL_FRAGMENT_SHADER, + kFragmentShaderEgl, sizeof(kFragmentShader)); + LinkProgram(program); // Bind parameters. glUniform1i(glGetUniformLocation(program, "y_tex"), 0); @@ -377,12 +512,4 @@ bool GlesVideoRenderer::InitializeGles() { glEnableVertexAttribArray(tc_location); glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); - - // We are getting called on a thread. Release the context so that it can be - // made current on the main thread. - // TODO(hclam): Fix this if neccessary. Currently the following call fails - // for some drivers. - // eglMakeCurrent(egl_display_, EGL_NO_SURFACE, - // EGL_NO_SURFACE, EGL_NO_CONTEXT); - return true; } |