diff options
author | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-22 20:30:46 +0000 |
---|---|---|
committer | piman@chromium.org <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-22 20:30:46 +0000 |
commit | d3a2888b46a75f14e2f2ca7b71467b2cdaad88af (patch) | |
tree | 7479703b7b3f1a43d85c430ced27e59942ee51dd /media | |
parent | d9a01e006460180d4b345d1444a46bc97a5f3102 (diff) | |
download | chromium_src-d3a2888b46a75f14e2f2ca7b71467b2cdaad88af.zip chromium_src-d3a2888b46a75f14e2f2ca7b71467b2cdaad88af.tar.gz chromium_src-d3a2888b46a75f14e2f2ca7b71467b2cdaad88af.tar.bz2 |
linux: add display option to media_bench, using GL
Review URL: http://codereview.chromium.org/523120
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36886 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/media.gyp | 3 | ||||
-rw-r--r-- | media/tools/player_x11/player_x11.cc | 2 | ||||
-rw-r--r-- | media/tools/player_x11/x11_video_renderer.cc | 342 | ||||
-rw-r--r-- | media/tools/player_x11/x11_video_renderer.h | 17 |
4 files changed, 310 insertions, 54 deletions
diff --git a/media/media.gyp b/media/media.gyp index e504d12..07d5271 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Copyright (c) 2010 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -354,6 +354,7 @@ 'dependencies': [ 'media', '../base/base.gyp:base', + '../gpu/gpu.gyp:gl_libs', ], 'link_settings': { 'libraries': [ diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc index 53aefea..7cba68f 100644 --- a/media/tools/player_x11/player_x11.cc +++ b/media/tools/player_x11/player_x11.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this // source code is governed by a BSD-style license that can be found in the // LICENSE file. diff --git a/media/tools/player_x11/x11_video_renderer.cc b/media/tools/player_x11/x11_video_renderer.cc index 4b0c45f..67c6c5c 100644 --- a/media/tools/player_x11/x11_video_renderer.cc +++ b/media/tools/player_x11/x11_video_renderer.cc @@ -1,9 +1,10 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/tools/player_x11/x11_video_renderer.h" +#include <dlfcn.h> #include <X11/Xutil.h> #include <X11/extensions/Xrender.h> #include <X11/extensions/Xcomposite.h> @@ -58,7 +59,9 @@ X11VideoRenderer::X11VideoRenderer(Display* display, Window window) image_(NULL), new_frame_(false), picture_(0), - use_render_(true) { + use_render_(false), + use_gl_(false), + gl_context_(NULL) { // Save the instance of the video renderer. CHECK(!instance_); instance_ = this; @@ -78,12 +81,128 @@ bool X11VideoRenderer::IsMediaFormatSupported( } void X11VideoRenderer::OnStop() { - XDestroyImage(image_); + if (use_gl_) { + glXMakeCurrent(display_, 0, NULL); + glXDestroyContext(display_, gl_context_); + } + if (image_) { + XDestroyImage(image_); + } if (use_render_) { XRenderFreePicture(display_, picture_); } } +static GLXContext InitGLContext(Display* display, Window window) { + // Some versions of NVIDIA's GL libGL.so include a broken version of + // dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically + // load it, and use glew to dynamically resolve symbols. + // See http://code.google.com/p/chromium/issues/detail?id=16800 + void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + LOG(ERROR) << "Could not find libGL.so.1"; + return NULL; + } + if (glxewInit() != GLEW_OK) { + LOG(ERROR) << "GLXEW failed initialization"; + return NULL; + } + + XWindowAttributes attributes; + XGetWindowAttributes(display, window, &attributes); + XVisualInfo visual_info_template; + visual_info_template.visualid = XVisualIDFromVisual(attributes.visual); + int visual_info_count = 0; + XVisualInfo* visual_info_list = XGetVisualInfo(display, VisualIDMask, + &visual_info_template, + &visual_info_count); + GLXContext context = NULL; + for (int i = 0; i < visual_info_count && !context; ++i) { + context = glXCreateContext(display, visual_info_list + i, 0, + True /* Direct rendering */); + } + + XFree(visual_info_list); + if (!context) { + return NULL; + } + + if (!glXMakeCurrent(display, window, context)) { + glXDestroyContext(display, context); + return NULL; + } + + if (glewInit() != GLEW_OK) { + LOG(ERROR) << "GLEW failed initialization"; + glXDestroyContext(display, context); + return NULL; + } + + if (!glewIsSupported("GL_VERSION_2_0")) { + LOG(ERROR) << "GL implementation doesn't support GL version 2.0"; + glXDestroyContext(display, context); + return NULL; + } + + return context; +} + +// Matrix used for the YUV to RGB conversion. +static const float kYUV2RGB[9] = { + 1.f, 0.f, 1.403f, + 1.f, -.344f, -.714f, + 1.f, 1.772f, 0.f, +}; + +// Vertices for a full screen quad. +static const float kVertices[8] = { + -1.f, 1.f, + -1.f, -1.f, + 1.f, 1.f, + 1.f, -1.f, +}; + +// Texture Coordinates mapping the entire texture. +static const float kTextureCoords[8] = { + 0, 0, + 0, 1, + 1, 0, + 1, 1, +}; + +// Pass-through vertex shader. +static const char kVertexShader[] = + "varying vec2 interp_tc;\n" + "\n" + "attribute vec4 in_pos;\n" + "attribute vec2 in_tc;\n" + "\n" + "void main() {\n" + " interp_tc = in_tc;\n" + " gl_Position = in_pos;\n" + "}\n"; + +// YUV to RGB pixel shader. Loads a pixel from each plane and pass through the +// matrix. +static const char kFragmentShader[] = + "varying vec2 interp_tc;\n" + "\n" + "uniform sampler2D y_tex;\n" + "uniform sampler2D u_tex;\n" + "uniform sampler2D v_tex;\n" + "uniform mat3 yuv2rgb;\n" + "\n" + "void main() {\n" + " float y = texture2D(y_tex, interp_tc).x;\n" + " float u = texture2D(u_tex, interp_tc).r - .5;\n" + " float v = texture2D(v_tex, interp_tc).r - .5;\n" + " vec3 rgb = yuv2rgb * vec3(y, u, v);\n" + " gl_FragColor = vec4(rgb, 1);\n" + "}\n"; + +// Buffer size for compile errors. +static const unsigned int kErrorSize = 4096; + bool X11VideoRenderer::OnInitialize(media::VideoDecoder* decoder) { if (!ParseMediaFormat(decoder->media_format(), &width_, &height_)) return false; @@ -91,39 +210,136 @@ bool X11VideoRenderer::OnInitialize(media::VideoDecoder* decoder) { // Resize the window to fit that of the video. XResizeWindow(display_, window_, width_, height_); - // Testing XRender support. We'll use the very basic of XRender - // so if it presents it is already good enough. We don't need - // to check its version. - int dummy; - use_render_ = XRenderQueryExtension(display_, &dummy, &dummy); - - if (use_render_) { - // If we are using XRender, we'll create a picture representing the - // window. - XWindowAttributes attr; - XGetWindowAttributes(display_, window_, &attr); - - XRenderPictFormat* pictformat = XRenderFindVisualFormat( - display_, - attr.visual); - CHECK(pictformat) << "XRENDER does not support default visual"; - - picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL); - CHECK(picture_) << "Backing picture not created"; - } - - // Initialize the XImage to store the output of YUV -> RGB conversion. - image_ = XCreateImage(display_, - DefaultVisual(display_, DefaultScreen(display_)), - DefaultDepth(display_, DefaultScreen(display_)), - ZPixmap, - 0, - static_cast<char*>(malloc(width_ * height_ * 4)), - width_, - height_, - 32, - width_ * 4); - DCHECK(image_); + gl_context_ = InitGLContext(display_, window_); + use_gl_ = (gl_context_ != NULL); + + if (use_gl_) { + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glViewport(0, 0, width_, height_); + + // Create 3 textures, one for each plane, and bind them to different + // texture units. + glGenTextures(media::VideoSurface::kNumYUVPlanes, textures_); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures_[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glEnable(GL_TEXTURE_2D); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textures_[1]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glEnable(GL_TEXTURE_2D); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, textures_[2]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glEnable(GL_TEXTURE_2D); + + 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_); + + 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_); + + 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_); + + // Bind parameters. + glUniform1i(glGetUniformLocation(program_, "y_tex"), 0); + glUniform1i(glGetUniformLocation(program_, "u_tex"), 1); + glUniform1i(glGetUniformLocation(program_, "v_tex"), 2); + int yuv2rgb_location = glGetUniformLocation(program_, "yuv2rgb"); + glUniformMatrix3fv(yuv2rgb_location, 1, GL_TRUE, kYUV2RGB); + + 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, + kTextureCoords); + + // We are getting called on a thread. Release the context so that it can be + // made current on the main thread. + glXMakeCurrent(display_, 0, NULL); + } else { + // Testing XRender support. We'll use the very basic of XRender + // so if it presents it is already good enough. We don't need + // to check its version. + int dummy; + use_render_ = XRenderQueryExtension(display_, &dummy, &dummy); + + if (use_render_) { + // If we are using XRender, we'll create a picture representing the + // window. + XWindowAttributes attr; + XGetWindowAttributes(display_, window_, &attr); + + XRenderPictFormat* pictformat = XRenderFindVisualFormat( + display_, + attr.visual); + CHECK(pictformat) << "XRENDER does not support default visual"; + + picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL); + CHECK(picture_) << "Backing picture not created"; + } + + // Initialize the XImage to store the output of YUV -> RGB conversion. + image_ = XCreateImage(display_, + DefaultVisual(display_, DefaultScreen(display_)), + DefaultDepth(display_, DefaultScreen(display_)), + ZPixmap, + 0, + static_cast<char*>(malloc(width_ * height_ * 4)), + width_, + height_, + 32, + width_ * 4); + DCHECK(image_); + } return true; } @@ -147,7 +363,7 @@ void X11VideoRenderer::Paint() { scoped_refptr<media::VideoFrame> video_frame; GetCurrentFrame(&video_frame); - if (!image_ || !video_frame) + if ((!use_gl_ && !image_) || !video_frame) return; // Convert YUV frame to RGB. @@ -158,25 +374,49 @@ void X11VideoRenderer::Paint() { DCHECK(frame_in.strides[media::VideoSurface::kUPlane] == frame_in.strides[media::VideoSurface::kVPlane]); DCHECK(frame_in.planes == media::VideoSurface::kNumYUVPlanes); - DCHECK(image_->data); - - media::YUVType yuv_type = (frame_in.format == media::VideoSurface::YV12) ? - media::YV12 : media::YV16; - media::ConvertYUVToRGB32(frame_in.data[media::VideoSurface::kYPlane], - frame_in.data[media::VideoSurface::kUPlane], - frame_in.data[media::VideoSurface::kVPlane], - (uint8*)image_->data, - frame_in.width, - frame_in.height, - frame_in.strides[media::VideoSurface::kYPlane], - frame_in.strides[media::VideoSurface::kUPlane], - image_->bytes_per_line, - yuv_type); + + if (use_gl_) { + if (glXGetCurrentContext() != gl_context_ || + glXGetCurrentDrawable() != window_) { + glXMakeCurrent(display_, window_, gl_context_); + } + for (unsigned int i = 0; i < media::VideoSurface::kNumYUVPlanes; ++i) { + unsigned int width = (i == media::VideoSurface::kYPlane) ? + frame_in.width : frame_in.width / 2; + unsigned int height = (i == media::VideoSurface::kYPlane || + frame_in.format == media::VideoSurface::YV16) ? + frame_in.height : frame_in.height / 2; + glActiveTexture(GL_TEXTURE0 + i); + glPixelStorei(GL_UNPACK_ROW_LENGTH, frame_in.strides[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, frame_in.data[i]); + } + } else { + DCHECK(image_->data); + media::YUVType yuv_type = (frame_in.format == media::VideoSurface::YV12) ? + media::YV12 : media::YV16; + media::ConvertYUVToRGB32(frame_in.data[media::VideoSurface::kYPlane], + frame_in.data[media::VideoSurface::kUPlane], + frame_in.data[media::VideoSurface::kVPlane], + (uint8*)image_->data, + frame_in.width, + frame_in.height, + frame_in.strides[media::VideoSurface::kYPlane], + frame_in.strides[media::VideoSurface::kUPlane], + image_->bytes_per_line, + yuv_type); + } video_frame->Unlock(); } else { NOTREACHED(); } + if (use_gl_) { + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glXSwapBuffers(display_, window_); + return; + } + if (use_render_) { // If XRender is used, we'll upload the image to a pixmap. And then // creats a picture from the pixmap and composite the picture over diff --git a/media/tools/player_x11/x11_video_renderer.h b/media/tools/player_x11/x11_video_renderer.h index 68d7c29..ed94e6d 100644 --- a/media/tools/player_x11/x11_video_renderer.h +++ b/media/tools/player_x11/x11_video_renderer.h @@ -1,10 +1,12 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this // source code is governed by a BSD-style license that can be found in the // LICENSE file. #ifndef MEDIA_TOOLS_PLAYER_X11_X11_VIDEO_RENDERER_H_ #define MEDIA_TOOLS_PLAYER_X11_X11_VIDEO_RENDERER_H_ +#include <GL/glew.h> +#include <GL/glxew.h> #include <X11/Xlib.h> #include "base/lock.h" @@ -62,6 +64,19 @@ class X11VideoRenderer : public media::VideoRendererBase { bool use_render_; + bool use_gl_; + + // GL context. + GLXContext gl_context_; + + // 3 textures, one for each plane. + GLuint textures_[3]; + + // Shaders and program for YUV->RGB conversion. + GLuint vertex_shader_; + GLuint fragment_shader_; + GLuint program_; + static X11VideoRenderer* instance_; DISALLOW_COPY_AND_ASSIGN(X11VideoRenderer); |