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

Side by Side Diff: media/tools/player_x11/gles_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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "media/tools/player_x11/gles_video_renderer.h"
6
7 #include <dlfcn.h>
8 #include <X11/Xutil.h>
9 #include <X11/extensions/Xrender.h>
10 #include <X11/extensions/Xcomposite.h>
11
12 #include "media/base/buffers.h"
13 #include "media/base/yuv_convert.h"
14
15 GlesVideoRenderer* GlesVideoRenderer::instance_ = NULL;
16
17 GlesVideoRenderer::GlesVideoRenderer(Display* display, Window window)
18 : display_(display),
19 window_(window),
20 new_frame_(false),
21 egl_display_(NULL),
22 egl_surface_(NULL),
23 egl_context_(NULL) {
24 }
25
26 GlesVideoRenderer::~GlesVideoRenderer() {
27 }
28
29 // static
30 bool GlesVideoRenderer::IsMediaFormatSupported(
31 const media::MediaFormat& media_format) {
32 int width = 0;
33 int height = 0;
34 return ParseMediaFormat(media_format, &width, &height);
35 }
36
37 void GlesVideoRenderer::OnStop() {
38 eglMakeCurrent(egl_display_, EGL_NO_SURFACE,
39 EGL_NO_SURFACE, EGL_NO_CONTEXT);
40 eglDestroyContext(egl_display_, egl_context_);
41 eglDestroySurface(egl_display_, egl_surface_);
42 }
43
44 // Matrix used for the YUV to RGB conversion.
45 static const float kYUV2RGB[9] = {
46 1.f, 0.f, 1.403f,
47 1.f, -.344f, -.714f,
48 1.f, 1.772f, 0.f,
49 };
50
51 // Vertices for a full screen quad.
52 static const float kVertices[8] = {
53 -1.f, 1.f,
54 -1.f, -1.f,
55 1.f, 1.f,
56 1.f, -1.f,
57 };
58
59 // Texture Coordinates mapping the entire texture.
60 static const float kTextureCoords[8] = {
61 0, 0,
62 0, 1,
63 1, 0,
64 1, 1,
65 };
66
67 // Pass-through vertex shader.
68 static const char kVertexShader[] =
69 "precision highp float; precision highp int;\n"
70 "varying vec2 interp_tc;\n"
71 "\n"
72 "attribute vec4 in_pos;\n"
73 "attribute vec2 in_tc;\n"
74 "\n"
75 "void main() {\n"
76 " interp_tc = in_tc;\n"
77 " gl_Position = in_pos;\n"
78 "}\n";
79
80 // YUV to RGB pixel shader. Loads a pixel from each plane and pass through the
81 // matrix.
82 static const char kFragmentShader[] =
83 "precision mediump float; precision mediump int;\n"
84 "varying vec2 interp_tc;\n"
85 "\n"
86 "uniform sampler2D y_tex;\n"
87 "uniform sampler2D u_tex;\n"
88 "uniform sampler2D v_tex;\n"
89 "uniform mat3 yuv2rgb;\n"
90 "\n"
91 "void main() {\n"
92 " float y = texture2D(y_tex, interp_tc).x;\n"
93 " float u = texture2D(u_tex, interp_tc).r - .5;\n"
94 " float v = texture2D(v_tex, interp_tc).r - .5;\n"
95 " vec3 rgb = yuv2rgb * vec3(y, u, v);\n"
96 " gl_FragColor = vec4(rgb, 1);\n"
97 "}\n";
98
99 // Buffer size for compile errors.
100 static const unsigned int kErrorSize = 4096;
101
102 bool GlesVideoRenderer::OnInitialize(media::VideoDecoder* decoder) {
103 if (!ParseMediaFormat(decoder->media_format(), &width_, &height_))
104 return false;
105
106 LOG(INFO) << "Initializing GLES Renderer...";
107
108 // Resize the window to fit that of the video.
109 XResizeWindow(display_, window_, width_, height_);
110
111 egl_display_ = eglGetDisplay(display_);
112 if (eglGetError() != EGL_SUCCESS) {
113 DLOG(ERROR) << "eglGetDisplay failed.";
114 return false;
115 }
116
117 EGLint major;
118 EGLint minor;
119 if (!eglInitialize(egl_display_, &major, &minor)) {
120 DLOG(ERROR) << "eglInitialize failed.";
121 return false;
122 }
123 DLOG(INFO) << "EGL vendor:" << eglQueryString(egl_display_, EGL_VENDOR);
124 DLOG(INFO) << "EGL version:" << eglQueryString(egl_display_, EGL_VERSION);
125 DLOG(INFO) << "EGL extensions:"
126 << eglQueryString(egl_display_, EGL_EXTENSIONS);
127 DLOG(INFO) << "EGL client apis:"
128 << eglQueryString(egl_display_, EGL_CLIENT_APIS);
129
130 EGLint attribs[] = {
131 EGL_RED_SIZE, 5,
132 EGL_GREEN_SIZE, 6,
133 EGL_BLUE_SIZE, 5,
134 EGL_DEPTH_SIZE, 16,
135 EGL_STENCIL_SIZE, 0,
136 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
137 EGL_NONE
138 };
139
140 EGLint num_configs = -1;
141 if (!eglGetConfigs(egl_display_, NULL, 0, &num_configs)) {
142 DLOG(ERROR) << "eglGetConfigs failed.";
143 return false;
144 }
145
146 EGLConfig config;
147 if (!eglChooseConfig(egl_display_, attribs, &config, 1, &num_configs)) {
148 DLOG(ERROR) << "eglChooseConfig failed.";
149 return false;
150 }
151
152 EGLint red_size, green_size, blue_size, alpha_size, depth_size, stencil_size;
153 eglGetConfigAttrib(egl_display_, config, EGL_RED_SIZE, &red_size);
154 eglGetConfigAttrib(egl_display_, config, EGL_GREEN_SIZE, &green_size);
155 eglGetConfigAttrib(egl_display_, config, EGL_BLUE_SIZE, &blue_size);
156 eglGetConfigAttrib(egl_display_, config, EGL_ALPHA_SIZE, &alpha_size);
157 eglGetConfigAttrib(egl_display_, config, EGL_DEPTH_SIZE, &depth_size);
158 eglGetConfigAttrib(egl_display_, config, EGL_STENCIL_SIZE, &stencil_size);
159 DLOG(INFO) << "R,G,B,A: " << red_size << "," << green_size
160 << "," << blue_size << "," << alpha_size << " bits";
161 DLOG(INFO) << "Depth: " << depth_size << " bits, Stencil:" << stencil_size
162 << "bits";
163
164 egl_surface_ = eglCreateWindowSurface(egl_display_, config, window_, NULL);
165 if (!egl_surface_) {
166 DLOG(ERROR) << "eglCreateWindowSurface failed.";
167 return false;
168 }
169
170 egl_context_ = eglCreateContext(egl_display_, config, NULL, NULL);
171 if (!egl_context_) {
172 DLOG(ERROR) << "eglCreateContext failed.";
173 eglDestroySurface(egl_display_, egl_surface_);
174 return false;
175 }
176
177 if (eglMakeCurrent(egl_display_, egl_surface_,
178 egl_surface_, egl_context_) == EGL_FALSE) {
179 eglDestroyContext(egl_display_, egl_context_);
180 eglDestroySurface(egl_display_, egl_surface_);
181 egl_display_ = NULL;
182 egl_surface_ = NULL;
183 egl_context_ = NULL;
184 return false;
185 }
186
187 EGLint width;
188 EGLint height;
189 eglQuerySurface(egl_display_, egl_surface_, EGL_WIDTH, &width);
190 eglQuerySurface(egl_display_, egl_surface_, EGL_HEIGHT, &height);
191 glViewport(0, 0, width, height);
192
193 glViewport(0, 0, width_, height_);
194
195 // Create 3 textures, one for each plane, and bind them to different
196 // texture units.
197 glGenTextures(media::VideoSurface::kNumYUVPlanes, textures_);
198 glActiveTexture(GL_TEXTURE0);
199 glBindTexture(GL_TEXTURE_2D, textures_[0]);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
202 glEnable(GL_TEXTURE_2D);
203
204 glActiveTexture(GL_TEXTURE1);
205 glBindTexture(GL_TEXTURE_2D, textures_[1]);
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
208 glEnable(GL_TEXTURE_2D);
209
210 glActiveTexture(GL_TEXTURE2);
211 glBindTexture(GL_TEXTURE_2D, textures_[2]);
212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
214 glEnable(GL_TEXTURE_2D);
215
216 GLuint program_ = glCreateProgram();
217
218 // Create our YUV->RGB shader.
219 GLuint vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
220 const char* vs_source = kVertexShader;
221 int vs_size = sizeof(kVertexShader);
222 glShaderSource(vertex_shader_, 1, &vs_source, &vs_size);
223 glCompileShader(vertex_shader_);
224 int result = GL_FALSE;
225 glGetShaderiv(vertex_shader_, GL_COMPILE_STATUS, &result);
226 if (!result) {
227 char log[kErrorSize];
228 int len;
229 glGetShaderInfoLog(vertex_shader_, kErrorSize - 1, &len, log);
230 log[kErrorSize - 1] = 0;
231 LOG(FATAL) << log;
232 }
233 glAttachShader(program_, vertex_shader_);
234
235 GLuint fragment_shader_ = glCreateShader(GL_FRAGMENT_SHADER);
236 const char* ps_source = kFragmentShader;
237 int ps_size = sizeof(kFragmentShader);
238 glShaderSource(fragment_shader_, 1, &ps_source, &ps_size);
239 glCompileShader(fragment_shader_);
240 result = GL_FALSE;
241 glGetShaderiv(fragment_shader_, GL_COMPILE_STATUS, &result);
242 if (!result) {
243 char log[kErrorSize];
244 int len;
245 glGetShaderInfoLog(fragment_shader_, kErrorSize - 1, &len, log);
246 log[kErrorSize - 1] = 0;
247 LOG(FATAL) << log;
248 }
249 glAttachShader(program_, fragment_shader_);
250
251 glLinkProgram(program_);
252 result = GL_FALSE;
253 glGetProgramiv(program_, GL_LINK_STATUS, &result);
254 if (!result) {
255 char log[kErrorSize];
256 int len;
257 glGetProgramInfoLog(program_, kErrorSize - 1, &len, log);
258 log[kErrorSize - 1] = 0;
259 LOG(FATAL) << log;
260 }
261 glUseProgram(program_);
262
263 // Bind parameters.
264 glUniform1i(glGetUniformLocation(program_, "y_tex"), 0);
265 glUniform1i(glGetUniformLocation(program_, "u_tex"), 1);
266 glUniform1i(glGetUniformLocation(program_, "v_tex"), 2);
267 int yuv2rgb_location = glGetUniformLocation(program_, "yuv2rgb");
268 glUniformMatrix3fv(yuv2rgb_location, 1, GL_TRUE, kYUV2RGB);
269
270 int pos_location = glGetAttribLocation(program_, "in_pos");
271 glEnableVertexAttribArray(pos_location);
272 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
273
274 int tc_location = glGetAttribLocation(program_, "in_tc");
275 glEnableVertexAttribArray(tc_location);
276 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
277 kTextureCoords);
278
279 // We are getting called on a thread. Release the context so that it can be
280 // made current on the main thread.
281 eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
282
283 // Save this instance.
284 DCHECK(!instance_);
285 instance_ = this;
286 return true;
287 }
288
289 void GlesVideoRenderer::OnFrameAvailable() {
290 AutoLock auto_lock(lock_);
291 new_frame_ = true;
292 }
293
294 void GlesVideoRenderer::Paint() {
295 // Use |new_frame_| to prevent overdraw since Paint() is called more
296 // often than needed. It is OK to lock only this flag and we don't
297 // want to lock the whole function because this method takes a long
298 // time to complete.
299 {
300 AutoLock auto_lock(lock_);
301 if (!new_frame_)
302 return;
303 new_frame_ = false;
304 }
305
306 scoped_refptr<media::VideoFrame> video_frame;
307 GetCurrentFrame(&video_frame);
308
309 if (!video_frame)
310 return;
311
312 // Convert YUV frame to RGB.
313 media::VideoSurface frame_in;
314 if (video_frame->Lock(&frame_in)) {
315 DCHECK(frame_in.format == media::VideoSurface::YV12 ||
316 frame_in.format == media::VideoSurface::YV16);
317 DCHECK(frame_in.strides[media::VideoSurface::kUPlane] ==
318 frame_in.strides[media::VideoSurface::kVPlane]);
319 DCHECK(frame_in.planes == media::VideoSurface::kNumYUVPlanes);
320
321 if (eglGetCurrentContext() != egl_context_) {
322 eglMakeCurrent(egl_display_, egl_surface_,
323 egl_surface_, egl_context_);
324 }
325 for (unsigned int i = 0; i < media::VideoSurface::kNumYUVPlanes; ++i) {
326 unsigned int width = (i == media::VideoSurface::kYPlane) ?
327 frame_in.width : frame_in.width / 2;
328 unsigned int height = (i == media::VideoSurface::kYPlane ||
329 frame_in.format == media::VideoSurface::YV16) ?
330 frame_in.height : frame_in.height / 2;
331 glActiveTexture(GL_TEXTURE0 + i);
332 // No GL_UNPACK_ROW_LENGTH in GLES2.
333 // glPixelStorei(GL_UNPACK_ROW_LENGTH, frame_in.strides[i]);
334 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0,
335 GL_LUMINANCE, GL_UNSIGNED_BYTE, frame_in.data[i]);
336 }
337 video_frame->Unlock();
338 } else {
339 NOTREACHED();
340 }
341
342 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
343 eglSwapBuffers(egl_display_, egl_surface_);
344 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698