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

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: updates to failure path in CreateShader 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 #include "base/logging.h"
12 #include "base/numerics/safe_conversions.h" 13 #include "base/numerics/safe_conversions.h"
13 #include "base/single_thread_task_runner.h" 14 #include "base/single_thread_task_runner.h"
14 #include "cc/blink/context_provider_web_context.h" 15 #include "cc/blink/context_provider_web_context.h"
15 #include "content/public/renderer/render_thread.h" 16 #include "content/public/renderer/render_thread.h"
16 #include "content/renderer/pepper/pepper_video_decoder_host.h" 17 #include "content/renderer/pepper/pepper_video_decoder_host.h"
17 #include "content/renderer/render_thread_impl.h" 18 #include "content/renderer/render_thread_impl.h"
18 #include "gpu/command_buffer/client/gles2_implementation.h" 19 #include "gpu/command_buffer/client/gles2_implementation.h"
19 #include "media/base/decoder_buffer.h" 20 #include "media/base/decoder_buffer.h"
20 #include "media/base/limits.h" 21 #include "media/base/limits.h"
21 #include "media/base/video_decoder.h" 22 #include "media/base/video_decoder.h"
22 #include "media/blink/skcanvas_video_renderer.h" 23 #include "media/blink/skcanvas_video_renderer.h"
23 #include "media/filters/ffmpeg_video_decoder.h" 24 #include "media/filters/ffmpeg_video_decoder.h"
24 #include "media/filters/vpx_video_decoder.h" 25 #include "media/filters/vpx_video_decoder.h"
25 #include "media/video/picture.h" 26 #include "media/video/picture.h"
26 #include "media/video/video_decode_accelerator.h" 27 #include "media/video/video_decode_accelerator.h"
27 #include "ppapi/c/pp_errors.h" 28 #include "ppapi/c/pp_errors.h"
28 29
29 namespace content { 30 namespace content {
30 31
32 //
33 // YUV->RGB converter class using a shader and FBO
34 //
35 class YUVConv {
36 public:
bbudge 2015/05/01 20:08:59 chromium indent of public/private is 1 space, then
37 YUVConv( const scoped_refptr<cc_blink::ContextProviderWebContext> & );
bbudge 2015/05/01 20:08:59 Chromium coding style: no space after '(', '>', an
38 ~YUVConv();
39 bool Initialize();
40 void Convert( const scoped_refptr<media::VideoFrame> & frame,
41 GLuint texOut );
bbudge 2015/05/01 20:08:59 Style: Chrome uses texture_out style rather than c
42
43 private:
44 GLuint CreateShader();
45 GLuint CompileShader( const char * name, GLuint type, const char * code );
bbudge 2015/05/01 20:08:58 s/char * name/char* name
46 GLuint CreateProgram( const char * name, GLuint vshader, GLuint fshader );
47 bool SetUniform( GLuint program, const char * name, int value );
48 bool SetUniform( GLuint program, const char * name, float value );
49 GLuint CreateTexture();
50
51 private:
bbudge 2015/05/01 20:08:59 duplicate private
52 scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
53 gpu::gles2::GLES2Interface* gl_;
54 GLuint frame_buffer_;
55 GLuint vtx_buffer_;
56 GLuint program_;
57
58 GLuint y_texture_;
59 GLuint u_texture_;
60 GLuint v_texture_;
61
62 GLuint internal_format_;
63 GLuint format_;
64
65 GLuint y_width_;
66 GLuint y_height_;
67
68 GLuint uv_width_;
69 GLuint uv_height_;
70
71 GLfloat clamp_value_;
72 GLuint clamp_width_;
73 GLint clamp_width_loc_;
74
75 DISALLOW_COPY_AND_ASSIGN(YUVConv);
76 };
77
78 YUVConv::YUVConv(
79 const scoped_refptr<cc_blink::ContextProviderWebContext> & ctx_p )
bbudge 2015/05/01 20:08:59 s/ctx_p/context_provider You can use 'git cl form
80 : context_provider_( ctx_p )
81 , gl_( context_provider_->ContextGL() )
bbudge 2015/05/01 20:08:59 Chromium style puts the commas on the previous lin
82 , frame_buffer_(0)
83 , vtx_buffer_(0)
84 , program_(0)
85 , y_texture_(0)
86 , u_texture_(0)
87 , v_texture_(0)
88 , internal_format_(0)
89 , format_(0)
90 , y_width_(2)
91 , y_height_(2)
92 , uv_width_(2)
93 , uv_height_(2)
94 , clamp_value_(1.f)
95 , clamp_width_(0)
96 , clamp_width_loc_(0) {
97 }
98
99 YUVConv::~YUVConv() {
100 // delete textures
101 if( y_texture_ )
102 gl_->DeleteTextures( 1, &y_texture_ );
103
104 if( u_texture_ )
105 gl_->DeleteTextures( 1, &u_texture_ );
106
107 if( v_texture_ )
108 gl_->DeleteTextures( 1, &v_texture_ );
109
110 // delete framebuffer
111 if( frame_buffer_ )
112 gl_->DeleteFramebuffers( 1, &frame_buffer_ );
113
114 // delete vertex buffer
115 if( vtx_buffer_ )
116 gl_->DeleteBuffers( 1, &vtx_buffer_ );
117
118 // delete program
119 if( program_ )
120 gl_->DeleteProgram( program_ );
121 }
122
123 GLuint YUVConv::CreateTexture() {
124 GLuint tex = 0;
125
126 // create texture
127 gl_->GenTextures(1, &tex);
128 gl_->BindTexture(GL_TEXTURE_2D, tex);
129
130 // create texture with default size - will be resized upon first frame
131 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
132 GL_UNSIGNED_BYTE, NULL);
133
134 // set params
135 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
136 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
137 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
138 gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
139
140 // unbind
141 gl_->BindTexture(GL_TEXTURE_2D, 0);
142
143 return tex;
144 }
145
146 GLuint YUVConv::CompileShader( const char * name, GLuint type,
147 const char * code ) {
148 GLuint shader = gl_->CreateShader( type );
149
150 gl_->ShaderSource(shader, 1, (const GLchar**) &code, NULL);
151 gl_->CompileShader(shader);
152
153 GLint status = 0;
154
155 gl_->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
156 if(status != GL_TRUE)
157 {
158 GLint maxLength = 0;
159 gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
160
161 // The maxLength includes the NULL character
162 std::string errorLog(0,maxLength);
163 gl_->GetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
164
165 LOG(ERROR) << name << " shader compilation failed: "
166 << errorLog.c_str();
167 gl_->DeleteShader( shader );
168 return 0;
169 }
170
171 return shader;
172 }
173
174 GLuint YUVConv::CreateProgram( const char * name, GLuint vshader,
175 GLuint fshader ) {
176 GLuint program = gl_->CreateProgram();
177 gl_->AttachShader(program, vshader);
178 gl_->AttachShader(program, fshader);
179
180 // bind known vertex position
181 gl_->BindAttribLocation(program, 0, "aPosition");
182
183 gl_->LinkProgram(program);
184
185 GLint status = 0;
186
187 gl_->GetProgramiv(program, GL_LINK_STATUS, &status);
188 if(status != GL_TRUE)
189 {
190 GLint maxLength = 0;
191 gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
192
193 // The maxLength includes the NULL character
194 std::string errorLog(0,maxLength);
195 gl_->GetProgramInfoLog(program, maxLength, &maxLength, &errorLog[0]);
196
197 LOG(ERROR) << name << " program linking failed: "
198 << errorLog.c_str();
199 return 0;
200 }
201
202 return program;
203 }
204
205 bool YUVConv::SetUniform( GLuint program, const char * name,
206 int value ) {
207 bool result = false;
208 GLint loc = gl_->GetUniformLocation( program, name );
209 if( loc != -1 )
210 {
211 gl_->UseProgram( program );
212 gl_->Uniform1i( loc, value );
213 gl_->UseProgram( 0 );
214 result = true;
215 }
216
217 return result;
218 }
219
220 bool YUVConv::SetUniform( GLuint program, const char * name,
221 float value ) {
222 bool result = false;
223 GLint loc = gl_->GetUniformLocation( program, name );
224 if( loc != -1 )
225 {
226 gl_->UseProgram( program );
227 gl_->Uniform1f( loc, value );
228 gl_->UseProgram( 0 );
229 result = true;
230 }
231
232 return result;
233 }
234
235 GLuint YUVConv::CreateShader() {
236 const char* vertShader =
237 "precision mediump float;\n"
238 "attribute vec2 aPosition;\n"
239 "varying vec2 vTexCoord;\n"
240 "uniform float clamp_width;\n"
241 "void main()\n"
242 "{\n"
243 " gl_Position = vec4( aPosition.xy, 0, 1 );\n"
244 // convert vertex positions to texcoords, clamp x
245 " vec2 tmp = aPosition*0.5+0.5;\n"
246 " vTexCoord = vec2(min(tmp.x, clamp_width), tmp.y);\n"
247 "}";
248
249 const char* fragShader =
250 "precision mediump float;\n"
251 "varying vec2 vTexCoord;\n"
252 "#define texSample texture2D\n"
253 "#define fragColor gl_FragColor\n"
254 "uniform sampler2D texY;\n"
255 "uniform sampler2D texU;\n"
256 "uniform sampler2D texV;\n"
257 "void main()\n"
258 "{\n"
259 // These values are magic numbers that are used in the transformation
260 // from YUV to RGB color values. They are taken from the following
261 // webpage: http://www.fourcc.org/fccyvrgb.php. In this case Rec. 601.
262 // yuv_2_rgb and yuv_adjust_constrained were taken from gl_renderer.cc
263 " const mat3 yuv_2_rgb = mat3( 1.164, 1.164, 1.164,\n"
264 " 0.0, -.391, 2.018,\n"
265 " 1.596, -.813, 0.0 );\n"
266 // These values map to 16, 128, and 128 respectively, and are computed
267 // as a fraction over 256 (e.g. 16 / 256 = 0.0625).
268 // They are used in the YUV to RGBA conversion formula:
269 // Y - 16 : Gives 16 values of head and footroom for overshooting
270 // U - 128 : Turns unsigned U into signed U [-128,127]
271 // V - 128 : Turns unsigned V into signed V [-128,127]
272 " const vec3 yuv_adjust_constrained = vec3( -0.0625, -0.5, -0.5 );\n"
273
274 " vec3 yuv = vec3( texSample(texY, vTexCoord).x,\n"
275 " texSample(texU, vTexCoord).x,\n"
276 " texSample(texV, vTexCoord).x ) +\n"
277 " yuv_adjust_constrained;\n"
278 " fragColor = vec4( yuv_2_rgb * yuv, 1.0 );\n"
279 "}";
280
281 //
282 // Compile vertex and fragment shaders.
283 //
284 GLuint vertexShader = CompileShader( "Vertex Shader", GL_VERTEX_SHADER,
285 vertShader );
286 if( !vertexShader )
287 {
288 return 0;
289 }
290
291 GLuint fragmentShader = CompileShader("Fragment Shader", GL_FRAGMENT_SHADER,
292 fragShader);
293 if( !fragmentShader )
294 {
295 gl_->DeleteShader( vertexShader );
296 return 0;
297 }
298
299 //
300 // Create the program
301 //
302 GLuint program = CreateProgram( "YUVConv Program", vertexShader,
303 fragmentShader );
304
305 // delete shaders since they are no longer needed
306 gl_->DeleteShader( vertexShader );
307 gl_->DeleteShader( fragmentShader );
308
309 if( !program )
310 {
311 return 0;
312 }
313
314 GLuint result = program;
315
316 //
317 // Bind samplers to texture units - which never change.
318 //
319 if( !SetUniform( program, "texY", 0 ) )
320 {
321 result = 0;
322 }
323 if( !SetUniform( program, "texU", 1 ) )
324 {
325 result = 0;
326 }
327 if( !SetUniform( program, "texV", 2 ) )
328 {
329 result = 0;
330 }
331
332 // set default clamp width
333 if( !SetUniform( program, "clamp_width", clamp_value_ ) )
334 {
335 result = 0;
336 }
337
338 // store clamp width loc for later
339 clamp_width_loc_ = gl_->GetUniformLocation( program, "clamp_width" );
340 if( clamp_width_loc_ < 0 )
341 {
342 result = 0;
343 }
344
345 if( !result )
346 {
347 gl_->DeleteProgram( program );
348 }
349
350 return result;
351 }
352
353 bool YUVConv::Initialize() {
354
355 //
356 // Determine formats to use based on whether GL_RED is available or
357 // whether we need to use GL_LUMINANCE.
358 //
359 DCHECK(gl_);
360 if( context_provider_->ContextCapabilities().gpu.texture_rg )
361 {
362 internal_format_ = GL_RED_EXT;
363 format_ = GL_RED_EXT;
364 }
365 else
366 {
367 internal_format_ = GL_LUMINANCE;
368 format_ = GL_LUMINANCE;
369 }
370
371 // set group marker
372 gl_->PushGroupMarkerEXT(0, "YUVConvContext");
373
374 //
375 // Create Framebuffer
376 //
377 gl_->GenFramebuffers(1, &frame_buffer_);
378
379 //
380 // Create some default textures to hold Y,U,V values
381 //
382 y_texture_ = CreateTexture();
383 u_texture_ = CreateTexture();
384 v_texture_ = CreateTexture();
385
386 //
387 // Create Vertex Buffer
388 //
389 // Vertex positions. Also converted to texcoords in vertex shader.
390 GLfloat vtxBuf[] = { -1.f, -1.f,
391 1.f, -1.f,
392 -1.f, 1.f,
393 1.f, 1.f };
394
395 // Create buffer
396 gl_->GenBuffers(1, &vtx_buffer_);
397 gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_);
398 // Populate it
399 gl_->BufferData(GL_ARRAY_BUFFER, 2*sizeof( GLfloat ) * 4, vtxBuf,
400 GL_STATIC_DRAW );
401 // unbind
402 gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
403
404 //
405 // Create Shader
406 //
407 program_ = CreateShader();
408
409 gl_->PopGroupMarkerEXT();
410
411 return true;
412 }
413
414 void YUVConv::Convert( const scoped_refptr<media::VideoFrame> & frame,
415 GLuint texOut ) {
416 int divisor_height;
417 bool supported_format = true;
418
419 // make sure we support this format
420 switch( frame->format() )
421 {
422 case media::VideoFrame::YV12: /* 420 */
423 case media::VideoFrame::I420: /* 420 */
424 divisor_height = 2;
425 break;
426
427 case media::VideoFrame::YV16: /* 422 */
428 divisor_height = 1;
429 break;
430
431 case media::VideoFrame::YV24: /* 444 */
432 divisor_height = 1;
433 break;
434
435 default:
436 // rest are not supported..
437 supported_format = false;
438 break;
439 }
440
441 // set group marker
442 gl_->PushGroupMarkerEXT(0, "YUVConvContext");
443
444 bool set_clamp = false;
445
446 uint32_t ywidth = frame->coded_size().width();
447 uint32_t yheight = frame->coded_size().height();
448
449 if( supported_format )
450 {
451 DCHECK_EQ(frame->stride(media::VideoFrame::kUPlane),
452 frame->stride(media::VideoFrame::kVPlane));
453
454 uint32_t ystride = frame->stride(media::VideoFrame::kYPlane);
455 uint32_t uvstride = frame->stride(media::VideoFrame::kUPlane);
456
457 // resize textures if necessary
458 if( ystride != y_width_ || yheight != y_height_ )
459 {
460 // choose width based on the stride
461 // then, clamp later
462 y_width_ = ystride;
463 y_height_ = yheight;
464
465 uv_width_ = uvstride;
466 uv_height_ = y_height_ / divisor_height;
467
468 if( (ystride != ywidth) || (clamp_width_ != ywidth) )
469 {
470 if( clamp_width_ != ywidth )
471 {
472 // clamp width to avoid sampling padding pixels
473 clamp_width_ = ywidth;
474 clamp_value_ = static_cast<float>( ywidth ) /
475 static_cast<float>( ystride );
476 // clamp to 1/2 pixel inside to avoid bilinear sampling errors
477 clamp_value_ -= (1.f /
478 (2.f * static_cast<float>( ystride ) ) );
479
480 set_clamp = true;
481 }
482 }
483
484 //
485 // Resize the textures and upload data
486 //
487 gl_->ActiveTexture( GL_TEXTURE0 );
488 gl_->BindTexture( GL_TEXTURE_2D, y_texture_ );
489 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_,
490 0, format_, GL_UNSIGNED_BYTE,
491 frame->data(media::VideoFrame::kYPlane));
492
493 gl_->ActiveTexture( GL_TEXTURE1 );
494 gl_->BindTexture( GL_TEXTURE_2D, u_texture_ );
495 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_,
496 uv_height_, 0, format_, GL_UNSIGNED_BYTE,
497 frame->data(media::VideoFrame::kUPlane));
498
499 gl_->ActiveTexture( GL_TEXTURE2 );
500 gl_->BindTexture( GL_TEXTURE_2D, v_texture_ );
501 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_,
502 uv_height_, 0, format_, GL_UNSIGNED_BYTE,
503 frame->data(media::VideoFrame::kVPlane));
504 }
505 else
506 {
507 //
508 // Bind textures and upload texture data
509 //
510 gl_->ActiveTexture( GL_TEXTURE0 );
511 gl_->BindTexture( GL_TEXTURE_2D, y_texture_ );
512 gl_->TexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_,
513 format_, GL_UNSIGNED_BYTE,
514 frame->data(media::VideoFrame::kYPlane));
515
516 gl_->ActiveTexture( GL_TEXTURE1 );
517 gl_->BindTexture( GL_TEXTURE_2D, u_texture_ );
518 gl_->TexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_,
519 format_, GL_UNSIGNED_BYTE,
520 frame->data(media::VideoFrame::kUPlane));
521
522 gl_->ActiveTexture( GL_TEXTURE2 );
523 gl_->BindTexture( GL_TEXTURE_2D, v_texture_ );
524 gl_->TexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_,
525 format_, GL_UNSIGNED_BYTE,
526 frame->data(media::VideoFrame::kVPlane));
527 }
528 }
529 else
530 {
531 //
532 // Unsupported format - set textures to be 4x4 and produce a red output
533 // 2x2 texture didn't seem to work
534 //
535 uint8_t yudata[4*4];
536 memset( yudata, 0x5e, 4*4 );
537 gl_->ActiveTexture( GL_TEXTURE0 );
538 gl_->BindTexture( GL_TEXTURE_2D, y_texture_ );
539 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4,
540 0, format_, GL_UNSIGNED_BYTE, yudata );
541
542 gl_->ActiveTexture( GL_TEXTURE1 );
543 gl_->BindTexture( GL_TEXTURE_2D, u_texture_ );
544 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4,
545 0, format_, GL_UNSIGNED_BYTE, yudata );
546
547 uint8_t vdata[4*4];
548 memset( vdata, 0xe7, 4*4 );
549 gl_->ActiveTexture( GL_TEXTURE2 );
550 gl_->BindTexture( GL_TEXTURE_2D, v_texture_ );
551 gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4,
552 0, format_, GL_UNSIGNED_BYTE, vdata );
553
554 if( clamp_value_ != 1.f )
555 {
556 set_clamp = true;
557 clamp_value_ = 1.f;
558 }
559 }
560
561 // since we modify the viewport, save it here
562 // MMM - is this necessary?
563 GLint viewport[4] = {0};
564 gl_->GetIntegerv( GL_VIEWPORT, viewport );
565
566 //
567 // bind framebuffer and output texture
568 //
569 gl_->BindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
570 gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
571 GL_TEXTURE_2D, texOut, 0);
572
573 #ifndef NDEBUG
574 // NOTE: we should probably check for framebuffer complete here, but that
575 // will slow this method down so check in debug mode
576 GLint status = gl_->CheckFramebufferStatus( GL_FRAMEBUFFER );
577 if( status != GL_FRAMEBUFFER_COMPLETE )
578 {
579 return;
580 }
581 #endif
582
583 //
584 // Set viewport as dimensions of the video frame
585 //
586 gl_->Viewport( 0, 0, ywidth, yheight );
587
588 //
589 // Enable shader
590 //
591 gl_->UseProgram( program_ );
592
593 if( set_clamp )
594 {
595 gl_->Uniform1f( clamp_width_loc_, clamp_value_ );
596 }
597
598 //
599 // Render
600 //
601 gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_);
602 gl_->EnableVertexAttribArray(0);
603 gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat),
604 static_cast<const void *>(0));
605
606 // draw
607 gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
608
609 // disable everything we enabled
610 gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
611 gl_->DisableVertexAttribArray(0);
612 gl_->UseProgram(0);
613 gl_->BindFramebuffer( GL_FRAMEBUFFER, 0 );
614
615 // unbind textures
616 // active texture is still 2
617 gl_->BindTexture( GL_TEXTURE_2D, 0 );
618
619 gl_->ActiveTexture( GL_TEXTURE1 );
620 gl_->BindTexture( GL_TEXTURE_2D, 0 );
621
622 gl_->ActiveTexture( GL_TEXTURE0 );
623 gl_->BindTexture( GL_TEXTURE_2D, 0 );
624
625 // reset former viewport
626 gl_->Viewport( viewport[0], viewport[1], viewport[2], viewport[3] );
627
628 gl_->PopGroupMarkerEXT();
629 }
630
31 struct VideoDecoderShim::PendingDecode { 631 struct VideoDecoderShim::PendingDecode {
32 PendingDecode(uint32_t decode_id, 632 PendingDecode(uint32_t decode_id,
33 const scoped_refptr<media::DecoderBuffer>& buffer); 633 const scoped_refptr<media::DecoderBuffer>& buffer);
34 ~PendingDecode(); 634 ~PendingDecode();
35 635
36 const uint32_t decode_id; 636 const uint32_t decode_id;
37 const scoped_refptr<media::DecoderBuffer> buffer; 637 const scoped_refptr<media::DecoderBuffer> buffer;
38 }; 638 };
39 639
40 VideoDecoderShim::PendingDecode::PendingDecode( 640 VideoDecoderShim::PendingDecode::PendingDecode(
41 uint32_t decode_id, 641 uint32_t decode_id,
42 const scoped_refptr<media::DecoderBuffer>& buffer) 642 const scoped_refptr<media::DecoderBuffer>& buffer)
43 : decode_id(decode_id), buffer(buffer) { 643 : decode_id(decode_id), buffer(buffer) {
44 } 644 }
45 645
46 VideoDecoderShim::PendingDecode::~PendingDecode() { 646 VideoDecoderShim::PendingDecode::~PendingDecode() {
47 } 647 }
48 648
49 struct VideoDecoderShim::PendingFrame { 649 struct VideoDecoderShim::PendingFrame {
50 explicit PendingFrame(uint32_t decode_id); 650 explicit PendingFrame(uint32_t decode_id);
51 PendingFrame(uint32_t decode_id, 651 PendingFrame(uint32_t decode_id,
52 const gfx::Size& coded_size, 652 const scoped_refptr<media::VideoFrame>& frame);
53 const gfx::Rect& visible_rect);
54 ~PendingFrame(); 653 ~PendingFrame();
55 654
56 const uint32_t decode_id; 655 const uint32_t decode_id;
57 const gfx::Size coded_size; 656 scoped_refptr<media::VideoFrame> video_frame;
58 const gfx::Rect visible_rect;
59 std::vector<uint8_t> argb_pixels;
60 657
61 private: 658 private:
62 // This could be expensive to copy, so guard against that. 659 // This could be expensive to copy, so guard against that.
63 DISALLOW_COPY_AND_ASSIGN(PendingFrame); 660 DISALLOW_COPY_AND_ASSIGN(PendingFrame);
64 }; 661 };
65 662
66 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id) 663 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id)
67 : decode_id(decode_id) { 664 : decode_id(decode_id) {
68 } 665 }
69 666
70 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id, 667 VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id,
71 const gfx::Size& coded_size, 668 const scoped_refptr<media::VideoFrame>& frame)
72 const gfx::Rect& visible_rect)
73 : decode_id(decode_id), 669 : decode_id(decode_id),
74 coded_size(coded_size), 670 video_frame(frame) {
75 visible_rect(visible_rect),
76 argb_pixels(coded_size.width() * coded_size.height() * 4) {
77 } 671 }
78 672
79 VideoDecoderShim::PendingFrame::~PendingFrame() { 673 VideoDecoderShim::PendingFrame::~PendingFrame() {
80 } 674 }
81 675
82 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving 676 // DecoderImpl runs the underlying VideoDecoder on the media thread, receiving
83 // calls from the VideoDecodeShim on the main thread and sending results back. 677 // 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 678 // This class is constructed on the main thread, but used and destructed on the
85 // media thread. 679 // media thread.
86 class VideoDecoderShim::DecoderImpl { 680 class VideoDecoderShim::DecoderImpl {
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 } 856 }
263 857
264 void VideoDecoderShim::DecoderImpl::OnOutputComplete( 858 void VideoDecoderShim::DecoderImpl::OnOutputComplete(
265 const scoped_refptr<media::VideoFrame>& frame) { 859 const scoped_refptr<media::VideoFrame>& frame) {
266 // Software decoders are expected to generated frames only when a Decode() 860 // Software decoders are expected to generated frames only when a Decode()
267 // call is pending. 861 // call is pending.
268 DCHECK(awaiting_decoder_); 862 DCHECK(awaiting_decoder_);
269 863
270 scoped_ptr<PendingFrame> pending_frame; 864 scoped_ptr<PendingFrame> pending_frame;
271 if (!frame->end_of_stream()) { 865 if (!frame->end_of_stream()) {
272 pending_frame.reset(new PendingFrame( 866 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 { 867 } else {
280 pending_frame.reset(new PendingFrame(decode_id_)); 868 pending_frame.reset(new PendingFrame(decode_id_));
281 } 869 }
282 870
283 main_message_loop_->PostTask(FROM_HERE, 871 main_message_loop_->PostTask(FROM_HERE,
284 base::Bind(&VideoDecoderShim::OnOutputComplete, 872 base::Bind(&VideoDecoderShim::OnOutputComplete,
285 shim_, 873 shim_,
286 base::Passed(&pending_frame))); 874 base::Passed(&pending_frame)));
287 } 875 }
288 876
289 void VideoDecoderShim::DecoderImpl::OnResetComplete() { 877 void VideoDecoderShim::DecoderImpl::OnResetComplete() {
290 main_message_loop_->PostTask( 878 main_message_loop_->PostTask(
291 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_)); 879 FROM_HERE, base::Bind(&VideoDecoderShim::OnResetComplete, shim_));
292 } 880 }
293 881
294 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host) 882 VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host)
295 : state_(UNINITIALIZED), 883 : state_(UNINITIALIZED),
296 host_(host), 884 host_(host),
297 media_task_runner_( 885 media_task_runner_(
298 RenderThreadImpl::current()->GetMediaThreadTaskRunner()), 886 RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
299 context_provider_( 887 context_provider_(
300 RenderThreadImpl::current()->SharedMainThreadContextProvider()), 888 RenderThreadImpl::current()->SharedMainThreadContextProvider()),
301 texture_pool_size_(0), 889 texture_pool_size_(0),
302 num_pending_decodes_(0), 890 num_pending_decodes_(0),
303 weak_ptr_factory_(this) { 891 weak_ptr_factory_(this) {
304 DCHECK(host_); 892 DCHECK(host_);
305 DCHECK(media_task_runner_.get()); 893 DCHECK(media_task_runner_.get());
306 DCHECK(context_provider_.get()); 894 DCHECK(context_provider_.get());
307 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr())); 895 decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr()));
896 yuv_converter_.reset(new YUVConv( context_provider_ ));
308 } 897 }
309 898
310 VideoDecoderShim::~VideoDecoderShim() { 899 VideoDecoderShim::~VideoDecoderShim() {
311 DCHECK(RenderThreadImpl::current()); 900 DCHECK(RenderThreadImpl::current());
312 // Delete any remaining textures. 901 // Delete any remaining textures.
313 TextureIdMap::iterator it = texture_id_map_.begin(); 902 TextureIdMap::iterator it = texture_id_map_.begin();
314 for (; it != texture_id_map_.end(); ++it) 903 for (; it != texture_id_map_.end(); ++it)
315 DeleteTexture(it->second); 904 DeleteTexture(it->second);
316 texture_id_map_.clear(); 905 texture_id_map_.clear();
317 906
(...skipping 18 matching lines...) Expand all
336 DCHECK_EQ(state_, UNINITIALIZED); 925 DCHECK_EQ(state_, UNINITIALIZED);
337 media::VideoCodec codec = media::kUnknownVideoCodec; 926 media::VideoCodec codec = media::kUnknownVideoCodec;
338 if (profile <= media::H264PROFILE_MAX) 927 if (profile <= media::H264PROFILE_MAX)
339 codec = media::kCodecH264; 928 codec = media::kCodecH264;
340 else if (profile <= media::VP8PROFILE_MAX) 929 else if (profile <= media::VP8PROFILE_MAX)
341 codec = media::kCodecVP8; 930 codec = media::kCodecVP8;
342 else if (profile <= media::VP9PROFILE_MAX) 931 else if (profile <= media::VP9PROFILE_MAX)
343 codec = media::kCodecVP9; 932 codec = media::kCodecVP9;
344 DCHECK_NE(codec, media::kUnknownVideoCodec); 933 DCHECK_NE(codec, media::kUnknownVideoCodec);
345 934
935 // initialize yuv converter
936 if( !yuv_converter_->Initialize() )
937 {
938 return false;
939 }
940
346 media::VideoDecoderConfig config( 941 media::VideoDecoderConfig config(
347 codec, 942 codec,
348 profile, 943 profile,
349 media::VideoFrame::YV12, 944 media::VideoFrame::YV12,
350 gfx::Size(32, 24), // Small sizes that won't fail. 945 gfx::Size(32, 24), // Small sizes that won't fail.
351 gfx::Rect(32, 24), 946 gfx::Rect(32, 24),
352 gfx::Size(32, 24), 947 gfx::Size(32, 24),
353 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed. 948 NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed.
354 0 /* extra_data_size */, 949 0 /* extra_data_size */,
355 false /* decryption */); 950 false /* decryption */);
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 num_pending_decodes_--; 1059 num_pending_decodes_--;
465 completed_decodes_.push(decode_id); 1060 completed_decodes_.push(decode_id);
466 1061
467 // If frames are being queued because we're out of textures, don't notify 1062 // 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 1063 // 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. 1064 // the host from sending buffers that will cause pending_frames_ to grow.
470 if (pending_frames_.empty()) 1065 if (pending_frames_.empty())
471 NotifyCompletedDecodes(); 1066 NotifyCompletedDecodes();
472 } 1067 }
473 1068
474 void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) { 1069 void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> pframe) {
475 DCHECK(RenderThreadImpl::current()); 1070 DCHECK(RenderThreadImpl::current());
476 DCHECK(host_); 1071 DCHECK(host_);
477 1072
478 if (!frame->argb_pixels.empty()) { 1073 if ( pframe->video_frame ) {
479 if (texture_size_ != frame->coded_size) { 1074 if (texture_size_ != pframe->video_frame->coded_size()) {
480 // If the size has changed, all current textures must be dismissed. Add 1075 // 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 1076 // 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. 1077 // use by the plugin. We will dismiss the rest as they are recycled.
483 for (TextureIdMap::const_iterator it = texture_id_map_.begin(); 1078 for (TextureIdMap::const_iterator it = texture_id_map_.begin();
484 it != texture_id_map_.end(); 1079 it != texture_id_map_.end();
485 ++it) { 1080 ++it) {
486 textures_to_dismiss_.insert(it->first); 1081 textures_to_dismiss_.insert(it->first);
487 } 1082 }
488 for (TextureIdSet::const_iterator it = available_textures_.begin(); 1083 for (TextureIdSet::const_iterator it = available_textures_.begin();
489 it != available_textures_.end(); 1084 it != available_textures_.end();
490 ++it) { 1085 ++it) {
491 DismissTexture(*it); 1086 DismissTexture(*it);
492 } 1087 }
493 available_textures_.clear(); 1088 available_textures_.clear();
494 FlushCommandBuffer(); 1089 FlushCommandBuffer();
495 1090
496 DCHECK(pending_texture_mailboxes_.empty()); 1091 DCHECK(pending_texture_mailboxes_.empty());
497 for (uint32_t i = 0; i < texture_pool_size_; i++) 1092 for (uint32_t i = 0; i < texture_pool_size_; i++)
498 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); 1093 pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate());
499 1094
500 host_->RequestTextures(texture_pool_size_, 1095 host_->RequestTextures(texture_pool_size_,
501 frame->coded_size, 1096 pframe->video_frame->coded_size(),
502 GL_TEXTURE_2D, 1097 GL_TEXTURE_2D,
503 pending_texture_mailboxes_); 1098 pending_texture_mailboxes_);
504 texture_size_ = frame->coded_size; 1099 texture_size_ = pframe->video_frame->coded_size();
505 } 1100 }
506 1101
507 pending_frames_.push(linked_ptr<PendingFrame>(frame.release())); 1102 pending_frames_.push(linked_ptr<PendingFrame>(pframe.release()));
508 SendPictures(); 1103 SendPictures();
509 } 1104 }
510 } 1105 }
511 1106
512 void VideoDecoderShim::SendPictures() { 1107 void VideoDecoderShim::SendPictures() {
513 DCHECK(RenderThreadImpl::current()); 1108 DCHECK(RenderThreadImpl::current());
514 DCHECK(host_); 1109 DCHECK(host_);
515 while (!pending_frames_.empty() && !available_textures_.empty()) { 1110 while (!pending_frames_.empty() && !available_textures_.empty()) {
516 const linked_ptr<PendingFrame>& frame = pending_frames_.front(); 1111 const linked_ptr<PendingFrame>& frame = pending_frames_.front();
517 1112
518 TextureIdSet::iterator it = available_textures_.begin(); 1113 TextureIdSet::iterator it = available_textures_.begin();
519 uint32_t texture_id = *it; 1114 uint32_t texture_id = *it;
520 available_textures_.erase(it); 1115 available_textures_.erase(it);
521 1116
522 uint32_t local_texture_id = texture_id_map_[texture_id]; 1117 uint32_t local_texture_id = texture_id_map_[texture_id];
523 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); 1118
524 gles2->ActiveTexture(GL_TEXTURE0); 1119 // run the yuv conversion renderer
525 gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); 1120 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 1121
542 host_->PictureReady(media::Picture(texture_id, frame->decode_id, 1122 host_->PictureReady(media::Picture(texture_id, frame->decode_id,
543 frame->visible_rect, false)); 1123 frame->video_frame->visible_rect(),
1124 false));
544 pending_frames_.pop(); 1125 pending_frames_.pop();
545 } 1126 }
546 1127
547 FlushCommandBuffer(); 1128 FlushCommandBuffer();
548 1129
549 if (pending_frames_.empty()) { 1130 if (pending_frames_.empty()) {
550 // If frames aren't backing up, notify the host of any completed decodes so 1131 // If frames aren't backing up, notify the host of any completed decodes so
551 // it can send more buffers. 1132 // it can send more buffers.
552 NotifyCompletedDecodes(); 1133 NotifyCompletedDecodes();
553 1134
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
593 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) { 1174 void VideoDecoderShim::DeleteTexture(uint32_t texture_id) {
594 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); 1175 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
595 gles2->DeleteTextures(1, &texture_id); 1176 gles2->DeleteTextures(1, &texture_id);
596 } 1177 }
597 1178
598 void VideoDecoderShim::FlushCommandBuffer() { 1179 void VideoDecoderShim::FlushCommandBuffer() {
599 context_provider_->ContextGL()->Flush(); 1180 context_provider_->ContextGL()->Flush();
600 } 1181 }
601 1182
602 } // namespace content 1183 } // 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