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 "remoting/client/plugin/pepper_video_renderer_3d.h" | 5 #include "remoting/client/plugin/pepper_video_renderer_3d.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
| 10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 11 #include "ppapi/c/pp_codecs.h" | 11 #include "ppapi/c/pp_codecs.h" |
| 12 #include "ppapi/c/ppb_opengles2.h" | 12 #include "ppapi/c/ppb_opengles2.h" |
| 13 #include "ppapi/c/ppb_video_decoder.h" | 13 #include "ppapi/c/ppb_video_decoder.h" |
| 14 #include "ppapi/cpp/instance.h" | 14 #include "ppapi/cpp/instance.h" |
| 15 #include "ppapi/lib/gl/include/GLES2/gl2.h" | 15 #include "ppapi/lib/gl/include/GLES2/gl2.h" |
| 16 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" | 16 #include "ppapi/lib/gl/include/GLES2/gl2ext.h" |
| 17 #include "remoting/proto/video.pb.h" | 17 #include "remoting/proto/video.pb.h" |
| 18 #include "remoting/protocol/performance_tracker.h" | 18 #include "remoting/protocol/performance_tracker.h" |
| 19 #include "remoting/protocol/session_config.h" | 19 #include "remoting/protocol/session_config.h" |
| 20 | 20 |
| 21 namespace remoting { | 21 namespace remoting { |
| 22 | 22 |
| 23 // The implementation here requires that the decoder allocates at least 3 | 23 // The implementation here requires that the decoder allocates at least 3 |
| 24 // pictures. PPB_VideoDecode didn't support this parameter prior to | 24 // pictures. PPB_VideoDecoder didn't support this parameter prior to |
| 25 // 1.1, so we have to pass 0 for backwards compatibility with older versions of | 25 // 1.1, so we have to pass 0 for backwards compatibility with older versions of |
| 26 // the browser. Currently all API implementations allocate more than 3 buffers | 26 // the browser. Currently all API implementations allocate more than 3 buffers |
| 27 // by default. | 27 // by default. |
| 28 // | 28 // |
| 29 // TODO(sergeyu): Change this to 3 once PPB_VideoDecode v1.1 is enabled on | 29 // TODO(sergeyu): Change this to 3 once PPB_VideoDecoder v1.1 is enabled on |
| 30 // stable channel. | 30 // stable channel. |
|
Wez
2015/10/19 21:56:16
nit: Is there a bug filed for that work? If so, re
Sergey Ulanov
2015/10/19 22:19:51
Added reference to the bug to get 1.1 API enabled
| |
| 31 const uint32_t kMinimumPictureCount = 0; // 3 | 31 const uint32_t kMinimumPictureCount = 0; // 3 |
| 32 | 32 |
| 33 class PepperVideoRenderer3D::PendingPacket { | 33 class PepperVideoRenderer3D::PendingPacket { |
| 34 public: | 34 public: |
| 35 PendingPacket(scoped_ptr<VideoPacket> packet, const base::Closure& done) | 35 PendingPacket(scoped_ptr<VideoPacket> packet, const base::Closure& done) |
| 36 : packet_(packet.Pass()), | 36 : packet_(packet.Pass()), |
| 37 done_runner_(done) { | 37 done_runner_(done) { |
| 38 } | 38 } |
| 39 | 39 |
| 40 ~PendingPacket() {} | 40 ~PendingPacket() {} |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 webrtc::DesktopRegion dirty_region; | 238 webrtc::DesktopRegion dirty_region; |
| 239 for (int i = 0; i < packet->dirty_rects_size(); ++i) { | 239 for (int i = 0; i < packet->dirty_rects_size(); ++i) { |
| 240 Rect remoting_rect = packet->dirty_rects(i); | 240 Rect remoting_rect = packet->dirty_rects(i); |
| 241 dirty_region.AddRect(webrtc::DesktopRect::MakeXYWH( | 241 dirty_region.AddRect(webrtc::DesktopRect::MakeXYWH( |
| 242 remoting_rect.x(), remoting_rect.y(), | 242 remoting_rect.x(), remoting_rect.y(), |
| 243 remoting_rect.width(), remoting_rect.height())); | 243 remoting_rect.width(), remoting_rect.height())); |
| 244 } | 244 } |
| 245 event_handler_->OnVideoFrameDirtyRegion(dirty_region); | 245 event_handler_->OnVideoFrameDirtyRegion(dirty_region); |
| 246 } | 246 } |
| 247 | 247 |
| 248 if (frame_sizes_) { | |
| 249 frame_sizes_->insert(std::make_pair(packet->frame_id(), frame_size_)); | |
| 250 } | |
| 251 | |
| 248 pending_packets_.push_back( | 252 pending_packets_.push_back( |
| 249 new PendingPacket(packet.Pass(), done_runner.Release())); | 253 new PendingPacket(packet.Pass(), done_runner.Release())); |
| 250 DecodeNextPacket(); | 254 DecodeNextPacket(); |
| 251 } | 255 } |
| 252 | 256 |
| 253 void PepperVideoRenderer3D::OnInitialized(int32_t result) { | 257 void PepperVideoRenderer3D::OnInitialized(int32_t result) { |
| 254 // Assume that VP8 and VP9 codecs are always supported by the browser. | 258 // Assume that VP8 and VP9 codecs are always supported by the browser. |
| 255 CHECK_EQ(result, PP_OK) << "VideoDecoder::Initialize() failed: " << result; | 259 CHECK_EQ(result, PP_OK) << "VideoDecoder::Initialize() failed: " << result; |
| 256 initialization_finished_ = true; | 260 initialization_finished_ = true; |
| 257 | 261 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 306 get_picture_pending_ = false; | 310 get_picture_pending_ = false; |
| 307 | 311 |
| 308 if (result != PP_OK) { | 312 if (result != PP_OK) { |
| 309 LOG(ERROR) << "VideoDecoder::GetPicture() returned " << result; | 313 LOG(ERROR) << "VideoDecoder::GetPicture() returned " << result; |
| 310 event_handler_->OnVideoDecodeError(); | 314 event_handler_->OnVideoDecodeError(); |
| 311 return; | 315 return; |
| 312 } | 316 } |
| 313 | 317 |
| 314 perf_tracker_->OnFrameDecoded(picture.decode_id); | 318 perf_tracker_->OnFrameDecoded(picture.decode_id); |
| 315 | 319 |
| 320 // Workaround crbug.com/542945 by filling in visible_rect if it isn't set. | |
| 321 if (picture.visible_rect.size.width == 0 || | |
| 322 picture.visible_rect.size.height == 0 || frame_sizes_) { | |
| 323 | |
| 324 // Enable workaround by creating |frame_sizes_|. | |
| 325 if (!frame_sizes_) { | |
| 326 LOG(WARNING) << "PPB_VideoDecoder doesn't set visible_rect."; | |
| 327 frame_sizes_.reset(new FrameSizesMap()); | |
| 328 } | |
| 329 | |
| 330 FrameSizesMap::iterator size_it = frame_sizes_->find(picture.decode_id); | |
| 331 if (size_it != frame_sizes_->end()) { | |
| 332 picture.visible_rect.size.width = size_it->second.width(); | |
| 333 picture.visible_rect.size.height = size_it->second.height(); | |
| 334 frame_sizes_->erase(size_it); | |
| 335 } else { | |
| 336 // For the first few frames |frames_sizes_| will be empty as | |
| 337 // |frame_sizes_| is created only after the first picture is received and | |
| 338 // it's known that the workaround is necessary. So here we use | |
| 339 // |texture_size| as frame size. This may result is some minor visual | |
| 340 // artifacts, which will disappear with the next frame processed by | |
| 341 // ProcessVideoPacket(). | |
| 342 picture.visible_rect.size.width = picture.texture_size.width; | |
| 343 picture.visible_rect.size.height = picture.texture_size.width; | |
| 344 } | |
| 345 } | |
| 346 | |
| 316 next_picture_.reset(new Picture(&video_decoder_, picture)); | 347 next_picture_.reset(new Picture(&video_decoder_, picture)); |
| 317 | 348 |
| 318 PaintIfNeeded(); | 349 PaintIfNeeded(); |
| 319 GetNextPicture(); | 350 GetNextPicture(); |
| 320 } | 351 } |
| 321 | 352 |
| 322 void PepperVideoRenderer3D::PaintIfNeeded() { | 353 void PepperVideoRenderer3D::PaintIfNeeded() { |
| 323 bool need_repaint = next_picture_ || (force_repaint_ && current_picture_); | 354 bool need_repaint = next_picture_ || (force_repaint_ && current_picture_); |
| 324 if (paint_pending_ || !need_repaint) | 355 if (paint_pending_ || !need_repaint) |
| 325 return; | 356 return; |
| 326 | 357 |
| 327 if (next_picture_) | 358 if (next_picture_) |
| 328 current_picture_ = next_picture_.Pass(); | 359 current_picture_ = next_picture_.Pass(); |
| 329 | 360 |
| 330 force_repaint_ = false; | 361 force_repaint_ = false; |
| 331 | 362 |
| 332 const PP_VideoPicture& picture = current_picture_->picture(); | 363 const PP_VideoPicture& picture = current_picture_->picture(); |
| 333 PP_Resource graphics_3d = graphics_.pp_resource(); | 364 PP_Resource graphics_3d = graphics_.pp_resource(); |
| 334 | 365 |
| 335 EnsureProgramForTexture(picture.texture_target); | 366 EnsureProgramForTexture(picture.texture_target); |
| 336 | 367 |
| 337 gles2_if_->UseProgram(graphics_3d, shader_program_); | 368 gles2_if_->UseProgram(graphics_3d, shader_program_); |
| 338 | 369 |
| 339 // Calculate v_scale passed to the vertex shader. | 370 // Calculate v_scale passed to the vertex shader. |
| 340 double scale_x = picture.visible_rect.size.width; | 371 double scale_x = picture.visible_rect.size.width; |
| 341 double scale_y = picture.visible_rect.size.height; | 372 double scale_y = picture.visible_rect.size.height; |
| 342 if (picture.texture_target != GL_TEXTURE_RECTANGLE_ARB) { | 373 if (picture.texture_target != GL_TEXTURE_RECTANGLE_ARB) { |
| 374 CHECK(picture.texture_size.width > 0 && picture.texture_size.height > 0); | |
|
Sergey Ulanov
2015/10/19 21:47:20
These CHECKs will help to diagnose similar issues
| |
| 343 scale_x /= picture.texture_size.width; | 375 scale_x /= picture.texture_size.width; |
| 344 scale_y /= picture.texture_size.height; | 376 scale_y /= picture.texture_size.height; |
| 345 } | 377 } |
| 346 gles2_if_->Uniform2f(graphics_3d, shader_texcoord_scale_location_, | 378 gles2_if_->Uniform2f(graphics_3d, shader_texcoord_scale_location_, |
| 347 scale_x, scale_y); | 379 scale_x, scale_y); |
| 348 | 380 |
| 349 // Set viewport position & dimensions. | 381 // Set viewport position & dimensions. |
| 350 gles2_if_->Viewport(graphics_3d, 0, 0, view_size_.width(), | 382 gles2_if_->Viewport(graphics_3d, 0, 0, view_size_.width(), |
| 351 view_size_.height()); | 383 view_size_.height()); |
| 352 | 384 |
| 353 // Select the texture unit GL_TEXTURE0. | 385 // Select the texture unit GL_TEXTURE0. |
| 354 gles2_if_->ActiveTexture(graphics_3d, GL_TEXTURE0); | 386 gles2_if_->ActiveTexture(graphics_3d, GL_TEXTURE0); |
| 355 | 387 |
| 356 // Select the texture. | 388 // Select the texture. |
| 357 gles2_if_->BindTexture(graphics_3d, picture.texture_target, | 389 gles2_if_->BindTexture(graphics_3d, picture.texture_target, |
| 358 picture.texture_id); | 390 picture.texture_id); |
| 359 | 391 |
| 360 // Select linear filter in case the texture needs to be scaled. | 392 // Select linear filter in case the texture needs to be scaled. |
| 361 gles2_if_->TexParameteri(graphics_3d, picture.texture_target, | 393 gles2_if_->TexParameteri(graphics_3d, picture.texture_target, |
| 362 GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 394 GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 363 | 395 |
| 364 // When view dimensions are a multiple of the frame size then use | 396 // When view dimensions are a multiple of the frame size then use |
| 365 // nearest-neighbor scaling to achieve crisper image. Linear filter is used in | 397 // nearest-neighbor scaling to achieve crisper image. Linear filter is used in |
| 366 // all other cases. | 398 // all other cases. |
| 367 GLint mag_filter = GL_LINEAR; | 399 GLint mag_filter = GL_LINEAR; |
| 400 CHECK(picture.visible_rect.size.width > 0 && | |
| 401 picture.visible_rect.size.height > 0); | |
| 368 if (view_size_.width() % picture.visible_rect.size.width == 0 && | 402 if (view_size_.width() % picture.visible_rect.size.width == 0 && |
| 369 view_size_.height() % picture.visible_rect.size.height == 0) { | 403 view_size_.height() % picture.visible_rect.size.height == 0) { |
| 370 mag_filter = GL_NEAREST; | 404 mag_filter = GL_NEAREST; |
| 371 } | 405 } |
| 372 gles2_if_->TexParameteri(graphics_3d, picture.texture_target, | 406 gles2_if_->TexParameteri(graphics_3d, picture.texture_target, |
| 373 GL_TEXTURE_MAG_FILTER, mag_filter); | 407 GL_TEXTURE_MAG_FILTER, mag_filter); |
| 374 | 408 |
| 375 // Render texture by drawing a triangle strip with 4 vertices. | 409 // Render texture by drawing a triangle strip with 4 vertices. |
| 376 gles2_if_->DrawArrays(graphics_3d, GL_TRIANGLE_STRIP, 0, 4); | 410 gles2_if_->DrawArrays(graphics_3d, GL_TRIANGLE_STRIP, 0, 4); |
| 377 | 411 |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 gles2_if_->AttachShader(graphics_.pp_resource(), shader_program_, shader); | 533 gles2_if_->AttachShader(graphics_.pp_resource(), shader_program_, shader); |
| 500 gles2_if_->DeleteShader(graphics_.pp_resource(), shader); | 534 gles2_if_->DeleteShader(graphics_.pp_resource(), shader); |
| 501 } | 535 } |
| 502 | 536 |
| 503 void PepperVideoRenderer3D::CheckGLError() { | 537 void PepperVideoRenderer3D::CheckGLError() { |
| 504 GLenum error = gles2_if_->GetError(graphics_.pp_resource()); | 538 GLenum error = gles2_if_->GetError(graphics_.pp_resource()); |
| 505 CHECK_EQ(error, static_cast<GLenum>(GL_NO_ERROR)) << "GL error: " << error; | 539 CHECK_EQ(error, static_cast<GLenum>(GL_NO_ERROR)) << "GL error: " << error; |
| 506 } | 540 } |
| 507 | 541 |
| 508 } // namespace remoting | 542 } // namespace remoting |
| OLD | NEW |