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