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..6d0156c15ff9fa5ec36c8480ed5678d341107060 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,605 @@ |
namespace content { |
+// |
+// YUV->RGB converter class using a shader and FBO |
+// |
+class YUVConv { |
+ public: |
bbudge
2015/05/01 20:08:59
chromium indent of public/private is 1 space, then
|
+ YUVConv( const scoped_refptr<cc_blink::ContextProviderWebContext> & ); |
bbudge
2015/05/01 20:08:59
Chromium coding style: no space after '(', '>', an
|
+ ~YUVConv(); |
+ bool Initialize(); |
+ void Convert( const scoped_refptr<media::VideoFrame> & frame, |
+ GLuint texOut ); |
bbudge
2015/05/01 20:08:59
Style: Chrome uses texture_out style rather than c
|
+ |
+ private: |
+ GLuint CreateShader(); |
+ GLuint CompileShader( const char * name, GLuint type, const char * code ); |
bbudge
2015/05/01 20:08:58
s/char * name/char* name
|
+ 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(); |
+ |
+ private: |
bbudge
2015/05/01 20:08:59
duplicate private
|
+ 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(YUVConv); |
+}; |
+ |
+YUVConv::YUVConv( |
+ 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
|
+ : context_provider_( ctx_p ) |
+ , gl_( context_provider_->ContextGL() ) |
bbudge
2015/05/01 20:08:59
Chromium style puts the commas on the previous lin
|
+ , 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) { |
+} |
+ |
+YUVConv::~YUVConv() { |
+ // 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 YUVConv::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 YUVConv::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); |
+ if(status != GL_TRUE) |
+ { |
+ GLint maxLength = 0; |
+ gl_->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); |
+ |
+ // The maxLength includes the NULL character |
+ std::string errorLog(0,maxLength); |
+ gl_->GetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); |
+ |
+ LOG(ERROR) << name << " shader compilation failed: " |
+ << errorLog.c_str(); |
+ gl_->DeleteShader( shader ); |
+ return 0; |
+ } |
+ |
+ return shader; |
+} |
+ |
+GLuint YUVConv::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, "aPosition"); |
+ |
+ gl_->LinkProgram(program); |
+ |
+ GLint status = 0; |
+ |
+ gl_->GetProgramiv(program, GL_LINK_STATUS, &status); |
+ if(status != GL_TRUE) |
+ { |
+ GLint maxLength = 0; |
+ gl_->GetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); |
+ |
+ // The maxLength includes the NULL character |
+ std::string errorLog(0,maxLength); |
+ gl_->GetProgramInfoLog(program, maxLength, &maxLength, &errorLog[0]); |
+ |
+ LOG(ERROR) << name << " program linking failed: " |
+ << errorLog.c_str(); |
+ return 0; |
+ } |
+ |
+ return program; |
+} |
+ |
+bool YUVConv::SetUniform( GLuint program, const char * name, |
+ int value ) { |
+ bool result = false; |
+ GLint loc = gl_->GetUniformLocation( program, name ); |
+ if( loc != -1 ) |
+ { |
+ gl_->UseProgram( program ); |
+ gl_->Uniform1i( loc, value ); |
+ gl_->UseProgram( 0 ); |
+ result = true; |
+ } |
+ |
+ return result; |
+} |
+ |
+bool YUVConv::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 YUVConv::CreateShader() { |
+ const char* vertShader = |
+ "precision mediump float;\n" |
+ "attribute vec2 aPosition;\n" |
+ "varying vec2 vTexCoord;\n" |
+ "uniform float clamp_width;\n" |
+ "void main()\n" |
+ "{\n" |
+ " gl_Position = vec4( aPosition.xy, 0, 1 );\n" |
+ // convert vertex positions to texcoords, clamp x |
+ " vec2 tmp = aPosition*0.5+0.5;\n" |
+ " vTexCoord = vec2(min(tmp.x, clamp_width), tmp.y);\n" |
+ "}"; |
+ |
+ const char* fragShader = |
+ "precision mediump float;\n" |
+ "varying vec2 vTexCoord;\n" |
+ "#define texSample texture2D\n" |
+ "#define fragColor gl_FragColor\n" |
+ "uniform sampler2D texY;\n" |
+ "uniform sampler2D texU;\n" |
+ "uniform sampler2D texV;\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( texSample(texY, vTexCoord).x,\n" |
+ " texSample(texU, vTexCoord).x,\n" |
+ " texSample(texV, vTexCoord).x ) +\n" |
+ " yuv_adjust_constrained;\n" |
+ " fragColor = vec4( yuv_2_rgb * yuv, 1.0 );\n" |
+ "}"; |
+ |
+ // |
+ // Compile vertex and fragment shaders. |
+ // |
+ GLuint vertexShader = CompileShader( "Vertex Shader", GL_VERTEX_SHADER, |
+ vertShader ); |
+ if( !vertexShader ) |
+ { |
+ return 0; |
+ } |
+ |
+ GLuint fragmentShader = CompileShader("Fragment Shader", GL_FRAGMENT_SHADER, |
+ fragShader); |
+ if( !fragmentShader ) |
+ { |
+ gl_->DeleteShader( vertexShader ); |
+ return 0; |
+ } |
+ |
+ // |
+ // Create the program |
+ // |
+ GLuint program = CreateProgram( "YUVConv Program", vertexShader, |
+ fragmentShader ); |
+ |
+ // delete shaders since they are no longer needed |
+ gl_->DeleteShader( vertexShader ); |
+ gl_->DeleteShader( fragmentShader ); |
+ |
+ if( !program ) |
+ { |
+ return 0; |
+ } |
+ |
+ GLuint result = program; |
+ |
+ // |
+ // Bind samplers to texture units - which never change. |
+ // |
+ if( !SetUniform( program, "texY", 0 ) ) |
+ { |
+ result = 0; |
+ } |
+ if( !SetUniform( program, "texU", 1 ) ) |
+ { |
+ result = 0; |
+ } |
+ if( !SetUniform( program, "texV", 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 YUVConv::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 |
+ gl_->PushGroupMarkerEXT(0, "YUVConvContext"); |
+ |
+ // |
+ // 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 vtxBuf[] = { -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, vtxBuf, |
+ GL_STATIC_DRAW ); |
+ // unbind |
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 0); |
+ |
+ // |
+ // Create Shader |
+ // |
+ program_ = CreateShader(); |
+ |
+ gl_->PopGroupMarkerEXT(); |
+ |
+ return true; |
+} |
+ |
+void YUVConv::Convert( const scoped_refptr<media::VideoFrame> & frame, |
+ GLuint texOut ) { |
+ 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, "YUVConvContext"); |
+ |
+ 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? |
+ 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, texOut, 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 +649,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. |
@@ -68,12 +665,9 @@ VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id) |
} |
VideoDecoderShim::PendingFrame::PendingFrame(uint32_t decode_id, |
- const gfx::Size& coded_size, |
- const gfx::Rect& visible_rect) |
+ const scoped_refptr<media::VideoFrame>& frame) |
: decode_id(decode_id), |
- coded_size(coded_size), |
- visible_rect(visible_rect), |
- argb_pixels(coded_size.width() * coded_size.height() * 4) { |
+ video_frame(frame) { |
} |
VideoDecoderShim::PendingFrame::~PendingFrame() { |
@@ -269,13 +863,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 +893,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 YUVConv( context_provider_ )); |
} |
VideoDecoderShim::~VideoDecoderShim() { |
@@ -343,6 +932,12 @@ 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 +1066,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 +1093,13 @@ void VideoDecoderShim::OnOutputComplete(scoped_ptr<PendingFrame> frame) { |
pending_texture_mailboxes_.push_back(gpu::Mailbox::Generate()); |
host_->RequestTextures(texture_pool_size_, |
- frame->coded_size, |
+ 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 +1115,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(); |
} |