18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "remoting/codec/video_decoder_vpx.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <math.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <algorithm> 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/yuv_convert.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/util.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/libyuv/include/libyuv/convert_argb.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define VPX_CODEC_DISABLE_COMPAT 1 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace { 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const uint32 kTransparentColor = 0; 288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Fills the rectangle |rect| with the given ARGB color |color| in |buffer|. 308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void FillRect(uint8* buffer, 318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int stride, 328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const webrtc::DesktopRect& rect, 338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) uint32 color) { 348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) + 358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) (rect.left() * VideoDecoder::kBytesPerPixel)); 368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int width = rect.width(); 378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) for (int height = rect.height(); height > 0; --height) { 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::fill(ptr, ptr + width, color); 398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ptr += stride / VideoDecoder::kBytesPerPixel; 408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} // namespace 448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static 468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() { 478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ScopedVpxCodec codec(new vpx_codec_ctx_t); 488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // TODO(hclam): Scale the number of threads with number of cores of the 508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // machine. 518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_dec_cfg config; 528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.w = 0; 538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.h = 0; 548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.threads = 2; 558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_err_t ret = 568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_dec_init(codec.get(), vpx_codec_vp8_dx(), &config, 0); 578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (ret != VPX_CODEC_OK) { 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG(ERROR) << "Cannot initialize codec."; 598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return scoped_ptr<VideoDecoderVpx>(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return scoped_ptr<VideoDecoderVpx>(new VideoDecoderVpx(codec.Pass())); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() { 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ScopedVpxCodec codec(new vpx_codec_ctx_t); 688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // TODO(hclam): Scale the number of threads with number of cores of the 708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // machine. 718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_dec_cfg config; 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.w = 0; 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.h = 0; 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.threads = 2; 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_err_t ret = 768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_dec_init(codec.get(), vpx_codec_vp9_dx(), &config, 0); 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (ret != VPX_CODEC_OK) { 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG(ERROR) << "Cannot initialize codec."; 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return scoped_ptr<VideoDecoderVpx>(); 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return scoped_ptr<VideoDecoderVpx>(new VideoDecoderVpx(codec.Pass())); 838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)VideoDecoderVpx::~VideoDecoderVpx() {} 868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VideoDecoderVpx::Initialize(const webrtc::DesktopSize& screen_size) { 88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(!screen_size.is_empty()); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) screen_size_ = screen_size; 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) transparent_region_.SetRect(webrtc::DesktopRect::MakeSize(screen_size_)); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet) { 968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(!screen_size_.is_empty()); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do the actual decoding. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vpx_codec_err_t ret = vpx_codec_decode( 1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) codec_.get(), reinterpret_cast<const uint8*>(packet.data().data()), 10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) packet.data().size(), NULL, 0); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ret != VPX_CODEC_OK) { 103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const char* error = vpx_codec_error(codec_.get()); 104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const char* error_detail = vpx_codec_error_detail(codec_.get()); 105c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n" 106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch << "Details: " << (error_detail ? error_detail : "(NULL)"); 10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return false; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Gets the decoded data. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vpx_codec_iter_t iter = NULL; 1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_image_t* image = vpx_codec_get_frame(codec_.get(), &iter); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!image) { 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LOG(ERROR) << "No video frame decoded"; 11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return false; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_image_ = image; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion region; 12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int i = 0; i < packet.dirty_rects_size(); ++i) { 12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) Rect remoting_rect = packet.dirty_rects(i); 122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) region.AddRect(webrtc::DesktopRect::MakeXYWH( 123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) remoting_rect.x(), remoting_rect.y(), 124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) remoting_rect.width(), remoting_rect.height())); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region_.AddRegion(region); 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Update the desktop shape region. 130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion desktop_shape_region; 13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (packet.has_use_desktop_shape()) { 13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (int i = 0; i < packet.desktop_shape_rects_size(); ++i) { 13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) Rect remoting_rect = packet.desktop_shape_rects(i); 134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) desktop_shape_region.AddRect(webrtc::DesktopRect::MakeXYWH( 135d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) remoting_rect.x(), remoting_rect.y(), 136d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) remoting_rect.width(), remoting_rect.height())); 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Fallback for the case when the host didn't include the desktop shape 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // region. 141d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) desktop_shape_region = 142d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion(webrtc::DesktopRect::MakeSize(screen_size_)); 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UpdateImageShapeRegion(&desktop_shape_region); 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 14768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return true; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VideoDecoderVpx::Invalidate(const webrtc::DesktopSize& view_size, 151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const webrtc::DesktopRegion& region) { 152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(!view_size.is_empty()); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { 155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region_.AddRect(ScaleRect(i.rect(), view_size, screen_size_)); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Updated areas outside of the new desktop shape region should be made 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // transparent, not repainted. 160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion difference = updated_region_; 161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) difference.Subtract(desktop_shape_); 162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region_.Subtract(difference); 163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) transparent_region_.AddRegion(difference); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VideoDecoderVpx::RenderFrame(const webrtc::DesktopSize& view_size, 167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const webrtc::DesktopRect& clip_area, 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* image_buffer, 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int image_stride, 170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion* output_region) { 1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(!screen_size_.is_empty()); 172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(!view_size.is_empty()); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Early-return and do nothing if we haven't yet decoded any frames. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!last_image_) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRect source_clip = 179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRect::MakeWH(last_image_->d_w, last_image_->d_h); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // VP8 only outputs I420 frames, but VP9 can also produce I444. 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (last_image_->fmt) { 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case VPX_IMG_FMT_I444: { 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(wez): Add scaling support to the I444 conversion path. 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (view_size.equals(screen_size_)) { 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (webrtc::DesktopRegion::Iterator i(updated_region_); 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) !i.IsAtEnd(); i.Advance()) { 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Determine the scaled area affected by this rectangle changing. 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webrtc::DesktopRect rect = i.rect(); 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.IntersectWith(source_clip); 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.IntersectWith(clip_area); 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rect.is_empty()) 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) continue; 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int image_offset = image_stride * rect.top() + 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.left() * VideoDecoder::kBytesPerPixel; 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int y_offset = last_image_->stride[0] * rect.top() + rect.left(); 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int u_offset = last_image_->stride[1] * rect.top() + rect.left(); 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int v_offset = last_image_->stride[2] * rect.top() + rect.left(); 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) libyuv::I444ToARGB(last_image_->planes[0] + y_offset, 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[0], 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->planes[1] + u_offset, 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[1], 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->planes[2] + v_offset, 205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[2], 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image_buffer + image_offset, image_stride, 207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.width(), rect.height()); 208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output_region->AddRect(rect); 210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case VPX_IMG_FMT_I420: { 215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // ScaleYUVToRGB32WithRect does not currently support up-scaling. We 216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // won't be asked to up-scale except during resizes or if page zoom is 217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // >100%, so we work-around the limitation by using the slower 218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // ScaleYUVToRGB32. 219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // TODO(wez): Remove this hack if/when ScaleYUVToRGB32WithRect can 220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // up-scale. 221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!updated_region_.is_empty() && 222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) (source_clip.width() < view_size.width() || 223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_clip.height() < view_size.height())) { 224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We're scaling only |clip_area| into the |image_buffer|, so we need to 225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // work out which source rectangle that corresponds to. 226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webrtc::DesktopRect source_rect = 227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ScaleRect(clip_area, view_size, screen_size_); 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_rect = webrtc::DesktopRect::MakeLTRB( 229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RoundToTwosMultiple(source_rect.left()), 230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RoundToTwosMultiple(source_rect.top()), 231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_rect.right(), 232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_rect.bottom()); 233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // If there were no changes within the clip source area then don't 235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // render. 236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webrtc::DesktopRegion intersection(source_rect); 237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) intersection.IntersectWith(updated_region_); 238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (intersection.is_empty()) 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Scale & convert the entire clip area. 242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int y_offset = CalculateYOffset(source_rect.left(), source_rect.top(), 243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[0]); 244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int uv_offset = CalculateUVOffset(source_rect.left(), source_rect.top(), 245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[1]); 246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ScaleYUVToRGB32(last_image_->planes[0] + y_offset, 247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->planes[1] + uv_offset, 248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->planes[2] + uv_offset, 249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image_buffer, 250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_rect.width(), 251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_rect.height(), 252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) clip_area.width(), 253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) clip_area.height(), 254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[0], 255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[1], 256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image_stride, 257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::YV12, 258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::ROTATE_0, 259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::FILTER_BILINEAR); 260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output_region->AddRect(clip_area); 262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) updated_region_.Subtract(source_rect); 263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (webrtc::DesktopRegion::Iterator i(updated_region_); 267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) !i.IsAtEnd(); i.Advance()) { 268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Determine the scaled area affected by this rectangle changing. 269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) webrtc::DesktopRect rect = i.rect(); 270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.IntersectWith(source_clip); 271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rect.is_empty()) 272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) continue; 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect = ScaleRect(rect, screen_size_, view_size); 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.IntersectWith(clip_area); 275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rect.is_empty()) 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) continue; 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], 279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->planes[1], 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->planes[2], 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[0], 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) last_image_->stride[1], 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) screen_size_, 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) source_clip, 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image_buffer, 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image_stride, 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) view_size, 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) clip_area, 289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect); 290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output_region->AddRect(rect); 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) updated_region_.Subtract(ScaleRect(clip_area, view_size, screen_size_)); 295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: { 298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LOG(ERROR) << "Unsupported image format:" << last_image_->fmt; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 303d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) for (webrtc::DesktopRegion::Iterator i(transparent_region_); 304d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) !i.IsAtEnd(); i.Advance()) { 305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Determine the scaled area affected by this rectangle changing. 306d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRect rect = i.rect(); 307d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) rect.IntersectWith(source_clip); 308d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (rect.is_empty()) 309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch rect = ScaleRect(rect, screen_size_, view_size); 311d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) rect.IntersectWith(clip_area); 312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (rect.is_empty()) 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Fill the rectange with transparent pixels. 3168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) FillRect(image_buffer, image_stride, rect, kTransparentColor); 317d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) output_region->AddRect(rect); 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 320d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRect scaled_clip_area = 321d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ScaleRect(clip_area, view_size, screen_size_); 322d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region_.Subtract(scaled_clip_area); 323d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) transparent_region_.Subtract(scaled_clip_area); 324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const webrtc::DesktopRegion* VideoDecoderVpx::GetImageShape() { 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return &desktop_shape_; 328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)VideoDecoderVpx::VideoDecoderVpx(ScopedVpxCodec codec) 3318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) : codec_(codec.Pass()), 3328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) last_image_(NULL) { 3338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK(codec_); 334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VideoDecoderVpx::UpdateImageShapeRegion( 337d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion* new_desktop_shape) { 338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Add all areas that have been updated or become transparent to the 339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // transparent region. Exclude anything within the new desktop shape. 340d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) transparent_region_.AddRegion(desktop_shape_); 341d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) transparent_region_.AddRegion(updated_region_); 342d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) transparent_region_.Subtract(*new_desktop_shape); 343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Add newly exposed areas to the update region and limit updates to the new 345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // desktop shape. 346d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion difference = *new_desktop_shape; 347d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) difference.Subtract(desktop_shape_); 348d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region_.AddRegion(difference); 349d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region_.IntersectWith(*new_desktop_shape); 350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Set the new desktop shape region. 352d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) desktop_shape_.Swap(new_desktop_shape); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace remoting 356