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

Side by Side Diff: content/renderer/pepper/video_decoder_shim.cc

Issue 1111653004: Replace SW YUV conversion with higher quality Shader+FBO in pepper video path. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added InvalidateGrContext calls for Skia State. Created 5 years, 7 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/renderer/pepper/video_decoder_shim.h" 5 #include "content/renderer/pepper/video_decoder_shim.h"
6 6
7 #include <GLES2/gl2.h> 7 #include <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h> 8 #include <GLES2/gl2ext.h>
9 #include <GLES2/gl2extchromium.h> 9 #include <GLES2/gl2extchromium.h>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #ifndef NDEBUG
13 #include "base/logging.h"
14 #endif
12 #include "base/numerics/safe_conversions.h" 15 #include "base/numerics/safe_conversions.h"
13 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
14 #include "cc/blink/context_provider_web_context.h" 17 #include "cc/blink/context_provider_web_context.h"
15 #include "content/public/renderer/render_thread.h" 18 #include "content/public/renderer/render_thread.h"
16 #include "content/renderer/pepper/pepper_video_decoder_host.h" 19 #include "content/renderer/pepper/pepper_video_decoder_host.h"
17 #include "content/renderer/render_thread_impl.h" 20 #include "content/renderer/render_thread_impl.h"
18 #include "gpu/command_buffer/client/gles2_implementation.h" 21 #include "gpu/command_buffer/client/gles2_implementation.h"
19 #include "media/base/decoder_buffer.h" 22 #include "media/base/decoder_buffer.h"
20 #include "media/base/limits.h" 23 #include "media/base/limits.h"
21 #include "media/base/video_decoder.h" 24 #include "media/base/video_decoder.h"
22 #include "media/blink/skcanvas_video_renderer.h" 25 #include "media/blink/skcanvas_video_renderer.h"
23 #include "media/filters/ffmpeg_video_decoder.h" 26 #include "media/filters/ffmpeg_video_decoder.h"
24 #include "media/filters/vpx_video_decoder.h" 27 #include "media/filters/vpx_video_decoder.h"
25 #include "media/video/picture.h" 28 #include "media/video/picture.h"
26 #include "media/video/video_decode_accelerator.h" 29 #include "media/video/video_decode_accelerator.h"
27 #include "ppapi/c/pp_errors.h" 30 #include "ppapi/c/pp_errors.h"
31 #include "third_party/skia/include/gpu/GrTypes.h"
28 32
29 namespace content { 33 namespace content {
30 34
35 //
piman 2015/05/12 03:00:25 nit: remove blank comment line
36 // YUV->RGB converter class using a shader and FBO
piman 2015/05/12 03:00:24 nit: end with a .
37 //
piman 2015/05/12 03:00:24 nit: remove blank comment line
38 class YUVConverter {
39 public:
40 YUVConverter(const scoped_refptr<cc_blink::ContextProviderWebContext>&);
41 ~YUVConverter();
42 bool Initialize();
43 void Convert(const scoped_refptr<media::VideoFrame>& frame, GLuint tex_out);
44
45 private:
46 GLuint CreateShader();
47 GLuint CompileShader(const char* name, GLuint type, const char* code);
48 GLuint CreateProgram(const char* name, GLuint vshader, GLuint fshader);
49 void SetUniform(GLuint program, const char* name, int value);
50 void SetUniform(GLuint program, const char* name, float value);
51 GLuint CreateTexture();
52
53 scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
54 gpu::gles2::GLES2Interface* gl_;
55 GLuint frame_buffer_;
56 GLuint vtx_buffer_;
57 GLuint program_;
58
59 GLuint y_texture_;
60 GLuint u_texture_;
61 GLuint v_texture_;
62
63 GLuint internal_format_;
64 GLuint format_;
65
66 GLuint y_width_;
67 GLuint y_height_;
68
69 GLuint uv_width_;
70 GLuint uv_height_;
71
72 GLfloat clamp_value_;
73 GLuint clamp_width_;
74 GLint clamp_width_loc_;
75
76 const uint32_t gr_invalidate_state_;
77
78 DISALLOW_COPY_AND_ASSIGN(YUVConverter);
79 };
80
81 YUVConverter::YUVConverter(
82 const scoped_refptr<cc_blink::ContextProviderWebContext>& ctx_p)
83 : context_provider_(ctx_p),
84 gl_(context_provider_->ContextGL()),
85 frame_buffer_(0),
86 vtx_buffer_(0),
87 program_(0),
88 y_texture_(0),
89 u_texture_(0),
90 v_texture_(0),
91 internal_format_(0),
92 format_(0),
93 y_width_(2),
94 y_height_(2),
95 uv_width_(2),
96 uv_height_(2),
97 clamp_value_(1.f),
98 clamp_width_(0),
99 clamp_width_loc_(0),
100 gr_invalidate_state_(kRenderTarget_GrGLBackendState |
101 kTextureBinding_GrGLBackendState |
102 kView_GrGLBackendState |
103 kVertex_GrGLBackendState |
104 kProgram_GrGLBackendState) {
piman 2015/05/12 03:00:24 I don't think it's useful to have it as a field si
105 }
106
107 YUVConverter::~YUVConverter() {
108 // delete textures
piman 2015/05/12 03:00:23 nit: remove comment
109 if (y_texture_)
110 gl_->DeleteTextures(1, &y_texture_);
111
112 if (u_texture_)
113 gl_->DeleteTextures(1, &u_texture_);
114
115 if (v_texture_)
116 gl_->DeleteTextures(1, &v_texture_);
117
118 // delete framebuffer
piman 2015/05/12 03:00:24 nit: remove comment
119 if (frame_buffer_)
120 gl_->DeleteFramebuffers(1, &frame_buffer_);
121
122 // delete vertex buffer
piman 2015/05/12 03:00:24 nit: remove comment
123 if (vtx_buffer_)
124 gl_->DeleteBuffers(1, &vtx_buffer_);
125
126 // delete program
piman 2015/05/12 03:00:24 nit: remove comment
127 if (program_)
128 gl_->DeleteProgram(program_);
129 }
130
131 GLuint YUVConverter::CreateTexture() {
132 GLuint tex = 0;
133
134 // create texture
piman 2015/05/12 03:00:25 nit: remove comment
135 gl_->GenTextures(1, &tex);
136 gl_->BindTexture(GL_TEXTURE_2D, tex);
137
138 // create texture with default size - will be resized upon first frame
139 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
140 GL_UNSIGNED_BYTE, NULL);
141
142 // set params
piman 2015/05/12 03:00:25 nit: remove comment
143 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
144 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
145 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
146 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
147
148 // unbind
piman 2015/05/12 03:00:25 nit: remove comment
149 gl_->BindTexture(GL_TEXTURE_2D, 0);
150
151 return tex;
152 }
153
154 GLuint YUVConverter::CompileShader(const char* name,
155 GLuint type,
156 const char* code) {
157 GLuint shader = gl_->CreateShader(type);
158
159 gl_->ShaderSource(shader, 1, (const GLchar**)&code, NULL);
160 gl_->CompileShader(shader);
161
162 #ifndef NDEBUG
163 GLint status = 0;
164
165 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
166 if (status != GL_TRUE) {
167 GLint max_length = 0;
168 GLint actual_length = 0;
169 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
170
171 // The maxLength includes the NULL character
piman 2015/05/12 03:00:23 nit: max_length
172 std::string error_log(max_length, 0);
173 gl_->GetShaderInfoLog(shader, max_length, &actual_length, &error_log[0]);
174
175 LOG(ERROR) << name << " shader compilation failed: " << error_log.c_str();
176 gl_->DeleteShader(shader);
177 return 0;
178 }
179 #endif
180
181 return shader;
182 }
183
184 GLuint YUVConverter::CreateProgram(const char* name,
185 GLuint vshader,
186 GLuint fshader) {
187 GLuint program = gl_->CreateProgram();
188 gl_->AttachShader(program, vshader);
189 gl_->AttachShader(program, fshader);
190
191 // bind known vertex position
piman 2015/05/12 03:00:24 nit: remove comment
192 gl_->BindAttribLocation(program, 0, "position");
193
194 gl_->LinkProgram(program);
195
196 #ifndef NDEBUG
197 GLint status = 0;
198
199 gl_->GetProgramiv(program, GL_LINK_STATUS, &status);
200 if (status != GL_TRUE) {
201 GLint max_length = 0;
202 GLint actual_length = 0;
203 gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
204
205 // The maxLength includes the NULL character
piman 2015/05/12 03:00:25 nit: max_length
206 std::string error_log(max_length, 0);
207 gl_->GetProgramInfoLog(program, max_length, &actual_length, &error_log[0]);
208
209 LOG(ERROR) << name << " program linking failed: " << error_log.c_str();
210 return 0;
211 }
212 #endif
213
214 return program;
215 }
216
217 void YUVConverter::SetUniform(GLuint program, const char* name, int value) {
218 GLint loc = gl_->GetUniformLocation(program, name);
219 DCHECK(loc != -1);
220 gl_->UseProgram(program);
221 gl_->Uniform1i(loc, value);
222 gl_->UseProgram(0);
223 }
224
225 void YUVConverter::SetUniform(GLuint program, const char* name, float value) {
226 GLint loc = gl_->GetUniformLocation(program, name);
227 DCHECK(loc != -1);
228 gl_->UseProgram(program);
229 gl_->Uniform1f(loc, value);
230 gl_->UseProgram(0);
231 }
232
233 GLuint YUVConverter::CreateShader() {
234 const char* vert_shader =
235 "precision mediump float;\n"
236 "attribute vec2 position;\n"
237 "varying vec2 texcoord;\n"
238 "uniform float clamp_width;\n"
239 "void main()\n"
240 "{\n"
241 " gl_Position = vec4( position.xy, 0, 1 );\n"
242 // convert vertex positions to texcoords, clamp x
piman 2015/05/12 03:00:24 nit: remove comment
243 " vec2 tmp = position*0.5+0.5;\n"
244 " texcoord = vec2(min(tmp.x, clamp_width), tmp.y);\n"
245 "}";
246
247 const char* frag_shader =
248 "precision mediump float;\n"
249 "varying vec2 texcoord;\n"
250 "uniform sampler2D y_sampler;\n"
251 "uniform sampler2D u_sampler;\n"
252 "uniform sampler2D v_sampler;\n"
253 "void main()\n"
254 "{\n"
255 // These values are magic numbers that are used in the transformation
256 // from YUV to RGB color values. They are taken from the following
257 // webpage: http://www.fourcc.org/fccyvrgb.php. In this case Rec. 601.
258 // yuv_2_rgb and yuv_adjust_constrained were taken from gl_renderer.cc
259 " const mat3 yuv_2_rgb = mat3( 1.164, 1.164, 1.164,\n"
260 " 0.0, -.391, 2.018,\n"
261 " 1.596, -.813, 0.0 );\n"
262 // These values map to 16, 128, and 128 respectively, and are computed
263 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
264 // They are used in the YUV to RGBA conversion formula:
265 // Y - 16 : Gives 16 values of head and footroom for overshooting
266 // U - 128 : Turns unsigned U into signed U [-128,127]
267 // V - 128 : Turns unsigned V into signed V [-128,127]
268 " const vec3 yuv_adjust_constrained = vec3( -0.0625, -0.5, -0.5 );\n"
269
270 " vec3 yuv = vec3( texture2D(y_sampler, texcoord).x,\n"
271 " texture2D(u_sampler, texcoord).x,\n"
272 " texture2D(v_sampler, texcoord).x ) +\n"
273 " yuv_adjust_constrained;\n"
274 " gl_FragColor = vec4( yuv_2_rgb * yuv, 1.0 );\n"
275 "}";
276
277 //
278 // Compile vertex and fragment shaders.
279 //
piman 2015/05/12 03:00:23 nit: remove comment
280 GLuint vertex_shader =
281 CompileShader("Vertex Shader", GL_VERTEX_SHADER, vert_shader);
282 if (!vertex_shader) {
283 return 0;
284 }
285
286 GLuint fragment_shader =
287 CompileShader("Fragment Shader", GL_FRAGMENT_SHADER, frag_shader);
288 if (!fragment_shader) {
289 gl_->DeleteShader(vertex_shader);
290 return 0;
291 }
292
293 //
294 // Create the program
295 //
piman 2015/05/12 03:00:24 nit: remove comment
296 GLuint program =
297 CreateProgram("YUVConverter Program", vertex_shader, fragment_shader);
298
299 // delete shaders since they are no longer needed
piman 2015/05/12 03:00:24 nit: remove comment
300 gl_->DeleteShader(vertex_shader);
301 gl_->DeleteShader(fragment_shader);
302
303 if (!program) {
304 return 0;
305 }
306
307 GLuint result = program;
308
309 //
310 // Bind samplers to texture units - which never change.
311 //
piman 2015/05/12 03:00:25 nit: remove comment
312 SetUniform(program, "y_sampler", 0);
313 SetUniform(program, "u_sampler", 1);
314 SetUniform(program, "v_sampler", 2);
315
316 // set default clamp width
piman 2015/05/12 03:00:24 nit: remove comment
317 SetUniform(program, "clamp_width", clamp_value_);
318
319 // store clamp width loc for later
piman 2015/05/12 03:00:24 nit: remove comment
320 clamp_width_loc_ = gl_->GetUniformLocation(program, "clamp_width");
321 DCHECK(clamp_width_loc_ != -1);
322
323 if (!result) {
324 gl_->DeleteProgram(program);
325 }
326
327 return result;
328 }
329
330 bool YUVConverter::Initialize() {
331 //
piman 2015/05/12 03:00:24 nit: remove blank comment line
332 // Determine formats to use based on whether GL_RED is available or
333 // whether we need to use GL_LUMINANCE.
334 //
piman 2015/05/12 03:00:23 nit: remove blank comment line
335 DCHECK(gl_);
336 if (context_provider_->ContextCapabilities().gpu.texture_rg) {
337 internal_format_ = GL_RED_EXT;
338 format_ = GL_RED_EXT;
339 } else {
340 internal_format_ = GL_LUMINANCE;
341 format_ = GL_LUMINANCE;
342 }
343
344 gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
345
346 gl_->GenFramebuffers(1, &frame_buffer_);
347
348 // Create some default textures to hold Y,U,V values
piman 2015/05/12 03:00:25 nit: remove comment
349 y_texture_ = CreateTexture();
350 u_texture_ = CreateTexture();
351 v_texture_ = CreateTexture();
352
353 // Vertex positions. Also converted to texcoords in vertex shader.
354 GLfloat vtx_buf[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f};
355
356 gl_->GenBuffers(1, &vtx_buffer_);
357 gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_);
358 gl_->BufferData(GL_ARRAY_BUFFER, 2 * sizeof(GLfloat) * 4, vtx_buf,
359 GL_STATIC_DRAW);
360 gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
361
362 program_ = CreateShader();
363
364 gl_->PopGroupMarkerEXT();
365
366 context_provider_->InvalidateGrContext(gr_invalidate_state_);
367
368 return (program_ != 0);
369 }
370
371 void YUVConverter::Convert(const scoped_refptr<media::VideoFrame>& frame,
372 GLuint tex_out) {
373 int divisor_height = 1;
374 bool supported_format = true;
375
376 // make sure we support this format
piman 2015/05/12 03:00:24 nit: remove comment
377 switch (frame->format()) {
378 case media::VideoFrame::YV12: /* 420 */
379 case media::VideoFrame::I420: /* 420 */
380 divisor_height = 2;
381 break;
382
383 case media::VideoFrame::YV16: /* 422 */
384 case media::VideoFrame::YV24: /* 444 */
385 break;
386
387 default:
388 // rest are not supported..
piman 2015/05/12 03:00:23 nit: remove comment
389 supported_format = false;
390 break;
391 }
392
393 gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
394
395 bool set_clamp = false;
396
397 uint32_t ywidth = frame->coded_size().width();
398 uint32_t yheight = frame->coded_size().height();
399
400 if (supported_format) {
401 DCHECK_EQ(frame->stride(media::VideoFrame::kUPlane),
402 frame->stride(media::VideoFrame::kVPlane));
403
404 uint32_t ystride = frame->stride(media::VideoFrame::kYPlane);
405 uint32_t uvstride = frame->stride(media::VideoFrame::kUPlane);
406
407 // resize textures if necessary
piman 2015/05/12 03:00:24 nit: remove comment
408 if (ystride != y_width_ || yheight != y_height_) {
409 // choose width based on the stride
410 // then, clamp later
piman 2015/05/12 03:00:25 You can keep this comment, but it should be a full
411 y_width_ = ystride;
412 y_height_ = yheight;
413
414 uv_width_ = uvstride;
415 uv_height_ = y_height_ / divisor_height;
416
417 if ((ystride != ywidth) || (clamp_width_ != ywidth)) {
piman 2015/05/12 03:00:25 I'm not sure I understand the need for this outer
418 if (clamp_width_ != ywidth) {
419 // clamp width to avoid sampling padding pixels
piman 2015/05/12 03:00:24 nit: remove comment (assuming you explained above)
420 clamp_width_ = ywidth;
421 clamp_value_ =
422 static_cast<float>(ywidth) / static_cast<float>(ystride);
423 // clamp to 1/2 pixel inside to avoid bilinear sampling errors
piman 2015/05/12 03:00:24 nit: remove comment (assuming you explained above)
424 clamp_value_ -= (1.f / (2.f * static_cast<float>(ystride)));
425
426 set_clamp = true;
427 }
428 }
429
430 //
431 // Resize the textures and upload data
432 //
piman 2015/05/12 03:00:23 nit: remove comment
433 gl_->ActiveTexture(GL_TEXTURE0);
434 gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
435 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_,
436 0, format_, GL_UNSIGNED_BYTE,
437 frame->data(media::VideoFrame::kYPlane));
438
439 gl_->ActiveTexture(GL_TEXTURE1);
440 gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
441 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
442 0, format_, GL_UNSIGNED_BYTE,
443 frame->data(media::VideoFrame::kUPlane));
444
445 gl_->ActiveTexture(GL_TEXTURE2);
446 gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
447 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
448 0, format_, GL_UNSIGNED_BYTE,
449 frame->data(media::VideoFrame::kVPlane));
450 } else {
451 //
452 // Bind textures and upload texture data
453 //
piman 2015/05/12 03:00:24 nit: remove comment
454 gl_->ActiveTexture(GL_TEXTURE0);
455 gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
456 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_,
457 GL_UNSIGNED_BYTE,
458 frame->data(media::VideoFrame::kYPlane));
459
460 gl_->ActiveTexture(GL_TEXTURE1);
461 gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
462 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
463 GL_UNSIGNED_BYTE,
464 frame->data(media::VideoFrame::kUPlane));
465
466 gl_->ActiveTexture(GL_TEXTURE2);
467 gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
468 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
469 GL_UNSIGNED_BYTE,
470 frame->data(media::VideoFrame::kVPlane));
471 }
472 } else {
473 //
474 // Unsupported format - set textures to be 4x4 and produce a red output
475 // 2x2 texture didn't seem to work
476 //
piman 2015/05/12 03:00:25 If the format is not supported by the fast path, w
477 uint8_t yudata[4 * 4];
478 memset(yudata, 0x5e, 4 * 4);
479 gl_->ActiveTexture(GL_TEXTURE0);
480 gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
481 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4, 0, format_,
482 GL_UNSIGNED_BYTE, yudata);
483
484 gl_->ActiveTexture(GL_TEXTURE1);
485 gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
486 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4, 0, format_,
487 GL_UNSIGNED_BYTE, yudata);
488
489 uint8_t vdata[4 * 4];
490 memset(vdata, 0xe7, 4 * 4);
491 gl_->ActiveTexture(GL_TEXTURE2);
492 gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
493 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4, 0, format_,
494 GL_UNSIGNED_BYTE, vdata);
495
496 if (clamp_value_ != 1.f) {
497 set_clamp = true;
498 clamp_value_ = 1.f;
499 }
500 }
501
502 gl_->BindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
503 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
504 tex_out, 0);
505
506 #ifndef NDEBUG
507 // NOTE: we should probably check for framebuffer complete here, but that
508 // will slow this method down so check in debug mode
piman 2015/05/12 03:00:25 nit: end with a .
509 GLint status = gl_->CheckFramebufferStatus(GL_FRAMEBUFFER);
510 if (status != GL_FRAMEBUFFER_COMPLETE) {
511 return;
512 }
513 #endif
514
515 gl_->Viewport(0, 0, ywidth, yheight);
516
517 gl_->UseProgram(program_);
518
519 if (set_clamp) {
520 gl_->Uniform1f(clamp_width_loc_, clamp_value_);
521 }
522
523 gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_);
524 gl_->EnableVertexAttribArray(0);
525 gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
526 static_cast<const void*>(0));
527
528 gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
529
530 gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
531 gl_->DisableVertexAttribArray(0);
532 gl_->UseProgram(0);
533 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
534
535 // active texture is still 2
piman 2015/05/12 03:00:23 nit: remove comment
536 gl_->BindTexture(GL_TEXTURE_2D, 0);
537
538 gl_->ActiveTexture(GL_TEXTURE1);
539 gl_->BindTexture(GL_TEXTURE_2D, 0);
540
541 gl_->ActiveTexture(GL_TEXTURE0);
542 gl_->BindTexture(GL_TEXTURE_2D, 0);
543
544 gl_->PopGroupMarkerEXT();
545
546 context_provider_->InvalidateGrContext(gr_invalidate_state_);
547 }
548
31 struct VideoDecoderShim::PendingDecode { 549 struct VideoDecoderShim::PendingDecode {
32 PendingDecode(uint32_t decode_id, 550 PendingDecode(uint32_t decode_id,
33 const scoped_refptr<media::DecoderBuffer>& buffer); 551 const scoped_refptr<media::DecoderBuffer>& buffer);
34 ~PendingDecode(); 552 ~PendingDecode();
35 553
36 const uint32_t decode_id; 554 const uint32_t decode_id;
37 const scoped_refptr<media::DecoderBuffer> buffer; 555 const scoped_refptr<media::DecoderBuffer> buffer;
38 }; 556 };
39 557
40 VideoDecoderShim::PendingDecode::PendingDecode( 558 VideoDecoderShim::PendingDecode::PendingDecode(
41 uint32_t decode_id, 559 uint32_t decode_id,
42 const scoped_refptr<media::DecoderBuffer>& buffer) 560 const scoped_refptr<media::DecoderBuffer>& buffer)
43 : decode_id(decode_id), buffer(buffer) { 561 : decode_id(decode_id), buffer(buffer) {
44 } 562 }
45 563
46 VideoDecoderShim::PendingDecode::~PendingDecode() { 564 VideoDecoderShim::PendingDecode::~PendingDecode() {
47 } 565 }
48 566
49 struct VideoDecoderShim::PendingFrame { 567 struct VideoDecoderShim::PendingFrame {
50 explicit PendingFrame(uint32_t decode_id); 568 explicit PendingFrame(uint32_t decode_id);
51 PendingFrame(uint32_t decode_id, 569 PendingFrame(uint32_t decode_id,
52 const gfx::Size& coded_size, 570 const scoped_refptr<media::VideoFrame>& frame);
53 const gfx::Rect& visible_rect);
54 ~PendingFrame(); 571 ~PendingFrame();
55 572
56 const uint32_t decode_id; 573 const uint32_t decode_id;
57 const gfx::Size coded_size; 574 scoped_refptr<media::VideoFrame> video_frame;
58 const gfx::Rect visible_rect;
59 std::vector<uint8_t> argb_pixels;
60 575
61 private: 576 private:
62 // This could be expensive to copy, so guard against that. 577 // This could be expensive to copy, so guard against that.
63 DISALLOW_COPY_AND_ASSIGN(PendingFrame); 578 DISALLOW_COPY_AND_ASSIGN(PendingFrame);
64 }; 579 };
65 580
66 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id) 581 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id)
67 : decode_id(decode_id) { 582 : decode_id(decode_id) {
68 } 583 }
69 584
70 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id, 585 VideoDecoderShim::PendingFrame::PendingFrame(
71 const gfx::Size& coded_size, 586 uint32_t decode_id,
72 const gfx::Rect& visible_rect) 587 const scoped_refptr<media::VideoFrame>& frame)
73 : decode_id(decode_id), 588 : decode_id(decode_id), video_frame(frame) {
74 coded_size(coded_size),
75 visible_rect(visible_rect),
76 argb_pixels(coded_size.width() * coded_size.height() * 4) {
77 } 589 }
78 590
79 VideoDecoderShim::PendingFrame::~PendingFrame() { 591 VideoDecoderShim::PendingFrame::~PendingFrame() {
80 } 592 }
81 593
82 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving 594 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving
83 // calls from the VideoDecodeShim on the main thread and sending results back. 595 // calls from the VideoDecodeShim on the main thread and sending results back.
84 // This class is constructed on the main thread, but used and destructed on the 596 // This class is constructed on the main thread, but used and destructed on the
85 // media thread. 597 // media thread.
86 class VideoDecoderShim::DecoderImpl { 598 class VideoDecoderShim::DecoderImpl {
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 774 }
263 775
264 void VideoDecoderShim::DecoderImpl::OnOutputComplete( 776 void VideoDecoderShim::DecoderImpl::OnOutputComplete(
265 const scoped_refptr<media::VideoFrame>& frame) { 777 const scoped_refptr<media::VideoFrame>& frame) {
266 // Software decoders are expected to generated frames only when a Decode() 778 // Software decoders are expected to generated frames only when a Decode()
267 // call is pending. 779 // call is pending.
268 DCHECK(awaiting_decoder_); 780 DCHECK(awaiting_decoder_);
269 781
270 scoped_ptr<PendingFrame> pending_frame; 782 scoped_ptr<PendingFrame> pending_frame;
271 if (!frame->end_of_stream()) { 783 if (!frame->end_of_stream()) {
272 pending_frame.reset(new PendingFrame( 784 pending_frame.reset(new PendingFrame(decode_id_, frame));
273 decode_id_, frame->coded_size(), frame->visible_rect()));
274 // Convert the VideoFrame pixels to ABGR to match VideoDecodeAccelerator.
275 media::SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels(
276 frame,
277 &pending_frame->argb_pixels.front(),
278 frame->coded_size().width() * 4);
279 } else { 785 } else {
280 pending_frame.reset(new PendingFrame(decode_id_)); 786 pending_frame.reset(new PendingFrame(decode_id_));
281 } 787 }
282 788
283 main_message_loop_->PostTask(FROM_HERE, 789 main_message_loop_->PostTask(FROM_HERE,
284 base::Bind(&VideoDecoderShim::OnOutputComplete, 790 base::Bind(&VideoDecoderShim::OnOutputComplete,
285 shim_, 791 shim_,
286 base::Passed(&pending_frame))); 792 base::Passed(&pending_frame)));
287 } 793 }
288 794
289 void VideoDecoderShim::DecoderImpl::OnResetComplete() { 795 void VideoDecoderShim::DecoderImpl::OnResetComplete() {
290 main_message_loop_->PostTask( 796 main_message_loop_->PostTask(
291 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_)); 797 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_));
292 } 798 }
293 799
294 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host) 800 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host)
295 : state_(UNINITIALIZED), 801 : state_(UNINITIALIZED),
296 host_(host), 802 host_(host),
297 media_task_runner_( 803 media_task_runner_(
298 RenderThreadImpl::current()->GetMediaThreadTaskRunner()), 804 RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
299 context_provider_( 805 context_provider_(
300 RenderThreadImpl::current()->SharedMainThreadContextProvider()), 806 RenderThreadImpl::current()->SharedMainThreadContextProvider()),
301 texture_pool_size_(0), 807 texture_pool_size_(0),
302 num_pending_decodes_(0), 808 num_pending_decodes_(0),
303 weak_ptr_factory_(this) { 809 weak_ptr_factory_(this) {
304 DCHECK(host_); 810 DCHECK(host_);
305 DCHECK(media_task_runner_.get()); 811 DCHECK(media_task_runner_.get());
306 DCHECK(context_provider_.get()); 812 DCHECK(context_provider_.get());
307 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr())); 813 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr()));
814 yuv_converter_.reset(new YUVConverter(context_provider_));
308 } 815 }
309 816
310 VideoDecoderShim::~VideoDecoderShim() { 817 VideoDecoderShim::~VideoDecoderShim() {
311 DCHECK(RenderThreadImpl::current()); 818 DCHECK(RenderThreadImpl::current());
312 // Delete any remaining textures. 819 // Delete any remaining textures.
313 TextureIdMap::iterator it = texture_id_map_.begin(); 820 TextureIdMap::iterator it = texture_id_map_.begin();
314 for (; it != texture_id_map_.end(); ++it) 821 for (; it != texture_id_map_.end(); ++it)
315 DeleteTexture(it->second); 822 DeleteTexture(it->second);
316 texture_id_map_.clear(); 823 texture_id_map_.clear();
317 824
(...skipping 18 matching lines...) Expand all
336 DCHECK_EQ(state_, UNINITIALIZED); 843 DCHECK_EQ(state_, UNINITIALIZED);
337 media::VideoCodec codec = media::kUnknownVideoCodec; 844 media::VideoCodec codec = media::kUnknownVideoCodec;
338 if (profile <= media::H264PROFILE_MAX) 845 if (profile <= media::H264PROFILE_MAX)
339 codec = media::kCodecH264; 846 codec = media::kCodecH264;
340 else if (profile <= media::VP8PROFILE_MAX) 847 else if (profile <= media::VP8PROFILE_MAX)
341 codec = media::kCodecVP8; 848 codec = media::kCodecVP8;
342 else if (profile <= media::VP9PROFILE_MAX) 849 else if (profile <= media::VP9PROFILE_MAX)
343 codec = media::kCodecVP9; 850 codec = media::kCodecVP9;
344 DCHECK_NE(codec, media::kUnknownVideoCodec); 851 DCHECK_NE(codec, media::kUnknownVideoCodec);
345 852
853 // initialize yuv converter
piman 2015/05/12 03:00:24 nit: remove comment
piman 2015/05/13 04:20:37 ping
854 if (!yuv_converter_->Initialize()) {
855 return false;
856 }
857
346 media::VideoDecoderConfig config( 858 media::VideoDecoderConfig config(
347 codec, 859 codec,
348 profile, 860 profile,
349 media::VideoFrame::YV12, 861 media::VideoFrame::YV12,
350 gfx::Size(32, 24), // Small sizes that won't fail. 862 gfx::Size(32, 24), // Small sizes that won't fail.
351 gfx::Rect(32, 24), 863 gfx::Rect(32, 24),
352 gfx::Size(32, 24), 864 gfx::Size(32, 24),
353 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed. 865 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed.
354 0 /* extra_data_size */, 866 0 /* extra_data_size */,
355 false /* decryption */); 867 false /* decryption */);
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 num_pending_decodes_--; 976 num_pending_decodes_--;
465 completed_decodes_.push(decode_id); 977 completed_decodes_.push(decode_id);
466 978
467 // If frames are being queued because we're out of textures, don't notify 979 // If frames are being queued because we're out of textures, don't notify
468 // the host that decode has completed. This exerts "back pressure" to keep 980 // the host that decode has completed. This exerts "back pressure" to keep
469 // the host from sending buffers that will cause pending_frames_ to grow. 981 // the host from sending buffers that will cause pending_frames_ to grow.
470 if (pending_frames_.empty()) 982 if (pending_frames_.empty())
471 NotifyCompletedDecodes(); 983 NotifyCompletedDecodes();
472 } 984 }
473 985
474 void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) { 986 void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> pframe) {
475 DCHECK(RenderThreadImpl::current()); 987 DCHECK(RenderThreadImpl::current());
476 DCHECK(host_); 988 DCHECK(host_);
477 989
478 if (!frame->argb_pixels.empty()) { 990 if (pframe->video_frame) {
479 if (texture_size_ != frame->coded_size) { 991 if (texture_size_ != pframe->video_frame->coded_size()) {
480 // If the size has changed, all current textures must be dismissed. Add 992 // If the size has changed, all current textures must be dismissed. Add
481 // all textures to |textures_to_dismiss_| and dismiss any that aren't in 993 // all textures to |textures_to_dismiss_| and dismiss any that aren't in
482 // use by the plugin. We will dismiss the rest as they are recycled. 994 // use by the plugin. We will dismiss the rest as they are recycled.
483 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); 995 for (TextureIdMap::const_iterator it = texture_id_map_.begin();
484 it != texture_id_map_.end(); 996 it != texture_id_map_.end();
485 ++it) { 997 ++it) {
486 textures_to_dismiss_.insert(it->first); 998 textures_to_dismiss_.insert(it->first);
487 } 999 }
488 for (TextureIdSet::const_iterator it = available_textures_.begin(); 1000 for (TextureIdSet::const_iterator it = available_textures_.begin();
489 it != available_textures_.end(); 1001 it != available_textures_.end();
490 ++it) { 1002 ++it) {
491 DismissTexture(*it); 1003 DismissTexture(*it);
492 } 1004 }
493 available_textures_.clear(); 1005 available_textures_.clear();
494 FlushCommandBuffer(); 1006 FlushCommandBuffer();
495 1007
496 DCHECK(pending_texture_mailboxes_.empty()); 1008 DCHECK(pending_texture_mailboxes_.empty());
497 for (uint32_t i = 0; i < texture_pool_size_; i++) 1009 for (uint32_t i = 0; i < texture_pool_size_; i++)
498 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); 1010 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate());
499 1011
500 host_->RequestTextures(texture_pool_size_, 1012 host_->RequestTextures(texture_pool_size_,
501 frame->coded_size, 1013 pframe->video_frame->coded_size(), GL_TEXTURE_2D,
502 GL_TEXTURE_2D,
503 pending_texture_mailboxes_); 1014 pending_texture_mailboxes_);
504 texture_size_ = frame->coded_size; 1015 texture_size_ = pframe->video_frame->coded_size();
505 } 1016 }
506 1017
507 pending_frames_.push(linked_ptr<PendingFrame>(frame.release())); 1018 pending_frames_.push(linked_ptr<PendingFrame>(pframe.release()));
508 SendPictures(); 1019 SendPictures();
509 } 1020 }
510 } 1021 }
511 1022
512 void VideoDecoderShim::SendPictures() { 1023 void VideoDecoderShim::SendPictures() {
513 DCHECK(RenderThreadImpl::current()); 1024 DCHECK(RenderThreadImpl::current());
514 DCHECK(host_); 1025 DCHECK(host_);
515 while (!pending_frames_.empty() && !available_textures_.empty()) { 1026 while (!pending_frames_.empty() && !available_textures_.empty()) {
516 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); 1027 const linked_ptr<PendingFrame>& frame = pending_frames_.front();
517 1028
518 TextureIdSet::iterator it = available_textures_.begin(); 1029 TextureIdSet::iterator it = available_textures_.begin();
519 uint32_t texture_id = *it; 1030 uint32_t texture_id = *it;
520 available_textures_.erase(it); 1031 available_textures_.erase(it);
521 1032
522 uint32_t local_texture_id = texture_id_map_[texture_id]; 1033 uint32_t local_texture_id = texture_id_map_[texture_id];
523 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); 1034
524 gles2->ActiveTexture(GL_TEXTURE0); 1035 // run the yuv conversion renderer
piman 2015/05/12 03:00:23 nit: remove comment
piman 2015/05/13 04:20:37 ping
525 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); 1036 yuv_converter_->Convert(frame->video_frame, local_texture_id);
526 #if !defined(OS_ANDROID)
527 // BGRA is the native texture format, except on Android, where textures
528 // would be uploaded as GL_RGBA.
529 gles2->TexImage2D(GL_TEXTURE_2D,
530 0,
531 GL_BGRA_EXT,
532 texture_size_.width(),
533 texture_size_.height(),
534 0,
535 GL_BGRA_EXT,
536 GL_UNSIGNED_BYTE,
537 &frame->argb_pixels.front());
538 #else
539 #error Not implemented.
540 #endif
541 1037
542 host_->PictureReady(media::Picture(texture_id, frame->decode_id, 1038 host_->PictureReady(media::Picture(texture_id, frame->decode_id,
543 frame->visible_rect, false)); 1039 frame->video_frame->visible_rect(),
1040 false));
544 pending_frames_.pop(); 1041 pending_frames_.pop();
545 } 1042 }
546 1043
547 FlushCommandBuffer(); 1044 FlushCommandBuffer();
548 1045
549 if (pending_frames_.empty()) { 1046 if (pending_frames_.empty()) {
550 // If frames aren't backing up, notify the host of any completed decodes so 1047 // If frames aren't backing up, notify the host of any completed decodes so
551 // it can send more buffers. 1048 // it can send more buffers.
552 NotifyCompletedDecodes(); 1049 NotifyCompletedDecodes();
553 1050
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) { 1090 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) {
594 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); 1091 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
595 gles2->DeleteTextures(1, &texture_id); 1092 gles2->DeleteTextures(1, &texture_id);
596 } 1093 }
597 1094
598 void VideoDecoderShim::FlushCommandBuffer() { 1095 void VideoDecoderShim::FlushCommandBuffer() {
599 context_provider_->ContextGL()->Flush(); 1096 context_provider_->ContextGL()->Flush();
600 } 1097 }
601 1098
602 } // namespace content 1099 } // namespace content
OLDNEW
« content/renderer/pepper/video_decoder_shim.h ('K') | « content/renderer/pepper/video_decoder_shim.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698