Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(625)

Side by Side Diff: media/tools/player_x11/x11_video_renderer.cc

Issue 596055: Implement GLES video renderer in player_x11 (Closed)
Patch Set: nits fixed Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/tools/player_x11/x11_video_renderer.h" 5 #include "media/tools/player_x11/x11_video_renderer.h"
6 6
7 #include <dlfcn.h> 7 #include <dlfcn.h>
8 #include <X11/Xutil.h> 8 #include <X11/Xutil.h>
9 #include <X11/extensions/Xrender.h> 9 #include <X11/extensions/Xrender.h>
10 #include <X11/extensions/Xcomposite.h> 10 #include <X11/extensions/Xcomposite.h>
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 52
53 return pictformat; 53 return pictformat;
54 } 54 }
55 55
56 X11VideoRenderer::X11VideoRenderer(Display* display, Window window) 56 X11VideoRenderer::X11VideoRenderer(Display* display, Window window)
57 : display_(display), 57 : display_(display),
58 window_(window), 58 window_(window),
59 image_(NULL), 59 image_(NULL),
60 new_frame_(false), 60 new_frame_(false),
61 picture_(0), 61 picture_(0),
62 use_render_(false), 62 use_render_(false) {
63 use_gl_(false),
64 gl_context_(NULL) {
65 // Save the instance of the video renderer.
66 CHECK(!instance_);
67 instance_ = this;
68 } 63 }
69 64
70 X11VideoRenderer::~X11VideoRenderer() { 65 X11VideoRenderer::~X11VideoRenderer() {
71 CHECK(instance_);
72 instance_ = NULL;
73 } 66 }
74 67
75 // static 68 // static
76 bool X11VideoRenderer::IsMediaFormatSupported( 69 bool X11VideoRenderer::IsMediaFormatSupported(
77 const media::MediaFormat& media_format) { 70 const media::MediaFormat& media_format) {
78 int width = 0; 71 int width = 0;
79 int height = 0; 72 int height = 0;
80 return ParseMediaFormat(media_format, &width, &height); 73 return ParseMediaFormat(media_format, &width, &height);
81 } 74 }
82 75
83 void X11VideoRenderer::OnStop() { 76 void X11VideoRenderer::OnStop() {
84 if (use_gl_) {
85 glXMakeCurrent(display_, 0, NULL);
86 glXDestroyContext(display_, gl_context_);
87 }
88 if (image_) { 77 if (image_) {
89 XDestroyImage(image_); 78 XDestroyImage(image_);
90 } 79 }
91 if (use_render_) { 80 XRenderFreePicture(display_, picture_);
92 XRenderFreePicture(display_, picture_);
93 }
94 } 81 }
95 82
96 static GLXContext InitGLContext(Display* display, Window window) {
97 // Some versions of NVIDIA's GL libGL.so include a broken version of
98 // dlopen/dlsym, and so linking it into chrome breaks it. So we dynamically
99 // load it, and use glew to dynamically resolve symbols.
100 // See http://code.google.com/p/chromium/issues/detail?id=16800
101 void* handle = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
102 if (!handle) {
103 LOG(ERROR) << "Could not find libGL.so.1";
104 return NULL;
105 }
106 if (glxewInit() != GLEW_OK) {
107 LOG(ERROR) << "GLXEW failed initialization";
108 return NULL;
109 }
110
111 XWindowAttributes attributes;
112 XGetWindowAttributes(display, window, &attributes);
113 XVisualInfo visual_info_template;
114 visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
115 int visual_info_count = 0;
116 XVisualInfo* visual_info_list = XGetVisualInfo(display, VisualIDMask,
117 &visual_info_template,
118 &visual_info_count);
119 GLXContext context = NULL;
120 for (int i = 0; i < visual_info_count && !context; ++i) {
121 context = glXCreateContext(display, visual_info_list + i, 0,
122 True /* Direct rendering */);
123 }
124
125 XFree(visual_info_list);
126 if (!context) {
127 return NULL;
128 }
129
130 if (!glXMakeCurrent(display, window, context)) {
131 glXDestroyContext(display, context);
132 return NULL;
133 }
134
135 if (glewInit() != GLEW_OK) {
136 LOG(ERROR) << "GLEW failed initialization";
137 glXDestroyContext(display, context);
138 return NULL;
139 }
140
141 if (!glewIsSupported("GL_VERSION_2_0")) {
142 LOG(ERROR) << "GL implementation doesn't support GL version 2.0";
143 glXDestroyContext(display, context);
144 return NULL;
145 }
146
147 return context;
148 }
149
150 // Matrix used for the YUV to RGB conversion.
151 static const float kYUV2RGB[9] = {
152 1.f, 0.f, 1.403f,
153 1.f, -.344f, -.714f,
154 1.f, 1.772f, 0.f,
155 };
156
157 // Vertices for a full screen quad.
158 static const float kVertices[8] = {
159 -1.f, 1.f,
160 -1.f, -1.f,
161 1.f, 1.f,
162 1.f, -1.f,
163 };
164
165 // Texture Coordinates mapping the entire texture.
166 static const float kTextureCoords[8] = {
167 0, 0,
168 0, 1,
169 1, 0,
170 1, 1,
171 };
172
173 // Pass-through vertex shader.
174 static const char kVertexShader[] =
175 "varying vec2 interp_tc;\n"
176 "\n"
177 "attribute vec4 in_pos;\n"
178 "attribute vec2 in_tc;\n"
179 "\n"
180 "void main() {\n"
181 " interp_tc = in_tc;\n"
182 " gl_Position = in_pos;\n"
183 "}\n";
184
185 // YUV to RGB pixel shader. Loads a pixel from each plane and pass through the
186 // matrix.
187 static const char kFragmentShader[] =
188 "varying vec2 interp_tc;\n"
189 "\n"
190 "uniform sampler2D y_tex;\n"
191 "uniform sampler2D u_tex;\n"
192 "uniform sampler2D v_tex;\n"
193 "uniform mat3 yuv2rgb;\n"
194 "\n"
195 "void main() {\n"
196 " float y = texture2D(y_tex, interp_tc).x;\n"
197 " float u = texture2D(u_tex, interp_tc).r - .5;\n"
198 " float v = texture2D(v_tex, interp_tc).r - .5;\n"
199 " vec3 rgb = yuv2rgb * vec3(y, u, v);\n"
200 " gl_FragColor = vec4(rgb, 1);\n"
201 "}\n";
202
203 // Buffer size for compile errors.
204 static const unsigned int kErrorSize = 4096;
205
206 bool X11VideoRenderer::OnInitialize(media::VideoDecoder* decoder) { 83 bool X11VideoRenderer::OnInitialize(media::VideoDecoder* decoder) {
207 if (!ParseMediaFormat(decoder->media_format(), &width_, &height_)) 84 if (!ParseMediaFormat(decoder->media_format(), &width_, &height_))
208 return false; 85 return false;
209 86
87 LOG(INFO) << "Initializing X11 Renderer...";
88
210 // Resize the window to fit that of the video. 89 // Resize the window to fit that of the video.
211 XResizeWindow(display_, window_, width_, height_); 90 XResizeWindow(display_, window_, width_, height_);
212 91
213 gl_context_ = InitGLContext(display_, window_); 92 // Testing XRender support. We'll use the very basic of XRender
214 use_gl_ = (gl_context_ != NULL); 93 // so if it presents it is already good enough. We don't need
94 // to check its version.
95 int dummy;
96 use_render_ = XRenderQueryExtension(display_, &dummy, &dummy);
215 97
216 if (use_gl_) { 98 if (use_render_) {
217 glMatrixMode(GL_MODELVIEW); 99 // If we are using XRender, we'll create a picture representing the
218 glLoadIdentity(); 100 // window.
219 glViewport(0, 0, width_, height_); 101 XWindowAttributes attr;
102 XGetWindowAttributes(display_, window_, &attr);
220 103
221 // Create 3 textures, one for each plane, and bind them to different 104 XRenderPictFormat* pictformat = XRenderFindVisualFormat(
222 // texture units. 105 display_,
223 glGenTextures(media::VideoSurface::kNumYUVPlanes, textures_); 106 attr.visual);
224 glActiveTexture(GL_TEXTURE0); 107 CHECK(pictformat) << "XRENDER does not support default visual";
225 glBindTexture(GL_TEXTURE_2D, textures_[0]);
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
228 glEnable(GL_TEXTURE_2D);
229 108
230 glActiveTexture(GL_TEXTURE1); 109 picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL);
231 glBindTexture(GL_TEXTURE_2D, textures_[1]); 110 CHECK(picture_) << "Backing picture not created";
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 111 }
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
234 glEnable(GL_TEXTURE_2D);
235 112
236 glActiveTexture(GL_TEXTURE2); 113 // Initialize the XImage to store the output of YUV -> RGB conversion.
237 glBindTexture(GL_TEXTURE_2D, textures_[2]); 114 image_ = XCreateImage(display_,
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 115 DefaultVisual(display_, DefaultScreen(display_)),
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 116 DefaultDepth(display_, DefaultScreen(display_)),
240 glEnable(GL_TEXTURE_2D); 117 ZPixmap,
118 0,
119 static_cast<char*>(malloc(width_ * height_ * 4)),
120 width_,
121 height_,
122 32,
123 width_ * 4);
124 DCHECK(image_);
241 125
242 GLuint program_ = glCreateProgram(); 126 // Save this instance.
243 127 DCHECK(!instance_);
244 // Create our YUV->RGB shader. 128 instance_ = this;
245 GLuint vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
246 const char* vs_source = kVertexShader;
247 int vs_size = sizeof(kVertexShader);
248 glShaderSource(vertex_shader_, 1, &vs_source, &vs_size);
249 glCompileShader(vertex_shader_);
250 int result = GL_FALSE;
251 glGetShaderiv(vertex_shader_, GL_COMPILE_STATUS, &result);
252 if (!result) {
253 char log[kErrorSize];
254 int len;
255 glGetShaderInfoLog(vertex_shader_, kErrorSize - 1, &len, log);
256 log[kErrorSize - 1] = 0;
257 LOG(FATAL) << log;
258 }
259 glAttachShader(program_, vertex_shader_);
260
261 GLuint fragment_shader_ = glCreateShader(GL_FRAGMENT_SHADER);
262 const char* ps_source = kFragmentShader;
263 int ps_size = sizeof(kFragmentShader);
264 glShaderSource(fragment_shader_, 1, &ps_source, &ps_size);
265 glCompileShader(fragment_shader_);
266 result = GL_FALSE;
267 glGetShaderiv(fragment_shader_, GL_COMPILE_STATUS, &result);
268 if (!result) {
269 char log[kErrorSize];
270 int len;
271 glGetShaderInfoLog(fragment_shader_, kErrorSize - 1, &len, log);
272 log[kErrorSize - 1] = 0;
273 LOG(FATAL) << log;
274 }
275 glAttachShader(program_, fragment_shader_);
276
277 glLinkProgram(program_);
278 result = GL_FALSE;
279 glGetProgramiv(program_, GL_LINK_STATUS, &result);
280 if (!result) {
281 char log[kErrorSize];
282 int len;
283 glGetProgramInfoLog(program_, kErrorSize - 1, &len, log);
284 log[kErrorSize - 1] = 0;
285 LOG(FATAL) << log;
286 }
287 glUseProgram(program_);
288
289 // Bind parameters.
290 glUniform1i(glGetUniformLocation(program_, "y_tex"), 0);
291 glUniform1i(glGetUniformLocation(program_, "u_tex"), 1);
292 glUniform1i(glGetUniformLocation(program_, "v_tex"), 2);
293 int yuv2rgb_location = glGetUniformLocation(program_, "yuv2rgb");
294 glUniformMatrix3fv(yuv2rgb_location, 1, GL_TRUE, kYUV2RGB);
295
296 int pos_location = glGetAttribLocation(program_, "in_pos");
297 glEnableVertexAttribArray(pos_location);
298 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
299
300 int tc_location = glGetAttribLocation(program_, "in_tc");
301 glEnableVertexAttribArray(tc_location);
302 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
303 kTextureCoords);
304
305 // We are getting called on a thread. Release the context so that it can be
306 // made current on the main thread.
307 glXMakeCurrent(display_, 0, NULL);
308 } else {
309 // Testing XRender support. We'll use the very basic of XRender
310 // so if it presents it is already good enough. We don't need
311 // to check its version.
312 int dummy;
313 use_render_ = XRenderQueryExtension(display_, &dummy, &dummy);
314
315 if (use_render_) {
316 // If we are using XRender, we'll create a picture representing the
317 // window.
318 XWindowAttributes attr;
319 XGetWindowAttributes(display_, window_, &attr);
320
321 XRenderPictFormat* pictformat = XRenderFindVisualFormat(
322 display_,
323 attr.visual);
324 CHECK(pictformat) << "XRENDER does not support default visual";
325
326 picture_ = XRenderCreatePicture(display_, window_, pictformat, 0, NULL);
327 CHECK(picture_) << "Backing picture not created";
328 }
329
330 // Initialize the XImage to store the output of YUV -> RGB conversion.
331 image_ = XCreateImage(display_,
332 DefaultVisual(display_, DefaultScreen(display_)),
333 DefaultDepth(display_, DefaultScreen(display_)),
334 ZPixmap,
335 0,
336 static_cast<char*>(malloc(width_ * height_ * 4)),
337 width_,
338 height_,
339 32,
340 width_ * 4);
341 DCHECK(image_);
342 }
343 return true; 129 return true;
344 } 130 }
345 131
346 void X11VideoRenderer::OnFrameAvailable() { 132 void X11VideoRenderer::OnFrameAvailable() {
347 AutoLock auto_lock(lock_); 133 AutoLock auto_lock(lock_);
348 new_frame_ = true; 134 new_frame_ = true;
349 } 135 }
350 136
351 void X11VideoRenderer::Paint() { 137 void X11VideoRenderer::Paint() {
352 // Use |new_frame_| to prevent overdraw since Paint() is called more 138 // Use |new_frame_| to prevent overdraw since Paint() is called more
353 // often than needed. It is OK to lock only this flag and we don't 139 // often than needed. It is OK to lock only this flag and we don't
354 // want to lock the whole function because this method takes a long 140 // want to lock the whole function because this method takes a long
355 // time to complete. 141 // time to complete.
356 { 142 {
357 AutoLock auto_lock(lock_); 143 AutoLock auto_lock(lock_);
358 if (!new_frame_) 144 if (!new_frame_)
359 return; 145 return;
360 new_frame_ = false; 146 new_frame_ = false;
361 } 147 }
362 148
363 scoped_refptr<media::VideoFrame> video_frame; 149 scoped_refptr<media::VideoFrame> video_frame;
364 GetCurrentFrame(&video_frame); 150 GetCurrentFrame(&video_frame);
365 151
366 if ((!use_gl_ && !image_) || !video_frame) 152 if (!image_ ||!video_frame)
367 return; 153 return;
368 154
369 // Convert YUV frame to RGB. 155 // Convert YUV frame to RGB.
370 media::VideoSurface frame_in; 156 media::VideoSurface frame_in;
371 if (video_frame->Lock(&frame_in)) { 157 if (video_frame->Lock(&frame_in)) {
372 DCHECK(frame_in.format == media::VideoSurface::YV12 || 158 DCHECK(frame_in.format == media::VideoSurface::YV12 ||
373 frame_in.format == media::VideoSurface::YV16); 159 frame_in.format == media::VideoSurface::YV16);
374 DCHECK(frame_in.strides[media::VideoSurface::kUPlane] == 160 DCHECK(frame_in.strides[media::VideoSurface::kUPlane] ==
375 frame_in.strides[media::VideoSurface::kVPlane]); 161 frame_in.strides[media::VideoSurface::kVPlane]);
376 DCHECK(frame_in.planes == media::VideoSurface::kNumYUVPlanes); 162 DCHECK(frame_in.planes == media::VideoSurface::kNumYUVPlanes);
377 163
378 if (use_gl_) { 164 DCHECK(image_->data);
379 if (glXGetCurrentContext() != gl_context_ || 165 media::YUVType yuv_type = (frame_in.format == media::VideoSurface::YV12) ?
380 glXGetCurrentDrawable() != window_) { 166 media::YV12 : media::YV16;
381 glXMakeCurrent(display_, window_, gl_context_); 167 media::ConvertYUVToRGB32(frame_in.data[media::VideoSurface::kYPlane],
382 } 168 frame_in.data[media::VideoSurface::kUPlane],
383 for (unsigned int i = 0; i < media::VideoSurface::kNumYUVPlanes; ++i) { 169 frame_in.data[media::VideoSurface::kVPlane],
384 unsigned int width = (i == media::VideoSurface::kYPlane) ? 170 (uint8*)image_->data,
385 frame_in.width : frame_in.width / 2; 171 frame_in.width,
386 unsigned int height = (i == media::VideoSurface::kYPlane || 172 frame_in.height,
387 frame_in.format == media::VideoSurface::YV16) ? 173 frame_in.strides[media::VideoSurface::kYPlane],
388 frame_in.height : frame_in.height / 2; 174 frame_in.strides[media::VideoSurface::kUPlane],
389 glActiveTexture(GL_TEXTURE0 + i); 175 image_->bytes_per_line,
390 glPixelStorei(GL_UNPACK_ROW_LENGTH, frame_in.strides[i]); 176 yuv_type);
391 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0,
392 GL_LUMINANCE, GL_UNSIGNED_BYTE, frame_in.data[i]);
393 }
394 } else {
395 DCHECK(image_->data);
396 media::YUVType yuv_type = (frame_in.format == media::VideoSurface::YV12) ?
397 media::YV12 : media::YV16;
398 media::ConvertYUVToRGB32(frame_in.data[media::VideoSurface::kYPlane],
399 frame_in.data[media::VideoSurface::kUPlane],
400 frame_in.data[media::VideoSurface::kVPlane],
401 (uint8*)image_->data,
402 frame_in.width,
403 frame_in.height,
404 frame_in.strides[media::VideoSurface::kYPlane],
405 frame_in.strides[media::VideoSurface::kUPlane],
406 image_->bytes_per_line,
407 yuv_type);
408 }
409 video_frame->Unlock(); 177 video_frame->Unlock();
410 } else { 178 } else {
411 NOTREACHED(); 179 NOTREACHED();
412 } 180 }
413 181
414 if (use_gl_) {
415 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
416 glXSwapBuffers(display_, window_);
417 return;
418 }
419
420 if (use_render_) { 182 if (use_render_) {
421 // If XRender is used, we'll upload the image to a pixmap. And then 183 // If XRender is used, we'll upload the image to a pixmap. And then
422 // creats a picture from the pixmap and composite the picture over 184 // creats a picture from the pixmap and composite the picture over
423 // the picture represending the window. 185 // the picture represending the window.
424 186
425 // Creates a XImage. 187 // Creates a XImage.
426 XImage image; 188 XImage image;
427 memset(&image, 0, sizeof(image)); 189 memset(&image, 0, sizeof(image));
428 image.width = width_; 190 image.width = width_;
429 image.height = height_; 191 image.height = height_;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 // If XRender is not used, simply put the image to the server. 230 // If XRender is not used, simply put the image to the server.
469 // This will have a tearing effect but this is OK. 231 // This will have a tearing effect but this is OK.
470 // TODO(hclam): Upload the image to a pixmap and do XCopyArea() 232 // TODO(hclam): Upload the image to a pixmap and do XCopyArea()
471 // to the window. 233 // to the window.
472 GC gc = XCreateGC(display_, window_, 0, NULL); 234 GC gc = XCreateGC(display_, window_, 0, NULL);
473 XPutImage(display_, window_, gc, image_, 235 XPutImage(display_, window_, gc, image_,
474 0, 0, 0, 0, width_, height_); 236 0, 0, 0, 0, width_, height_);
475 XFlush(display_); 237 XFlush(display_);
476 XFreeGC(display_, gc); 238 XFreeGC(display_, gc);
477 } 239 }
OLDNEW
« media/tools/player_x11/x11_video_renderer.h ('K') | « media/tools/player_x11/x11_video_renderer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698