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

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 missing period. 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 static const uint32_t kGrInvalidateState =
36 kRenderTarget_GrGLBackendState | kTextureBinding_GrGLBackendState |
37 kView_GrGLBackendState | kVertex_GrGLBackendState |
38 kProgram_GrGLBackendState;
39
40 // YUV->RGB converter class using a shader and FBO.
41 class VideoDecoderShim::YUVConverter {
42 public:
43 YUVConverter(const scoped_refptr<cc_blink::ContextProviderWebContext>&);
44 ~YUVConverter();
45 bool Initialize();
46 void Convert(const scoped_refptr<media::VideoFrame>& frame, GLuint tex_out);
47
48 private:
49 GLuint CreateShader();
50 GLuint CompileShader(const char* name, GLuint type, const char* code);
51 GLuint CreateProgram(const char* name, GLuint vshader, GLuint fshader);
52 void SetUniform(GLuint program, const char* name, int value);
53 void SetUniform(GLuint program, const char* name, float value);
54 GLuint CreateTexture();
55 void SetTexcoordClamp(uint32_t stride, uint32_t width);
56
57 scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
58 gpu::gles2::GLES2Interface* gl_;
59 GLuint frame_buffer_;
60 GLuint vtx_buffer_;
bbudge 2015/05/14 16:45:48 nit: vertex_buffer_
CodeByThePound 2015/05/14 17:42:08 Done.
61 GLuint program_;
62
63 GLuint y_texture_;
64 GLuint u_texture_;
65 GLuint v_texture_;
66 GLuint a_texture_;
67
68 GLuint internal_format_;
69 GLuint format_;
70 media::VideoFrame::Format video_format_;
71
72 GLuint y_width_;
73 GLuint y_height_;
74
75 GLuint uv_width_;
76 GLuint uv_height_;
77 uint32_t uv_height_divisor_;
78
79 GLfloat clamp_value_;
80 GLuint clamp_width_;
81 GLint clamp_width_loc_;
82
83 GLint yuv_matrix_loc_;
84 GLint yuv_adjust_loc_;
85
86 DISALLOW_COPY_AND_ASSIGN(YUVConverter);
87 };
88
89 VideoDecoderShim::YUVConverter::YUVConverter(
90 const scoped_refptr<cc_blink::ContextProviderWebContext>& ctx_p)
bbudge 2015/05/14 16:45:48 nit: could you name this context_provider
CodeByThePound 2015/05/14 17:42:08 Done.
91 : context_provider_(ctx_p),
92 gl_(context_provider_->ContextGL()),
93 frame_buffer_(0),
94 vtx_buffer_(0),
95 program_(0),
96 y_texture_(0),
97 u_texture_(0),
98 v_texture_(0),
99 a_texture_(0),
100 internal_format_(0),
101 format_(0),
102 video_format_(media::VideoFrame::UNKNOWN),
103 y_width_(2),
104 y_height_(2),
105 uv_width_(2),
106 uv_height_(2),
107 uv_height_divisor_(1),
108 clamp_value_(1.f),
109 clamp_width_(0),
110 clamp_width_loc_(0),
111 yuv_matrix_loc_(0),
112 yuv_adjust_loc_(0) {
113 }
114
115 VideoDecoderShim::YUVConverter::~YUVConverter() {
116 if (y_texture_)
117 gl_->DeleteTextures(1, &y_texture_);
118
119 if (u_texture_)
120 gl_->DeleteTextures(1, &u_texture_);
121
122 if (v_texture_)
123 gl_->DeleteTextures(1, &v_texture_);
124
125 if (a_texture_)
126 gl_->DeleteTextures(1, &a_texture_);
127
128 if (frame_buffer_)
129 gl_->DeleteFramebuffers(1, &frame_buffer_);
130
131 if (vtx_buffer_)
132 gl_->DeleteBuffers(1, &vtx_buffer_);
133
134 if (program_)
135 gl_->DeleteProgram(program_);
136 }
137
138 GLuint VideoDecoderShim::YUVConverter::CreateTexture() {
139 GLuint tex = 0;
140
141 gl_->GenTextures(1, &tex);
142 gl_->BindTexture(GL_TEXTURE_2D, tex);
143
144 // Create texture with default size - will be resized upon first frame.
145 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
146 GL_UNSIGNED_BYTE, NULL);
147
148 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
149 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
150 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
151 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
152
153 gl_->BindTexture(GL_TEXTURE_2D, 0);
154
155 return tex;
156 }
157
158 GLuint VideoDecoderShim::YUVConverter::CompileShader(const char* name,
159 GLuint type,
160 const char* code) {
161 GLuint shader = gl_->CreateShader(type);
162
163 gl_->ShaderSource(shader, 1, (const GLchar**)&code, NULL);
164 gl_->CompileShader(shader);
165
166 #ifndef NDEBUG
167 GLint status = 0;
168
169 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
170 if (status != GL_TRUE) {
171 GLint max_length = 0;
172 GLint actual_length = 0;
173 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
174
175 // The max_length includes the NULL character.
176 std::string error_log(max_length, 0);
177 gl_->GetShaderInfoLog(shader, max_length, &actual_length, &error_log[0]);
178
179 LOG(ERROR) << name << " shader compilation failed: " << error_log.c_str();
180 gl_->DeleteShader(shader);
181 return 0;
182 }
183 #endif
184
185 return shader;
186 }
187
188 GLuint VideoDecoderShim::YUVConverter::CreateProgram(const char* name,
189 GLuint vshader,
190 GLuint fshader) {
191 GLuint program = gl_->CreateProgram();
192 gl_->AttachShader(program, vshader);
193 gl_->AttachShader(program, fshader);
194
195 gl_->BindAttribLocation(program, 0, "position");
196
197 gl_->LinkProgram(program);
198
199 #ifndef NDEBUG
200 GLint status = 0;
201
202 gl_->GetProgramiv(program, GL_LINK_STATUS, &status);
203 if (status != GL_TRUE) {
204 GLint max_length = 0;
205 GLint actual_length = 0;
206 gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
207
208 // The max_length includes the NULL character.
209 std::string error_log(max_length, 0);
210 gl_->GetProgramInfoLog(program, max_length, &actual_length, &error_log[0]);
211
212 LOG(ERROR) << name << " program linking failed: " << error_log.c_str();
213 return 0;
214 }
215 #endif
216
217 return program;
218 }
219
220 void VideoDecoderShim::YUVConverter::SetUniform(GLuint program,
221 const char* name,
222 int value) {
223 GLint loc = gl_->GetUniformLocation(program, name);
224 DCHECK(loc != -1);
225 gl_->UseProgram(program);
226 gl_->Uniform1i(loc, value);
227 gl_->UseProgram(0);
bbudge 2015/05/14 16:45:48 Is there a reason you set these inside the functio
CodeByThePound 2015/05/14 17:42:08 Removed SetUniform functions and inlined the code
228 }
229
230 void VideoDecoderShim::YUVConverter::SetUniform(GLuint program,
231 const char* name,
232 float value) {
233 GLint loc = gl_->GetUniformLocation(program, name);
234 DCHECK(loc != -1);
235 gl_->UseProgram(program);
236 gl_->Uniform1f(loc, value);
237 gl_->UseProgram(0);
238 }
239
240 GLuint VideoDecoderShim::YUVConverter::CreateShader() {
241 const char* vert_shader =
242 "precision mediump float;\n"
243 "attribute vec2 position;\n"
244 "varying vec2 texcoord;\n"
245 "uniform float clamp_width;\n"
246 "void main()\n"
247 "{\n"
248 " gl_Position = vec4( position.xy, 0, 1 );\n"
249 " vec2 tmp = position*0.5+0.5;\n"
250 " texcoord = vec2(min(tmp.x, clamp_width), tmp.y);\n"
251 "}";
252
253 const char* frag_shader =
254 "precision mediump float;\n"
255 "varying vec2 texcoord;\n"
256 "uniform sampler2D y_sampler;\n"
257 "uniform sampler2D u_sampler;\n"
258 "uniform sampler2D v_sampler;\n"
259 "uniform sampler2D a_sampler;\n"
260 "uniform mat3 yuv_matrix;\n"
261 "uniform vec3 yuv_adjust;\n"
262 "void main()\n"
263 "{\n"
264 " vec3 yuv = vec3(texture2D(y_sampler, texcoord).x,\n"
265 " texture2D(u_sampler, texcoord).x,\n"
266 " texture2D(v_sampler, texcoord).x) +\n"
267 " yuv_adjust;\n"
268 " gl_FragColor = vec4(yuv_matrix * yuv, texture2D(a_sampler, "
269 "texcoord).x);\n"
270 "}";
271
272 GLuint vertex_shader =
273 CompileShader("Vertex Shader", GL_VERTEX_SHADER, vert_shader);
274 if (!vertex_shader) {
275 return 0;
276 }
277
278 GLuint fragment_shader =
279 CompileShader("Fragment Shader", GL_FRAGMENT_SHADER, frag_shader);
280 if (!fragment_shader) {
281 gl_->DeleteShader(vertex_shader);
282 return 0;
283 }
284
285 GLuint program =
286 CreateProgram("YUVConverter Program", vertex_shader, fragment_shader);
287
288 gl_->DeleteShader(vertex_shader);
289 gl_->DeleteShader(fragment_shader);
290
291 if (!program) {
292 return 0;
293 }
294
295 SetUniform(program, "y_sampler", 0);
296 SetUniform(program, "u_sampler", 1);
297 SetUniform(program, "v_sampler", 2);
298 SetUniform(program, "a_sampler", 3);
299
300 SetUniform(program, "clamp_width", clamp_value_);
301
302 clamp_width_loc_ = gl_->GetUniformLocation(program, "clamp_width");
303 DCHECK(clamp_width_loc_ != -1);
304
305 yuv_matrix_loc_ = gl_->GetUniformLocation(program, "yuv_matrix");
306 DCHECK(yuv_matrix_loc_ != -1);
307
308 yuv_adjust_loc_ = gl_->GetUniformLocation(program, "yuv_adjust");
309 DCHECK(yuv_adjust_loc_ != -1);
310
311 return program;
312 }
313
314 bool VideoDecoderShim::YUVConverter::Initialize() {
315 DCHECK(gl_);
bbudge 2015/05/14 16:45:48 DCHECK in the constructor.
CodeByThePound 2015/05/14 17:42:08 Done.
316 // If texture_rg extension is not available, use slower GL_LUMINANCE.
317 if (context_provider_->ContextCapabilities().gpu.texture_rg) {
318 internal_format_ = GL_RED_EXT;
319 format_ = GL_RED_EXT;
320 } else {
321 internal_format_ = GL_LUMINANCE;
322 format_ = GL_LUMINANCE;
323 }
324
325 if (context_provider_->ContextCapabilities().gpu.max_texture_image_units <
326 4) {
327 // We support YUVA textures and require 4 texture units in the fragment
328 // stage.
329 return false;
330 }
331
332 gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
333
334 gl_->GenFramebuffers(1, &frame_buffer_);
335
336 y_texture_ = CreateTexture();
337 u_texture_ = CreateTexture();
338 v_texture_ = CreateTexture();
339 a_texture_ = CreateTexture();
340
341 // Vertex positions. Also converted to texcoords in vertex shader.
342 GLfloat vtx_buf[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f};
343
344 gl_->GenBuffers(1, &vtx_buffer_);
345 gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_);
346 gl_->BufferData(GL_ARRAY_BUFFER, 2 * sizeof(GLfloat) * 4, vtx_buf,
347 GL_STATIC_DRAW);
348 gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
349
350 program_ = CreateShader();
351
352 gl_->PopGroupMarkerEXT();
353
354 context_provider_->InvalidateGrContext(kGrInvalidateState);
355
356 return (program_ != 0);
357 }
358
359 void VideoDecoderShim::YUVConverter::SetTexcoordClamp(uint32_t stride,
360 uint32_t width) {
361 clamp_width_ = width;
362 if (width != stride) {
363 // Clamp texcoord width to avoid sampling padding pixels.
364 clamp_value_ = static_cast<float>(width) / static_cast<float>(stride);
365 // Further clamp to 1/2 pixel inside to avoid bilinear sampling errors.
366 clamp_value_ -= (1.f / (2.f * static_cast<float>(stride)));
367 } else {
368 // No clamping necessary if width and stride are equal.
369 clamp_value_ = 1.f;
370 }
371 }
372
373 void VideoDecoderShim::YUVConverter::Convert(
374 const scoped_refptr<media::VideoFrame>& frame,
375 GLuint tex_out) {
376 const float* yuv_matrix = 0;
377 const float* yuv_adjust = 0;
378
379 if (video_format_ != frame->format()) {
380 // The constants below were taken from cc/output/gl_renderer.cc.
381 // These values are magic numbers that are used in the transformation from
382 // YUV
bbudge 2015/05/14 16:45:48 nit strange formatting
CodeByThePound 2015/05/14 17:42:09 Must have been done by git cl format. Fixed.
383 // to RGB color values. They are taken from the following webpage:
384 // http://www.fourcc.org/fccyvrgb.php
385 const float yuv_to_rgb_rec601[9] = {
386 1.164f, 1.164f, 1.164f, 0.0f, -.391f, 2.018f, 1.596f, -.813f, 0.0f,
387 };
388 const float yuv_to_rgb_jpeg[9] = {
389 1.f, 1.f, 1.f, 0.0f, -.34414f, 1.772f, 1.402f, -.71414f, 0.0f,
390 };
391 const float yuv_to_rgb_rec709[9] = {
392 1.164f, 1.164f, 1.164f, 0.0f, -0.213f, 2.112f, 1.793f, -0.533f, 0.0f,
393 };
394
395 // These values map to 16, 128, and 128 respectively, and are computed
396 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
397 // They are used in the YUV to RGBA conversion formula:
398 // Y - 16 : Gives 16 values of head and footroom for overshooting
399 // U - 128 : Turns unsigned U into signed U [-128,127]
400 // V - 128 : Turns unsigned V into signed V [-128,127]
401 const float yuv_adjust_constrained[3] = {
402 -0.0625f, -0.5f, -0.5f,
403 };
404 // Same as above, but without the head and footroom.
405 const float yuv_adjust_full[3] = {
406 0.0f, -0.5f, -0.5f,
407 };
408
409 switch (frame->format()) {
410 case media::VideoFrame::YV12: /* 420 */
bbudge 2015/05/14 16:45:48 nit: C++ style comments.
CodeByThePound 2015/05/14 17:42:08 Done.
411 case media::VideoFrame::YV12A:
412 case media::VideoFrame::I420:
413 uv_height_divisor_ = 2;
414 yuv_matrix = yuv_to_rgb_rec601;
415 yuv_adjust = yuv_adjust_constrained;
416 break;
417
418 case media::VideoFrame::YV12HD: /* 420 */
419 uv_height_divisor_ = 2;
420 yuv_matrix = yuv_to_rgb_rec709;
421 yuv_adjust = yuv_adjust_constrained;
422 break;
423
424 case media::VideoFrame::YV12J: /* 420 */
425 uv_height_divisor_ = 2;
426 yuv_matrix = yuv_to_rgb_jpeg;
427 yuv_adjust = yuv_adjust_full;
428 break;
429
430 case media::VideoFrame::YV16: /* 422 */
431 case media::VideoFrame::YV24: /* 444 */
432 uv_height_divisor_ = 1;
433 yuv_matrix = yuv_to_rgb_rec601;
434 yuv_adjust = yuv_adjust_constrained;
435 break;
436
437 default:
438 NOTREACHED();
439 }
440
441 video_format_ = frame->format();
442
443 // Zero these so everything is reset below.
444 y_width_ = y_height_ = 0;
445 }
446
447 gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
448
449 bool set_clamp = false;
450
451 uint32_t ywidth = frame->coded_size().width();
452 uint32_t yheight = frame->coded_size().height();
453
454 DCHECK_EQ(frame->stride(media::VideoFrame::kUPlane),
455 frame->stride(media::VideoFrame::kVPlane));
456
457 uint32_t ystride = frame->stride(media::VideoFrame::kYPlane);
458 uint32_t uvstride = frame->stride(media::VideoFrame::kUPlane);
459
460 // The following code assumes that extended GLES 2.0 state like
461 // UNPACK_SKIP* and UNPACK_ROW_LENGTH (if available) are set to defaults.
462 gl_->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
463
464 if (ystride != y_width_ || yheight != y_height_) {
465 // Choose width based on the stride. Clamp texcoords below.
466 y_width_ = ystride;
467 y_height_ = yheight;
468
469 uv_width_ = uvstride;
470 uv_height_ = y_height_ / uv_height_divisor_;
471
472 SetTexcoordClamp(ystride, ywidth);
473 set_clamp = true;
474
475 // Re-create to resize the textures and upload data.
476 gl_->ActiveTexture(GL_TEXTURE0);
477 gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
478 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_, 0,
479 format_, GL_UNSIGNED_BYTE,
480 frame->data(media::VideoFrame::kYPlane));
481
482 gl_->ActiveTexture(GL_TEXTURE1);
483 gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
484 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
485 0, format_, GL_UNSIGNED_BYTE,
486 frame->data(media::VideoFrame::kUPlane));
487
488 gl_->ActiveTexture(GL_TEXTURE2);
489 gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
490 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
491 0, format_, GL_UNSIGNED_BYTE,
492 frame->data(media::VideoFrame::kVPlane));
493
494 if (video_format_ == media::VideoFrame::YV12A) {
495 DCHECK_EQ(frame->stride(media::VideoFrame::kYPlane),
496 frame->stride(media::VideoFrame::kAPlane));
497 gl_->ActiveTexture(GL_TEXTURE3);
498 gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
499 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_,
500 0, format_, GL_UNSIGNED_BYTE,
501 frame->data(media::VideoFrame::kAPlane));
502 } else {
503 // if there is no alpha channel, then create a 2x2 texture with full
504 // alpha.
505 const uint8_t alpha[4] = {0xff, 0xff, 0xff, 0xff};
506 gl_->ActiveTexture(GL_TEXTURE3);
507 gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
508 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
509 GL_UNSIGNED_BYTE, alpha);
510 }
511 } else {
512 // Width may have changed even though stride remained the same.
513 if (clamp_width_ != ywidth) {
514 SetTexcoordClamp(ystride, ywidth);
515 set_clamp = true;
516 }
517
518 // Bind textures and upload texture data
519 gl_->ActiveTexture(GL_TEXTURE0);
520 gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
521 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_,
522 GL_UNSIGNED_BYTE,
523 frame->data(media::VideoFrame::kYPlane));
524
525 gl_->ActiveTexture(GL_TEXTURE1);
526 gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
527 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
528 GL_UNSIGNED_BYTE,
529 frame->data(media::VideoFrame::kUPlane));
530
531 gl_->ActiveTexture(GL_TEXTURE2);
532 gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
533 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
534 GL_UNSIGNED_BYTE,
535 frame->data(media::VideoFrame::kVPlane));
536
537 if (video_format_ == media::VideoFrame::YV12A) {
538 DCHECK_EQ(frame->stride(media::VideoFrame::kYPlane),
539 frame->stride(media::VideoFrame::kAPlane));
540 gl_->ActiveTexture(GL_TEXTURE3);
541 gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
542 gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_,
543 GL_UNSIGNED_BYTE,
544 frame->data(media::VideoFrame::kAPlane));
545 } else {
546 gl_->ActiveTexture(GL_TEXTURE3);
547 gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
548 }
549 }
550
551 gl_->BindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
552 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
553 tex_out, 0);
554
555 #ifndef NDEBUG
556 // We should probably check for framebuffer complete here, but that
557 // will slow this method down so check only in debug mode.
558 GLint status = gl_->CheckFramebufferStatus(GL_FRAMEBUFFER);
559 if (status != GL_FRAMEBUFFER_COMPLETE) {
560 return;
561 }
562 #endif
563
564 gl_->Viewport(0, 0, ywidth, yheight);
565
566 gl_->UseProgram(program_);
567
568 if (set_clamp) {
569 gl_->Uniform1f(clamp_width_loc_, clamp_value_);
570 }
571
572 if (yuv_matrix) {
573 gl_->UniformMatrix3fv(yuv_matrix_loc_, 1, 0, yuv_matrix);
574 gl_->Uniform3fv(yuv_adjust_loc_, 1, yuv_adjust);
575 }
576
577 gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_);
578 gl_->EnableVertexAttribArray(0);
579 gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
580 static_cast<const void*>(0));
581
582 gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
583
bbudge 2015/05/14 16:45:48 I think a big comment explaining about restoring s
CodeByThePound 2015/05/14 17:42:08 Added.
584 gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
585 gl_->DisableVertexAttribArray(0);
586 gl_->UseProgram(0);
587 gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
588
589 gl_->BindTexture(GL_TEXTURE_2D, 0);
590
591 gl_->ActiveTexture(GL_TEXTURE2);
592 gl_->BindTexture(GL_TEXTURE_2D, 0);
593
594 gl_->ActiveTexture(GL_TEXTURE1);
595 gl_->BindTexture(GL_TEXTURE_2D, 0);
596
597 gl_->ActiveTexture(GL_TEXTURE0);
598 gl_->BindTexture(GL_TEXTURE_2D, 0);
599
600 gl_->PopGroupMarkerEXT();
601
602 context_provider_->InvalidateGrContext(kGrInvalidateState);
603 }
604
31 struct VideoDecoderShim::PendingDecode { 605 struct VideoDecoderShim::PendingDecode {
32 PendingDecode(uint32_t decode_id, 606 PendingDecode(uint32_t decode_id,
33 const scoped_refptr<media::DecoderBuffer>& buffer); 607 const scoped_refptr<media::DecoderBuffer>& buffer);
34 ~PendingDecode(); 608 ~PendingDecode();
35 609
36 const uint32_t decode_id; 610 const uint32_t decode_id;
37 const scoped_refptr<media::DecoderBuffer> buffer; 611 const scoped_refptr<media::DecoderBuffer> buffer;
38 }; 612 };
39 613
40 VideoDecoderShim::PendingDecode::PendingDecode( 614 VideoDecoderShim::PendingDecode::PendingDecode(
41 uint32_t decode_id, 615 uint32_t decode_id,
42 const scoped_refptr<media::DecoderBuffer>& buffer) 616 const scoped_refptr<media::DecoderBuffer>& buffer)
43 : decode_id(decode_id), buffer(buffer) { 617 : decode_id(decode_id), buffer(buffer) {
44 } 618 }
45 619
46 VideoDecoderShim::PendingDecode::~PendingDecode() { 620 VideoDecoderShim::PendingDecode::~PendingDecode() {
47 } 621 }
48 622
49 struct VideoDecoderShim::PendingFrame { 623 struct VideoDecoderShim::PendingFrame {
50 explicit PendingFrame(uint32_t decode_id); 624 explicit PendingFrame(uint32_t decode_id);
51 PendingFrame(uint32_t decode_id, 625 PendingFrame(uint32_t decode_id,
52 const gfx::Size& coded_size, 626 const scoped_refptr<media::VideoFrame>& frame);
53 const gfx::Rect& visible_rect);
54 ~PendingFrame(); 627 ~PendingFrame();
55 628
56 const uint32_t decode_id; 629 const uint32_t decode_id;
57 const gfx::Size coded_size; 630 scoped_refptr<media::VideoFrame> video_frame;
58 const gfx::Rect visible_rect;
59 std::vector<uint8_t> argb_pixels;
60 631
61 private: 632 private:
62 // This could be expensive to copy, so guard against that. 633 // This could be expensive to copy, so guard against that.
63 DISALLOW_COPY_AND_ASSIGN(PendingFrame); 634 DISALLOW_COPY_AND_ASSIGN(PendingFrame);
64 }; 635 };
65 636
66 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id) 637 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id)
67 : decode_id(decode_id) { 638 : decode_id(decode_id) {
68 } 639 }
69 640
70 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id, 641 VideoDecoderShim::PendingFrame::PendingFrame(
71 const gfx::Size& coded_size, 642 uint32_t decode_id,
72 const gfx::Rect& visible_rect) 643 const scoped_refptr<media::VideoFrame>& frame)
73 : decode_id(decode_id), 644 : 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 } 645 }
78 646
79 VideoDecoderShim::PendingFrame::~PendingFrame() { 647 VideoDecoderShim::PendingFrame::~PendingFrame() {
80 } 648 }
81 649
82 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving 650 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving
83 // calls from the VideoDecodeShim on the main thread and sending results back. 651 // 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 652 // This class is constructed on the main thread, but used and destructed on the
85 // media thread. 653 // media thread.
86 class VideoDecoderShim::DecoderImpl { 654 class VideoDecoderShim::DecoderImpl {
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 830 }
263 831
264 void VideoDecoderShim::DecoderImpl::OnOutputComplete( 832 void VideoDecoderShim::DecoderImpl::OnOutputComplete(
265 const scoped_refptr<media::VideoFrame>& frame) { 833 const scoped_refptr<media::VideoFrame>& frame) {
266 // Software decoders are expected to generated frames only when a Decode() 834 // Software decoders are expected to generated frames only when a Decode()
267 // call is pending. 835 // call is pending.
268 DCHECK(awaiting_decoder_); 836 DCHECK(awaiting_decoder_);
269 837
270 scoped_ptr<PendingFrame> pending_frame; 838 scoped_ptr<PendingFrame> pending_frame;
271 if (!frame->end_of_stream()) { 839 if (!frame->end_of_stream()) {
272 pending_frame.reset(new PendingFrame( 840 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 { 841 } else {
280 pending_frame.reset(new PendingFrame(decode_id_)); 842 pending_frame.reset(new PendingFrame(decode_id_));
281 } 843 }
282 844
283 main_message_loop_->PostTask(FROM_HERE, 845 main_message_loop_->PostTask(FROM_HERE,
284 base::Bind(&VideoDecoderShim::OnOutputComplete, 846 base::Bind(&VideoDecoderShim::OnOutputComplete,
285 shim_, 847 shim_,
286 base::Passed(&pending_frame))); 848 base::Passed(&pending_frame)));
287 } 849 }
288 850
289 void VideoDecoderShim::DecoderImpl::OnResetComplete() { 851 void VideoDecoderShim::DecoderImpl::OnResetComplete() {
290 main_message_loop_->PostTask( 852 main_message_loop_->PostTask(
291 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_)); 853 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_));
292 } 854 }
293 855
294 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host) 856 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host)
295 : state_(UNINITIALIZED), 857 : state_(UNINITIALIZED),
296 host_(host), 858 host_(host),
297 media_task_runner_( 859 media_task_runner_(
298 RenderThreadImpl::current()->GetMediaThreadTaskRunner()), 860 RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
299 context_provider_( 861 context_provider_(
300 RenderThreadImpl::current()->SharedMainThreadContextProvider()), 862 RenderThreadImpl::current()->SharedMainThreadContextProvider()),
301 texture_pool_size_(0), 863 texture_pool_size_(0),
302 num_pending_decodes_(0), 864 num_pending_decodes_(0),
303 weak_ptr_factory_(this) { 865 weak_ptr_factory_(this) {
304 DCHECK(host_); 866 DCHECK(host_);
305 DCHECK(media_task_runner_.get()); 867 DCHECK(media_task_runner_.get());
306 DCHECK(context_provider_.get()); 868 DCHECK(context_provider_.get());
307 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr())); 869 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr()));
870 yuv_converter_.reset(new YUVConverter(context_provider_));
bbudge 2015/05/14 16:45:48 nit: this could be initialized sooner, in the init
CodeByThePound 2015/05/14 17:42:08 Done.
308 } 871 }
309 872
310 VideoDecoderShim::~VideoDecoderShim() { 873 VideoDecoderShim::~VideoDecoderShim() {
311 DCHECK(RenderThreadImpl::current()); 874 DCHECK(RenderThreadImpl::current());
312 // Delete any remaining textures. 875 // Delete any remaining textures.
313 TextureIdMap::iterator it = texture_id_map_.begin(); 876 TextureIdMap::iterator it = texture_id_map_.begin();
314 for (; it != texture_id_map_.end(); ++it) 877 for (; it != texture_id_map_.end(); ++it)
315 DeleteTexture(it->second); 878 DeleteTexture(it->second);
316 texture_id_map_.clear(); 879 texture_id_map_.clear();
317 880
(...skipping 18 matching lines...) Expand all
336 DCHECK_EQ(state_, UNINITIALIZED); 899 DCHECK_EQ(state_, UNINITIALIZED);
337 media::VideoCodec codec = media::kUnknownVideoCodec; 900 media::VideoCodec codec = media::kUnknownVideoCodec;
338 if (profile <= media::H264PROFILE_MAX) 901 if (profile <= media::H264PROFILE_MAX)
339 codec = media::kCodecH264; 902 codec = media::kCodecH264;
340 else if (profile <= media::VP8PROFILE_MAX) 903 else if (profile <= media::VP8PROFILE_MAX)
341 codec = media::kCodecVP8; 904 codec = media::kCodecVP8;
342 else if (profile <= media::VP9PROFILE_MAX) 905 else if (profile <= media::VP9PROFILE_MAX)
343 codec = media::kCodecVP9; 906 codec = media::kCodecVP9;
344 DCHECK_NE(codec, media::kUnknownVideoCodec); 907 DCHECK_NE(codec, media::kUnknownVideoCodec);
345 908
909 if (!yuv_converter_->Initialize()) {
910 return false;
bbudge 2015/05/14 16:45:48 Does this mean software fallback won't work in som
CodeByThePound 2015/05/14 17:42:08 The YUVConverter initialization could fail if 1) t
bbudge 2015/05/14 20:47:59 Let's leave it as is for now. We could add fallbac
911 }
912
346 media::VideoDecoderConfig config( 913 media::VideoDecoderConfig config(
347 codec, 914 codec,
348 profile, 915 profile,
349 media::VideoFrame::YV12, 916 media::VideoFrame::YV12,
350 gfx::Size(32, 24), // Small sizes that won't fail. 917 gfx::Size(32, 24), // Small sizes that won't fail.
351 gfx::Rect(32, 24), 918 gfx::Rect(32, 24),
352 gfx::Size(32, 24), 919 gfx::Size(32, 24),
353 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed. 920 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed.
354 0 /* extra_data_size */, 921 0 /* extra_data_size */,
355 false /* decryption */); 922 false /* decryption */);
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 num_pending_decodes_--; 1031 num_pending_decodes_--;
465 completed_decodes_.push(decode_id); 1032 completed_decodes_.push(decode_id);
466 1033
467 // If frames are being queued because we're out of textures, don't notify 1034 // 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 1035 // 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. 1036 // the host from sending buffers that will cause pending_frames_ to grow.
470 if (pending_frames_.empty()) 1037 if (pending_frames_.empty())
471 NotifyCompletedDecodes(); 1038 NotifyCompletedDecodes();
472 } 1039 }
473 1040
474 void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) { 1041 void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> pframe) {
bbudge 2015/05/14 16:45:48 nit: Chrome style is usually 'frame'
CodeByThePound 2015/05/14 17:42:08 Done.
475 DCHECK(RenderThreadImpl::current()); 1042 DCHECK(RenderThreadImpl::current());
476 DCHECK(host_); 1043 DCHECK(host_);
477 1044
478 if (!frame->argb_pixels.empty()) { 1045 if (pframe->video_frame) {
479 if (texture_size_ != frame->coded_size) { 1046 if (texture_size_ != pframe->video_frame->coded_size()) {
480 // If the size has changed, all current textures must be dismissed. Add 1047 // 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 1048 // 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. 1049 // use by the plugin. We will dismiss the rest as they are recycled.
483 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); 1050 for (TextureIdMap::const_iterator it = texture_id_map_.begin();
484 it != texture_id_map_.end(); 1051 it != texture_id_map_.end();
485 ++it) { 1052 ++it) {
486 textures_to_dismiss_.insert(it->first); 1053 textures_to_dismiss_.insert(it->first);
487 } 1054 }
488 for (TextureIdSet::const_iterator it = available_textures_.begin(); 1055 for (TextureIdSet::const_iterator it = available_textures_.begin();
489 it != available_textures_.end(); 1056 it != available_textures_.end();
490 ++it) { 1057 ++it) {
491 DismissTexture(*it); 1058 DismissTexture(*it);
492 } 1059 }
493 available_textures_.clear(); 1060 available_textures_.clear();
494 FlushCommandBuffer(); 1061 FlushCommandBuffer();
495 1062
496 DCHECK(pending_texture_mailboxes_.empty()); 1063 DCHECK(pending_texture_mailboxes_.empty());
497 for (uint32_t i = 0; i < texture_pool_size_; i++) 1064 for (uint32_t i = 0; i < texture_pool_size_; i++)
498 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); 1065 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate());
499 1066
500 host_->RequestTextures(texture_pool_size_, 1067 host_->RequestTextures(texture_pool_size_,
501 frame->coded_size, 1068 pframe->video_frame->coded_size(), GL_TEXTURE_2D,
502 GL_TEXTURE_2D,
503 pending_texture_mailboxes_); 1069 pending_texture_mailboxes_);
504 texture_size_ = frame->coded_size; 1070 texture_size_ = pframe->video_frame->coded_size();
505 } 1071 }
506 1072
507 pending_frames_.push(linked_ptr<PendingFrame>(frame.release())); 1073 pending_frames_.push(linked_ptr<PendingFrame>(pframe.release()));
508 SendPictures(); 1074 SendPictures();
509 } 1075 }
510 } 1076 }
511 1077
512 void VideoDecoderShim::SendPictures() { 1078 void VideoDecoderShim::SendPictures() {
513 DCHECK(RenderThreadImpl::current()); 1079 DCHECK(RenderThreadImpl::current());
514 DCHECK(host_); 1080 DCHECK(host_);
515 while (!pending_frames_.empty() && !available_textures_.empty()) { 1081 while (!pending_frames_.empty() && !available_textures_.empty()) {
516 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); 1082 const linked_ptr<PendingFrame>& frame = pending_frames_.front();
517 1083
518 TextureIdSet::iterator it = available_textures_.begin(); 1084 TextureIdSet::iterator it = available_textures_.begin();
519 uint32_t texture_id = *it; 1085 uint32_t texture_id = *it;
520 available_textures_.erase(it); 1086 available_textures_.erase(it);
521 1087
522 uint32_t local_texture_id = texture_id_map_[texture_id]; 1088 uint32_t local_texture_id = texture_id_map_[texture_id];
523 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); 1089
524 gles2->ActiveTexture(GL_TEXTURE0); 1090 yuv_converter_->Convert(frame->video_frame, local_texture_id);
525 gles2->BindTexture(GL_TEXTURE_2D, 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 1091
542 host_->PictureReady(media::Picture(texture_id, frame->decode_id, 1092 host_->PictureReady(media::Picture(texture_id, frame->decode_id,
543 frame->visible_rect, false)); 1093 frame->video_frame->visible_rect(),
1094 false));
544 pending_frames_.pop(); 1095 pending_frames_.pop();
545 } 1096 }
546 1097
547 FlushCommandBuffer(); 1098 FlushCommandBuffer();
548 1099
549 if (pending_frames_.empty()) { 1100 if (pending_frames_.empty()) {
550 // If frames aren't backing up, notify the host of any completed decodes so 1101 // If frames aren't backing up, notify the host of any completed decodes so
551 // it can send more buffers. 1102 // it can send more buffers.
552 NotifyCompletedDecodes(); 1103 NotifyCompletedDecodes();
553 1104
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) { 1144 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) {
594 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); 1145 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
595 gles2->DeleteTextures(1, &texture_id); 1146 gles2->DeleteTextures(1, &texture_id);
596 } 1147 }
597 1148
598 void VideoDecoderShim::FlushCommandBuffer() { 1149 void VideoDecoderShim::FlushCommandBuffer() {
599 context_provider_->ContextGL()->Flush(); 1150 context_provider_->ContextGL()->Flush();
600 } 1151 }
601 1152
602 } // namespace content 1153 } // 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