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_encoder_vpx.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/bind.h" 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/command_line.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_info.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/util.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/proto/video.pb.h" 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "third_party/libyuv/include/libyuv/convert_from_argb.h" 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_region.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define VPX_CODEC_DISABLE_COMPAT 1 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace remoting { 258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Name of command-line flag to enable VP9 to use I444 by default. 29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kEnableI444SwitchName[] = "enable-i444"; 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Number of bytes in an RGBx pixel. 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kBytesPerRgbPixel = 4; 33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Defines the dimension of a macro block. This is used to compute the active 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// map for the encoder. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMacroBlockSize = 16; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Magic encoder profile numbers for I420 and I444 input formats. 39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kVp9I420ProfileNumber = 0; 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kVp9I444ProfileNumber = 1; 41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void SetCommonCodecParameters(const webrtc::DesktopSize& size, 43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) vpx_codec_enc_cfg_t* config) { 44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Use millisecond granularity time base. 45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_timebase.num = 1; 46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_timebase.den = 1000; 47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Adjust default target bit-rate to account for actual desktop size. 49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->rc_target_bitrate = size.width() * size.height() * 50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->rc_target_bitrate / config->g_w / config->g_h; 51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_w = size.width(); 53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_h = size.height(); 54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_pass = VPX_RC_ONE_PASS; 55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Start emitting packets immediately. 57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_lag_in_frames = 0; 58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Using 2 threads gives a great boost in performance for most systems with 60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // adequate processing power. NB: Going to multiple threads on low end 61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // windows systems can really hurt performance. 62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // http://crbug.com/99179 63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) config->g_threads = (base::SysInfo::NumberOfProcessors() > 2) ? 2 : 1; 64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ScopedVpxCodec CreateVP8Codec(const webrtc::DesktopSize& size) { 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ScopedVpxCodec codec(new vpx_codec_ctx_t); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Configure the encoder. 708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_enc_cfg_t config; 718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const vpx_codec_iface_t* algo = vpx_codec_vp8_cx(); 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) CHECK(algo); 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0); 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (ret != VPX_CODEC_OK) 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return ScopedVpxCodec(); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetCommonCodecParameters(size, &config); 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Value of 2 means using the real time profile. This is basically a 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // redundant option since we explicitly select real time mode when doing 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // encoding. 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.g_profile = 2; 838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Clamping the quantizer constrains the worst-case quality and CPU usage. 858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.rc_min_quantizer = 20; 868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) config.rc_max_quantizer = 30; 878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (vpx_codec_enc_init(codec.get(), algo, &config, 0)) 898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return ScopedVpxCodec(); 908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Value of 16 will have the smallest CPU load. This turns off subpixel 928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // motion search. 938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, 16)) 948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return ScopedVpxCodec(); 958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Use the lowest level of noise sensitivity so as to spend less time 978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // on motion estimation and inter-prediction mode. 988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (vpx_codec_control(codec.get(), VP8E_SET_NOISE_SENSITIVITY, 0)) 998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return ScopedVpxCodec(); 1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return codec.Pass(); 1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ScopedVpxCodec CreateVP9Codec(const webrtc::DesktopSize& size, 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool lossless_color, 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool lossless_encode) { 107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch ScopedVpxCodec codec(new vpx_codec_ctx_t); 108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Configure the encoder. 110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch vpx_codec_enc_cfg_t config; 111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch const vpx_codec_iface_t* algo = vpx_codec_vp9_cx(); 112e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch CHECK(algo); 113e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0); 114e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (ret != VPX_CODEC_OK) 115e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ScopedVpxCodec(); 116e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SetCommonCodecParameters(size, &config); 118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Configure VP9 for I420 or I444 source frames. 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.g_profile = 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lossless_color ? kVp9I444ProfileNumber : kVp9I420ProfileNumber; 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (lossless_encode) { 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Disable quantization entirely, putting the encoder in "lossless" mode. 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.rc_min_quantizer = 0; 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.rc_max_quantizer = 0; 127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Lossy encode using the same settings as for VP8. 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.rc_min_quantizer = 20; 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) config.rc_max_quantizer = 30; 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 132e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 133e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch if (vpx_codec_enc_init(codec.get(), algo, &config, 0)) 134e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ScopedVpxCodec(); 135e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Request the lowest-CPU usage that VP9 supports, which depends on whether 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // we are encoding lossy or lossless. 138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Note that this is configured via the same parameter as for VP8. 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int cpu_used = lossless_encode ? 5 : 7; 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, cpu_used)) 141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ScopedVpxCodec(); 142e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // Use the lowest level of noise sensitivity so as to spend less time 144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch // on motion estimation and inter-prediction mode. 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (vpx_codec_control(codec.get(), VP9E_SET_NOISE_SENSITIVITY, 0)) 146e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return ScopedVpxCodec(); 147e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return codec.Pass(); 149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch} 150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void CreateImage(bool use_i444, 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const webrtc::DesktopSize& size, 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<vpx_image_t>* out_image, 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<uint8[]>* out_image_buffer) { 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!size.is_empty()); 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<vpx_image_t> image(new vpx_image_t()); 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) memset(image.get(), 0, sizeof(vpx_image_t)); 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // libvpx seems to require both to be assigned. 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->d_w = size.width(); 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->w = size.width(); 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->d_h = size.height(); 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->h = size.height(); 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // libvpx should derive chroma shifts from|fmt| but currently has a bug: 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // https://code.google.com/p/webm/issues/detail?id=627 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (use_i444) { 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->fmt = VPX_IMG_FMT_I444; 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->x_chroma_shift = 0; 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->y_chroma_shift = 0; 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { // I420 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->fmt = VPX_IMG_FMT_YV12; 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->x_chroma_shift = 1; 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->y_chroma_shift = 1; 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // the Y, U and V planes' strides to multiples of 16 bytes. 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int y_stride = ((image->w - 1) & ~15) + 16; 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // libvpx accesses the source image in macro blocks, and will over-read 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // if the image is not padded out to the next macroblock: crbug.com/119633. 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Pad the Y, U and V planes' height out to compensate. 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Assuming macroblocks are 16x16, aligning the planes' strides above also 188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // macroblock aligned them. 189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK_EQ(16, kMacroBlockSize); 190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int y_rows = ((image->h - 1) & ~(kMacroBlockSize-1)) + kMacroBlockSize; 191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int uv_rows = y_rows >> image->y_chroma_shift; 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Allocate a YUV buffer large enough for the aligned data & padding. 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows; 195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<uint8[]> image_buffer(new uint8[buffer_size]); 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Reset image value to 128 so we just need to fill in the y plane. 198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) memset(image_buffer.get(), 128, buffer_size); 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Fill in the information for |image_|. 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unsigned char* uchar_buffer = 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) reinterpret_cast<unsigned char*>(image_buffer.get()); 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->planes[0] = uchar_buffer; 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->planes[1] = image->planes[0] + y_stride * y_rows; 205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->planes[2] = image->planes[1] + uv_stride * uv_rows; 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->stride[0] = y_stride; 207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->stride[1] = uv_stride; 208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) image->stride[2] = uv_stride; 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *out_image = image.Pass(); 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *out_image_buffer = image_buffer.Pass(); 212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} // namespace 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static 2178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() { 218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return scoped_ptr<VideoEncoderVpx>(new VideoEncoderVpx(false)); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 221e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// static 222e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochscoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9() { 223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return scoped_ptr<VideoEncoderVpx>(new VideoEncoderVpx(true)); 224e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch} 225e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 2268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)VideoEncoderVpx::~VideoEncoderVpx() {} 2278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void VideoEncoderVpx::SetLosslessEncode(bool want_lossless) { 229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (use_vp9_ && (want_lossless != lossless_encode_)) { 230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lossless_encode_ = want_lossless; 231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) codec_.reset(); // Force encoder re-initialization. 232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void VideoEncoderVpx::SetLosslessColor(bool want_lossless) { 236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (use_vp9_ && (want_lossless != lossless_color_)) { 237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lossless_color_ = want_lossless; 238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) codec_.reset(); // Force encoder re-initialization. 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 2428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<VideoPacket> VideoEncoderVpx::Encode( 2438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const webrtc::DesktopFrame& frame) { 2448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK_LE(32, frame.size().width()); 2458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK_LE(32, frame.size().height()); 2468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 247010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::TimeTicks encode_start_time = base::TimeTicks::Now(); 2488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!codec_ || 2508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h))) { 2518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) bool ret = Initialize(frame.size()); 2528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // TODO(hclam): Handle error better. 2538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) CHECK(ret) << "Initialization of encoder failed"; 254010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 255010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Set now as the base for timestamp calculation. 256010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) timestamp_base_ = encode_start_time; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Convert the updated capture data ready for encode. 2608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) webrtc::DesktopRegion updated_region; 2618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) PrepareImage(frame, &updated_region); 2628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Update active map based on updated region. 2648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) PrepareActiveMap(updated_region); 2658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Apply active map to the encoder. 2678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_active_map_t act_map; 2688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) act_map.rows = active_map_height_; 2698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) act_map.cols = active_map_width_; 2708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) act_map.active_map = active_map_.get(); 2718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { 2728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) LOG(ERROR) << "Unable to apply active map"; 2738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 2748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Do the actual encoding. 276010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) int timestamp = (encode_start_time - timestamp_base_).InMilliseconds(); 277010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) vpx_codec_err_t ret = vpx_codec_encode( 278010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME); 2798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) DCHECK_EQ(ret, VPX_CODEC_OK) 2808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" 2818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) << "Details: " << vpx_codec_error(codec_.get()) << "\n" 2828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) << vpx_codec_error_detail(codec_.get()); 2838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Read the encoded data. 2858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_iter_t iter = NULL; 2868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) bool got_data = false; 2878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // TODO(hclam): Make sure we get exactly one frame from the packet. 2898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // TODO(hclam): We should provide the output buffer to avoid one copy. 2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci scoped_ptr<VideoPacket> packet( 2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci helper_.CreateVideoPacketWithUpdatedRegion(frame, updated_region)); 2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); 2938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 2948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) while (!got_data) { 2958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const vpx_codec_cx_pkt_t* vpx_packet = 2968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) vpx_codec_get_cx_data(codec_.get(), &iter); 2978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (!vpx_packet) 2988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) continue; 2998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) switch (vpx_packet->kind) { 3018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) case VPX_CODEC_CX_FRAME_PKT: 3028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) got_data = true; 3038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) packet->set_data(vpx_packet->data.frame.buf, vpx_packet->data.frame.sz); 3048bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 3058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) default: 3068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) break; 3078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 3088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 3098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Note the time taken to encode the pixel data. 3118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) packet->set_encode_time_ms( 312010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp()); 3138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return packet.Pass(); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) 318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : use_vp9_(use_vp9), 319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lossless_encode_(false), 320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) lossless_color_(false), 3218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) active_map_width_(0), 322010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) active_map_height_(0) { 323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (use_vp9_) { 324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Use I444 colour space, by default, if specified on the command-line. 325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableI444SwitchName)) { 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetLosslessColor(true); 327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 3298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 3308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)bool VideoEncoderVpx::Initialize(const webrtc::DesktopSize& size) { 332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(use_vp9_ || !lossless_color_); 333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(use_vp9_ || !lossless_encode_); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) codec_.reset(); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // (Re)Create the VPX image structure and pixel buffer. 338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) CreateImage(lossless_color_, size, &image_, &image_buffer_); 3398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize active map. 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_map_width_ = (image_->w + kMacroBlockSize - 1) / kMacroBlockSize; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_map_height_ = (image_->h + kMacroBlockSize - 1) / kMacroBlockSize; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) active_map_.reset(new uint8[active_map_width_ * active_map_height_]); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // (Re)Initialize the codec. 346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (use_vp9_) { 347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) codec_ = CreateVP9Codec(size, lossless_color_, lossless_encode_); 348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) codec_ = CreateVP8Codec(size); 350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return codec_; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VideoEncoderVpx::PrepareImage(const webrtc::DesktopFrame& frame, 356d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRegion* updated_region) { 357d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (frame.updated_region().is_empty()) { 358d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region->Clear(); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Align the region to macroblocks, to avoid encoding artefacts. 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This also ensures that all rectangles have even-aligned top-left, which 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is required for ConvertRGBToYUVWithRect() to work. 365d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) std::vector<webrtc::DesktopRect> aligned_rects; 366d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) for (webrtc::DesktopRegion::Iterator r(frame.updated_region()); 36790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) !r.IsAtEnd(); r.Advance()) { 36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) const webrtc::DesktopRect& rect = r.rect(); 369d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) aligned_rects.push_back(AlignRect(webrtc::DesktopRect::MakeLTRB( 370d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) rect.left(), rect.top(), rect.right(), rect.bottom()))); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!aligned_rects.empty()); 373d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region->Clear(); 374d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region->AddRects(&aligned_rects[0], aligned_rects.size()); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clip back to the screen dimensions, in case they're not macroblock aligned. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The conversion routines don't require even width & height, so this is safe 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // even if the source dimensions are not even. 379d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) updated_region->IntersectWith( 380d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) webrtc::DesktopRect::MakeWH(image_->w, image_->h)); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert the updated region to YUV ready for encoding. 383d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const uint8* rgb_data = frame.data(); 384d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const int rgb_stride = frame.stride(); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int y_stride = image_->stride[0]; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(image_->stride[1], image_->stride[2]); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int uv_stride = image_->stride[1]; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* y_data = image_->planes[0]; 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* u_data = image_->planes[1]; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* v_data = image_->planes[2]; 391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) switch (image_->fmt) { 393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case VPX_IMG_FMT_I444: 394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (webrtc::DesktopRegion::Iterator r(*updated_region); !r.IsAtEnd(); 395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) r.Advance()) { 396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const webrtc::DesktopRect& rect = r.rect(); 397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int rgb_offset = rgb_stride * rect.top() + 398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.left() * kBytesPerRgbPixel; 399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int yuv_offset = uv_stride * rect.top() + rect.left(); 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) libyuv::ARGBToI444(rgb_data + rgb_offset, rgb_stride, 401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) y_data + yuv_offset, y_stride, 402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) u_data + yuv_offset, uv_stride, 403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) v_data + yuv_offset, uv_stride, 404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.width(), rect.height()); 405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) case VPX_IMG_FMT_YV12: 408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (webrtc::DesktopRegion::Iterator r(*updated_region); !r.IsAtEnd(); 409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) r.Advance()) { 410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const webrtc::DesktopRect& rect = r.rect(); 411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int rgb_offset = rgb_stride * rect.top() + 412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.left() * kBytesPerRgbPixel; 413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int y_offset = y_stride * rect.top() + rect.left(); 414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int uv_offset = uv_stride * rect.top() / 2 + rect.left() / 2; 415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) libyuv::ARGBToI420(rgb_data + rgb_offset, rgb_stride, 416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) y_data + y_offset, y_stride, 417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) u_data + uv_offset, uv_stride, 418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) v_data + uv_offset, uv_stride, 419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) rect.width(), rect.height()); 420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 422cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) default: 423cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) NOTREACHED(); 424cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) break; 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VideoEncoderVpx::PrepareActiveMap( 429d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const webrtc::DesktopRegion& updated_region) { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear active map first. 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(active_map_.get(), 0, active_map_width_ * active_map_height_); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mark updated areas active. 434d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) for (webrtc::DesktopRegion::Iterator r(updated_region); !r.IsAtEnd(); 435d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) r.Advance()) { 436d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const webrtc::DesktopRect& rect = r.rect(); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int left = rect.left() / kMacroBlockSize; 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int right = (rect.right() - 1) / kMacroBlockSize; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int top = rect.top() / kMacroBlockSize; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int bottom = (rect.bottom() - 1) / kMacroBlockSize; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(right, active_map_width_); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(bottom, active_map_height_); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* map = active_map_.get() + top * active_map_width_; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int y = top; y <= bottom; ++y) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int x = left; x <= right; ++x) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map[x] = 1; 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map += active_map_width_; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace remoting 454