Chromium Code Reviews| Index: content/renderer/pepper/video_decoder_shim.cc |
| diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc |
| index 35594a8e3a609ac7fbefd241b8aa3a8fe66a2b42..b9281cf64a3a40120026dba391eaf90668e669e9 100644 |
| --- a/content/renderer/pepper/video_decoder_shim.cc |
| +++ b/content/renderer/pepper/video_decoder_shim.cc |
| @@ -9,6 +9,7 @@ |
| #include <GLES2/gl2extchromium.h> |
| #include "base/bind.h" |
| +#include "base/logging.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/single_thread_task_runner.h" |
| #include "cc/blink/context_provider_web_context.h" |
| @@ -28,6 +29,571 @@ |
| namespace content { |
| +// |
| +// YUV->RGB converter class using a shader and FBO |
| +// |
| +class YUVConverter { |
| + public: |
| + YUVConverter(const scoped_refptr<cc_blink::ContextProviderWebContext>&); |
| + ~YUVConverter(); |
| + bool Initialize(); |
| + void Convert(const scoped_refptr<media::VideoFrame>& frame, GLuint tex_out); |
| + |
| + private: |
| + GLuint CreateShader(); |
| + GLuint CompileShader(const char* name, GLuint type, const char* code); |
| + GLuint CreateProgram(const char* name, GLuint vshader, GLuint fshader); |
| + bool SetUniform(GLuint program, const char* name, int value); |
| + bool SetUniform(GLuint program, const char* name, float value); |
| + GLuint CreateTexture(); |
| + |
| + scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_; |
| + gpu::gles2::GLES2Interface* gl_; |
| + GLuint frame_buffer_; |
| + GLuint vtx_buffer_; |
| + GLuint program_; |
| + |
| + GLuint y_texture_; |
| + GLuint u_texture_; |
| + GLuint v_texture_; |
| + |
| + GLuint internal_format_; |
| + GLuint format_; |
| + |
| + GLuint y_width_; |
| + GLuint y_height_; |
| + |
| + GLuint uv_width_; |
| + GLuint uv_height_; |
| + |
| + GLfloat clamp_value_; |
| + GLuint clamp_width_; |
| + GLint clamp_width_loc_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(YUVConverter); |
| +}; |
| + |
| +YUVConverter::YUVConverter( |
| + const scoped_refptr<cc_blink::ContextProviderWebContext>& ctx_p) |
| + : context_provider_(ctx_p), |
| + gl_(context_provider_->ContextGL()), |
| + frame_buffer_(0), |
| + vtx_buffer_(0), |
| + program_(0), |
| + y_texture_(0), |
| + u_texture_(0), |
| + v_texture_(0), |
| + internal_format_(0), |
| + format_(0), |
| + y_width_(2), |
| + y_height_(2), |
| + uv_width_(2), |
| + uv_height_(2), |
| + clamp_value_(1.f), |
| + clamp_width_(0), |
| + clamp_width_loc_(0) { |
| +} |
| + |
| +YUVConverter::~YUVConverter() { |
| + // delete textures |
| + if (y_texture_) |
| + gl_->DeleteTextures(1, &y_texture_); |
| + |
| + if (u_texture_) |
| + gl_->DeleteTextures(1, &u_texture_); |
| + |
| + if (v_texture_) |
| + gl_->DeleteTextures(1, &v_texture_); |
| + |
| + // delete framebuffer |
| + if (frame_buffer_) |
| + gl_->DeleteFramebuffers(1, &frame_buffer_); |
| + |
| + // delete vertex buffer |
| + if (vtx_buffer_) |
| + gl_->DeleteBuffers(1, &vtx_buffer_); |
| + |
| + // delete program |
| + if (program_) |
| + gl_->DeleteProgram(program_); |
| +} |
| + |
| +GLuint YUVConverter::CreateTexture() { |
| + GLuint tex = 0; |
| + |
| + // create texture |
| + gl_->GenTextures(1, &tex); |
| + gl_->BindTexture(GL_TEXTURE_2D, tex); |
| + |
| + // create texture with default size - will be resized upon first frame |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_, |
| + GL_UNSIGNED_BYTE, NULL); |
| + |
| + // set params |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| + gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| + |
| + // unbind |
| + gl_->BindTexture(GL_TEXTURE_2D, 0); |
| + |
| + return tex; |
| +} |
| + |
| +GLuint YUVConverter::CompileShader(const char* name, |
| + GLuint type, |
| + const char* code) { |
| + GLuint shader = gl_->CreateShader(type); |
| + |
| + gl_->ShaderSource(shader, 1, (const GLchar**)&code, NULL); |
| + gl_->CompileShader(shader); |
| + |
| + GLint status = 0; |
| + |
| + 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.
|
| + if (status != GL_TRUE) { |
| + GLint max_length = 0; |
| + GLint actual_length = 0; |
| + gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length); |
| + |
| + // The maxLength includes the NULL character |
| + std::string error_log(max_length, 0); |
| + gl_->GetShaderInfoLog(shader, max_length, &actual_length, &error_log[0]); |
| + |
| + LOG(ERROR) << name << " shader compilation failed: " << error_log.c_str(); |
| + gl_->DeleteShader(shader); |
| + return 0; |
| + } |
| + |
| + return shader; |
| +} |
| + |
| +GLuint YUVConverter::CreateProgram(const char* name, |
| + GLuint vshader, |
| + GLuint fshader) { |
| + GLuint program = gl_->CreateProgram(); |
| + gl_->AttachShader(program, vshader); |
| + gl_->AttachShader(program, fshader); |
| + |
| + // bind known vertex position |
| + gl_->BindAttribLocation(program, 0, "position"); |
| + |
| + gl_->LinkProgram(program); |
| + |
| + GLint status = 0; |
| + |
| + gl_->GetProgramiv(program, GL_LINK_STATUS, &status); |
|
piman
2015/05/05 02:21:55
Same here.
CodeByThePound
2015/05/05 22:00:06
Acknowledged.
|
| + if (status != GL_TRUE) { |
| + GLint max_length = 0; |
| + GLint actual_length = 0; |
| + gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length); |
| + |
| + // The maxLength includes the NULL character |
| + std::string error_log(max_length, 0); |
| + gl_->GetProgramInfoLog(program, max_length, &actual_length, &error_log[0]); |
| + |
| + LOG(ERROR) << name << " program linking failed: " << error_log.c_str(); |
| + return 0; |
| + } |
| + |
| + return program; |
| +} |
| + |
| +bool YUVConverter::SetUniform(GLuint program, const char* name, int value) { |
| + bool result = false; |
| + GLint loc = gl_->GetUniformLocation(program, name); |
| + 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.
|
| + gl_->UseProgram(program); |
| + gl_->Uniform1i(loc, value); |
| + gl_->UseProgram(0); |
| + result = true; |
| + } |
| + |
| + return result; |
| +} |
| + |
| +bool YUVConverter::SetUniform(GLuint program, const char* name, float value) { |
| + bool result = false; |
| + GLint loc = gl_->GetUniformLocation(program, name); |
| + if (loc != -1) { |
| + gl_->UseProgram(program); |
| + gl_->Uniform1f(loc, value); |
| + gl_->UseProgram(0); |
| + result = true; |
| + } |
| + |
| + return result; |
| +} |
| + |
| +GLuint YUVConverter::CreateShader() { |
| + const char* vert_shader = |
| + "precision mediump float;\n" |
| + "attribute vec2 position;\n" |
| + "varying vec2 texcoord;\n" |
| + "uniform float clamp_width;\n" |
| + "void main()\n" |
| + "{\n" |
| + " gl_Position = vec4( position.xy, 0, 1 );\n" |
| + // convert vertex positions to texcoords, clamp x |
| + " vec2 tmp = position*0.5+0.5;\n" |
| + " texcoord = vec2(min(tmp.x, clamp_width), tmp.y);\n" |
| + "}"; |
| + |
| + const char* frag_shader = |
| + "precision mediump float;\n" |
| + "varying vec2 texcoord;\n" |
| + "uniform sampler2D y_sampler;\n" |
| + "uniform sampler2D u_sampler;\n" |
| + "uniform sampler2D v_sampler;\n" |
| + "void main()\n" |
| + "{\n" |
| + // These values are magic numbers that are used in the transformation |
| + // from YUV to RGB color values. They are taken from the following |
| + // webpage: http://www.fourcc.org/fccyvrgb.php. In this case Rec. 601. |
| + // yuv_2_rgb and yuv_adjust_constrained were taken from gl_renderer.cc |
| + " const mat3 yuv_2_rgb = mat3( 1.164, 1.164, 1.164,\n" |
| + " 0.0, -.391, 2.018,\n" |
| + " 1.596, -.813, 0.0 );\n" |
| + // These values map to 16, 128, and 128 respectively, and are computed |
| + // as a fraction over 256 (e.g. 16 / 256 = 0.0625). |
| + // They are used in the YUV to RGBA conversion formula: |
| + // Y - 16 : Gives 16 values of head and footroom for overshooting |
| + // U - 128 : Turns unsigned U into signed U [-128,127] |
| + // V - 128 : Turns unsigned V into signed V [-128,127] |
| + " const vec3 yuv_adjust_constrained = vec3( -0.0625, -0.5, -0.5 );\n" |
| + |
| + " vec3 yuv = vec3( texture2D(y_sampler, texcoord).x,\n" |
| + " texture2D(u_sampler, texcoord).x,\n" |
| + " texture2D(v_sampler, texcoord).x ) +\n" |
| + " yuv_adjust_constrained;\n" |
| + " gl_FragColor = vec4( yuv_2_rgb * yuv, 1.0 );\n" |
| + "}"; |
| + |
| + // |
| + // Compile vertex and fragment shaders. |
| + // |
| + GLuint vertex_shader = |
| + CompileShader("Vertex Shader", GL_VERTEX_SHADER, vert_shader); |
| + if (!vertex_shader) { |
| + return 0; |
| + } |
| + |
| + GLuint fragment_shader = |
| + CompileShader("Fragment Shader", GL_FRAGMENT_SHADER, frag_shader); |
| + if (!fragment_shader) { |
| + gl_->DeleteShader(vertex_shader); |
| + return 0; |
| + } |
| + |
| + // |
| + // Create the program |
| + // |
| + GLuint program = |
| + CreateProgram("YUVConverter Program", vertex_shader, fragment_shader); |
| + |
| + // delete shaders since they are no longer needed |
| + gl_->DeleteShader(vertex_shader); |
| + gl_->DeleteShader(fragment_shader); |
| + |
| + if (!program) { |
| + return 0; |
| + } |
| + |
| + GLuint result = program; |
| + |
| + // |
| + // Bind samplers to texture units - which never change. |
| + // |
| + if (!SetUniform(program, "y_sampler", 0)) { |
| + result = 0; |
| + } |
| + if (!SetUniform(program, "u_sampler", 1)) { |
| + result = 0; |
| + } |
| + if (!SetUniform(program, "v_sampler", 2)) { |
| + result = 0; |
| + } |
| + |
| + // set default clamp width |
| + if (!SetUniform(program, "clamp_width", clamp_value_)) { |
| + result = 0; |
| + } |
| + |
| + // store clamp width loc for later |
| + clamp_width_loc_ = gl_->GetUniformLocation(program, "clamp_width"); |
| + if (clamp_width_loc_ < 0) { |
| + result = 0; |
| + } |
| + |
| + if (!result) { |
| + gl_->DeleteProgram(program); |
| + } |
| + |
| + return result; |
| +} |
| + |
| +bool YUVConverter::Initialize() { |
| + // |
| + // Determine formats to use based on whether GL_RED is available or |
| + // whether we need to use GL_LUMINANCE. |
| + // |
| + DCHECK(gl_); |
| + if (context_provider_->ContextCapabilities().gpu.texture_rg) { |
| + internal_format_ = GL_RED_EXT; |
| + format_ = GL_RED_EXT; |
| + } else { |
| + internal_format_ = GL_LUMINANCE; |
| + format_ = GL_LUMINANCE; |
| + } |
| + |
| + // 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.
|
| + gl_->PushGroupMarkerEXT(0, "YUVConverterContext"); |
| + |
| + // |
| + // Create Framebuffer |
| + // |
| + gl_->GenFramebuffers(1, &frame_buffer_); |
| + |
| + // |
| + // Create some default textures to hold Y,U,V values |
| + // |
| + y_texture_ = CreateTexture(); |
| + u_texture_ = CreateTexture(); |
| + v_texture_ = CreateTexture(); |
| + |
| + // |
| + // Create Vertex Buffer |
| + // |
| + // Vertex positions. Also converted to texcoords in vertex shader. |
| + GLfloat vtx_buf[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f}; |
| + |
| + // Create buffer |
| + gl_->GenBuffers(1, &vtx_buffer_); |
| + gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_); |
| + // Populate it |
| + gl_->BufferData(GL_ARRAY_BUFFER, 2 * sizeof(GLfloat) * 4, vtx_buf, |
| + GL_STATIC_DRAW); |
| + // unbind |
| + gl_->BindBuffer(GL_ARRAY_BUFFER, 0); |
| + |
| + // |
| + // Create Shader |
| + // |
| + program_ = CreateShader(); |
| + if (!program_) { |
| + return false; |
| + } |
| + |
| + gl_->PopGroupMarkerEXT(); |
| + |
| + return true; |
| +} |
| + |
| +void YUVConverter::Convert(const scoped_refptr<media::VideoFrame>& frame, |
| + GLuint tex_out) { |
| + int divisor_height; |
| + bool supported_format = true; |
| + |
| + // make sure we support this format |
| + switch (frame->format()) { |
| + case media::VideoFrame::YV12: /* 420 */ |
| + case media::VideoFrame::I420: /* 420 */ |
| + divisor_height = 2; |
| + break; |
| + |
| + case media::VideoFrame::YV16: /* 422 */ |
| + divisor_height = 1; |
| + break; |
| + |
| + case media::VideoFrame::YV24: /* 444 */ |
| + divisor_height = 1; |
| + break; |
| + |
| + default: |
| + // rest are not supported.. |
| + supported_format = false; |
| + break; |
| + } |
| + |
| + // set group marker |
| + gl_->PushGroupMarkerEXT(0, "YUVConverterContext"); |
| + |
| + bool set_clamp = false; |
| + |
| + uint32_t ywidth = frame->coded_size().width(); |
| + uint32_t yheight = frame->coded_size().height(); |
| + |
| + if (supported_format) { |
| + DCHECK_EQ(frame->stride(media::VideoFrame::kUPlane), |
| + frame->stride(media::VideoFrame::kVPlane)); |
| + |
| + uint32_t ystride = frame->stride(media::VideoFrame::kYPlane); |
| + uint32_t uvstride = frame->stride(media::VideoFrame::kUPlane); |
| + |
| + // resize textures if necessary |
| + if (ystride != y_width_ || yheight != y_height_) { |
| + // choose width based on the stride |
| + // then, clamp later |
| + y_width_ = ystride; |
| + y_height_ = yheight; |
| + |
| + uv_width_ = uvstride; |
| + uv_height_ = y_height_ / divisor_height; |
| + |
| + if ((ystride != ywidth) || (clamp_width_ != ywidth)) { |
| + if (clamp_width_ != ywidth) { |
| + // clamp width to avoid sampling padding pixels |
| + clamp_width_ = ywidth; |
| + clamp_value_ = |
| + static_cast<float>(ywidth) / static_cast<float>(ystride); |
| + // clamp to 1/2 pixel inside to avoid bilinear sampling errors |
| + clamp_value_ -= (1.f / (2.f * static_cast<float>(ystride))); |
| + |
| + set_clamp = true; |
| + } |
| + } |
| + |
| + // |
| + // Resize the textures and upload data |
| + // |
| + gl_->ActiveTexture(GL_TEXTURE0); |
| + gl_->BindTexture(GL_TEXTURE_2D, y_texture_); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_, |
| + 0, format_, GL_UNSIGNED_BYTE, |
| + frame->data(media::VideoFrame::kYPlane)); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE1); |
| + gl_->BindTexture(GL_TEXTURE_2D, u_texture_); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_, |
| + 0, format_, GL_UNSIGNED_BYTE, |
| + frame->data(media::VideoFrame::kUPlane)); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE2); |
| + gl_->BindTexture(GL_TEXTURE_2D, v_texture_); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_, |
| + 0, format_, GL_UNSIGNED_BYTE, |
| + frame->data(media::VideoFrame::kVPlane)); |
| + } else { |
| + // |
| + // Bind textures and upload texture data |
| + // |
| + gl_->ActiveTexture(GL_TEXTURE0); |
| + gl_->BindTexture(GL_TEXTURE_2D, y_texture_); |
| + gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_, |
| + GL_UNSIGNED_BYTE, |
| + frame->data(media::VideoFrame::kYPlane)); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE1); |
| + gl_->BindTexture(GL_TEXTURE_2D, u_texture_); |
| + gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_, |
| + GL_UNSIGNED_BYTE, |
| + frame->data(media::VideoFrame::kUPlane)); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE2); |
| + gl_->BindTexture(GL_TEXTURE_2D, v_texture_); |
| + gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_, |
| + GL_UNSIGNED_BYTE, |
| + frame->data(media::VideoFrame::kVPlane)); |
| + } |
| + } else { |
| + // |
| + // Unsupported format - set textures to be 4x4 and produce a red output |
| + // 2x2 texture didn't seem to work |
| + // |
| + uint8_t yudata[4 * 4]; |
| + memset(yudata, 0x5e, 4 * 4); |
| + gl_->ActiveTexture(GL_TEXTURE0); |
| + gl_->BindTexture(GL_TEXTURE_2D, y_texture_); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4, 0, format_, |
| + GL_UNSIGNED_BYTE, yudata); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE1); |
| + gl_->BindTexture(GL_TEXTURE_2D, u_texture_); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4, 0, format_, |
| + GL_UNSIGNED_BYTE, yudata); |
| + |
| + uint8_t vdata[4 * 4]; |
| + memset(vdata, 0xe7, 4 * 4); |
| + gl_->ActiveTexture(GL_TEXTURE2); |
| + gl_->BindTexture(GL_TEXTURE_2D, v_texture_); |
| + gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 4, 4, 0, format_, |
| + GL_UNSIGNED_BYTE, vdata); |
| + |
| + if (clamp_value_ != 1.f) { |
| + set_clamp = true; |
| + clamp_value_ = 1.f; |
| + } |
| + } |
| + |
| + // since we modify the viewport, save it here |
| + // 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
|
| + GLint viewport[4] = {0}; |
| + gl_->GetIntegerv(GL_VIEWPORT, viewport); |
| + |
| + // |
| + // bind framebuffer and output texture |
| + // |
| + gl_->BindFramebuffer(GL_FRAMEBUFFER, frame_buffer_); |
| + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| + tex_out, 0); |
| + |
| +#ifndef NDEBUG |
| + // NOTE: we should probably check for framebuffer complete here, but that |
| + // will slow this method down so check in debug mode |
| + GLint status = gl_->CheckFramebufferStatus(GL_FRAMEBUFFER); |
| + if (status != GL_FRAMEBUFFER_COMPLETE) { |
| + return; |
| + } |
| +#endif |
| + |
| + // |
| + // Set viewport as dimensions of the video frame |
| + // |
| + gl_->Viewport(0, 0, ywidth, yheight); |
| + |
| + // |
| + // Enable shader |
| + // |
| + gl_->UseProgram(program_); |
| + |
| + if (set_clamp) { |
| + gl_->Uniform1f(clamp_width_loc_, clamp_value_); |
| + } |
| + |
| + // |
| + // Render |
| + // |
| + gl_->BindBuffer(GL_ARRAY_BUFFER, vtx_buffer_); |
| + gl_->EnableVertexAttribArray(0); |
| + gl_->VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), |
| + static_cast<const void*>(0)); |
| + |
| + // draw |
| + gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| + |
| + // disable everything we enabled |
| + gl_->BindBuffer(GL_ARRAY_BUFFER, 0); |
| + gl_->DisableVertexAttribArray(0); |
| + gl_->UseProgram(0); |
| + gl_->BindFramebuffer(GL_FRAMEBUFFER, 0); |
| + |
| + // unbind textures |
| + // active texture is still 2 |
| + gl_->BindTexture(GL_TEXTURE_2D, 0); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE1); |
| + gl_->BindTexture(GL_TEXTURE_2D, 0); |
| + |
| + gl_->ActiveTexture(GL_TEXTURE0); |
| + gl_->BindTexture(GL_TEXTURE_2D, 0); |
| + |
| + // reset former viewport |
| + gl_->Viewport(viewport[0], viewport[1], viewport[2], viewport[3]); |
| + |
| + gl_->PopGroupMarkerEXT(); |
| +} |
| + |
| struct VideoDecoderShim::PendingDecode { |
| PendingDecode(uint32_t decode_id, |
| const scoped_refptr<media::DecoderBuffer>& buffer); |
| @@ -49,14 +615,11 @@ VideoDecoderShim::PendingDecode::~PendingDecode() { |
| struct VideoDecoderShim::PendingFrame { |
| explicit PendingFrame(uint32_t decode_id); |
| PendingFrame(uint32_t decode_id, |
| - const gfx::Size& coded_size, |
| - const gfx::Rect& visible_rect); |
| + const scoped_refptr<media::VideoFrame>& frame); |
| ~PendingFrame(); |
| const uint32_t decode_id; |
| - const gfx::Size coded_size; |
| - const gfx::Rect visible_rect; |
| - std::vector<uint8_t> argb_pixels; |
| + scoped_refptr<media::VideoFrame> video_frame; |
| private: |
| // This could be expensive to copy, so guard against that. |
| @@ -67,13 +630,10 @@ VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id) |
| : decode_id(decode_id) { |
| } |
| -VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id, |
| - const gfx::Size& coded_size, |
| - const gfx::Rect& visible_rect) |
| - : decode_id(decode_id), |
| - coded_size(coded_size), |
| - visible_rect(visible_rect), |
| - argb_pixels(coded_size.width() * coded_size.height() * 4) { |
| +VideoDecoderShim::PendingFrame::PendingFrame( |
| + uint32_t decode_id, |
| + const scoped_refptr<media::VideoFrame>& frame) |
| + : decode_id(decode_id), video_frame(frame) { |
| } |
| VideoDecoderShim::PendingFrame::~PendingFrame() { |
| @@ -269,13 +829,7 @@ void VideoDecoderShim::DecoderImpl::OnOutputComplete( |
| scoped_ptr<PendingFrame> pending_frame; |
| if (!frame->end_of_stream()) { |
| - pending_frame.reset(new PendingFrame( |
| - decode_id_, frame->coded_size(), frame->visible_rect())); |
| - // Convert the VideoFrame pixels to ABGR to match VideoDecodeAccelerator. |
| - media::SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
| - frame, |
| - &pending_frame->argb_pixels.front(), |
| - frame->coded_size().width() * 4); |
| + pending_frame.reset(new PendingFrame(decode_id_, frame)); |
| } else { |
| pending_frame.reset(new PendingFrame(decode_id_)); |
| } |
| @@ -305,6 +859,7 @@ VideoDecoderShim::VideoDecoderShim(PepperVideoDecoderHost* host) |
| DCHECK(media_task_runner_.get()); |
| DCHECK(context_provider_.get()); |
| decoder_impl_.reset(new DecoderImpl(weak_ptr_factory_.GetWeakPtr())); |
| + yuv_converter_.reset(new YUVConverter(context_provider_)); |
| } |
| VideoDecoderShim::~VideoDecoderShim() { |
| @@ -343,6 +898,11 @@ bool VideoDecoderShim::Initialize( |
| codec = media::kCodecVP9; |
| DCHECK_NE(codec, media::kUnknownVideoCodec); |
| + // initialize yuv converter |
| + if (!yuv_converter_->Initialize()) { |
| + return false; |
| + } |
| + |
| media::VideoDecoderConfig config( |
| codec, |
| profile, |
| @@ -471,12 +1031,12 @@ void VideoDecoderShim::OnDecodeComplete(int32_t result, uint32_t decode_id) { |
| NotifyCompletedDecodes(); |
| } |
| -void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) { |
| +void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> pframe) { |
| DCHECK(RenderThreadImpl::current()); |
| DCHECK(host_); |
| - if (!frame->argb_pixels.empty()) { |
| - if (texture_size_ != frame->coded_size) { |
| + if (pframe->video_frame) { |
| + if (texture_size_ != pframe->video_frame->coded_size()) { |
| // If the size has changed, all current textures must be dismissed. Add |
| // all textures to |textures_to_dismiss_| and dismiss any that aren't in |
| // use by the plugin. We will dismiss the rest as they are recycled. |
| @@ -498,13 +1058,12 @@ void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) { |
| pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); |
| host_->RequestTextures(texture_pool_size_, |
| - frame->coded_size, |
| - GL_TEXTURE_2D, |
| + pframe->video_frame->coded_size(), GL_TEXTURE_2D, |
| pending_texture_mailboxes_); |
| - texture_size_ = frame->coded_size; |
| + texture_size_ = pframe->video_frame->coded_size(); |
| } |
| - pending_frames_.push(linked_ptr<PendingFrame>(frame.release())); |
| + pending_frames_.push(linked_ptr<PendingFrame>(pframe.release())); |
| SendPictures(); |
| } |
| } |
| @@ -520,27 +1079,13 @@ void VideoDecoderShim::SendPictures() { |
| available_textures_.erase(it); |
| uint32_t local_texture_id = texture_id_map_[texture_id]; |
| - gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL(); |
| - gles2->ActiveTexture(GL_TEXTURE0); |
| - gles2->BindTexture(GL_TEXTURE_2D, local_texture_id); |
| -#if !defined(OS_ANDROID) |
| - // BGRA is the native texture format, except on Android, where textures |
| - // would be uploaded as GL_RGBA. |
| - gles2->TexImage2D(GL_TEXTURE_2D, |
| - 0, |
| - GL_BGRA_EXT, |
| - texture_size_.width(), |
| - texture_size_.height(), |
| - 0, |
| - GL_BGRA_EXT, |
| - GL_UNSIGNED_BYTE, |
| - &frame->argb_pixels.front()); |
| -#else |
| -#error Not implemented. |
| -#endif |
| + |
| + // run the yuv conversion renderer |
| + yuv_converter_->Convert(frame->video_frame, local_texture_id); |
| host_->PictureReady(media::Picture(texture_id, frame->decode_id, |
| - frame->visible_rect, false)); |
| + frame->video_frame->visible_rect(), |
| + false)); |
| pending_frames_.pop(); |
| } |