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