Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: remoting/codec/video_decoder_vpx.cc

Issue 1236663002: Allow shaped-desktop hosts to send shape only when it changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix Pepper 2D renderer build Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « remoting/codec/video_decoder_vpx.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/codec/video_decoder_vpx.h" 5 #include "remoting/codec/video_decoder_vpx.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "media/base/media.h" 12 #include "media/base/media.h"
13 #include "media/base/yuv_convert.h" 13 #include "media/base/yuv_convert.h"
14 #include "remoting/base/util.h" 14 #include "remoting/base/util.h"
15 #include "third_party/libyuv/include/libyuv/convert_argb.h" 15 #include "third_party/libyuv/include/libyuv/convert_argb.h"
16 16
17 extern "C" { 17 extern "C" {
18 #define VPX_CODEC_DISABLE_COMPAT 1 18 #define VPX_CODEC_DISABLE_COMPAT 1
19 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" 19 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h"
20 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" 20 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h"
21 } 21 }
22 22
23 namespace remoting { 23 namespace remoting {
24 24
25 namespace {
26
27 const uint32 kTransparentColor = 0;
28
29 // Fills the rectangle |rect| with the given ARGB color |color| in |buffer|.
30 void FillRect(uint8* buffer,
31 int stride,
32 const webrtc::DesktopRect& rect,
33 uint32 color) {
34 uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) +
35 (rect.left() * VideoDecoder::kBytesPerPixel));
36 int width = rect.width();
37 for (int height = rect.height(); height > 0; --height) {
38 std::fill(ptr, ptr + width, color);
39 ptr += stride / VideoDecoder::kBytesPerPixel;
40 }
41 }
42
43 } // namespace
44
45 // static 25 // static
46 scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() { 26 scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP8() {
47 ScopedVpxCodec codec(new vpx_codec_ctx_t); 27 return make_scoped_ptr(new VideoDecoderVpx(vpx_codec_vp8_dx()));
48
49 // TODO(hclam): Scale the number of threads with number of cores of the
50 // machine.
51 vpx_codec_dec_cfg config;
52 config.w = 0;
53 config.h = 0;
54 config.threads = 2;
55 vpx_codec_err_t ret =
56 vpx_codec_dec_init(codec.get(), vpx_codec_vp8_dx(), &config, 0);
57 if (ret != VPX_CODEC_OK) {
58 LOG(ERROR) << "Cannot initialize codec.";
59 return nullptr;
60 }
61
62 return make_scoped_ptr(new VideoDecoderVpx(codec.Pass()));
63 } 28 }
64 29
65 // static 30 // static
66 scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() { 31 scoped_ptr<VideoDecoderVpx> VideoDecoderVpx::CreateForVP9() {
67 ScopedVpxCodec codec(new vpx_codec_ctx_t); 32 return make_scoped_ptr(new VideoDecoderVpx(vpx_codec_vp9_dx()));
68
69 // TODO(hclam): Scale the number of threads with number of cores of the
70 // machine.
71 vpx_codec_dec_cfg config;
72 config.w = 0;
73 config.h = 0;
74 config.threads = 2;
75 vpx_codec_err_t ret =
76 vpx_codec_dec_init(codec.get(), vpx_codec_vp9_dx(), &config, 0);
77 if (ret != VPX_CODEC_OK) {
78 LOG(ERROR) << "Cannot initialize codec.";
79 return nullptr;
80 }
81
82 return make_scoped_ptr(new VideoDecoderVpx(codec.Pass()));
83 } 33 }
84 34
85 VideoDecoderVpx::~VideoDecoderVpx() {} 35 VideoDecoderVpx::~VideoDecoderVpx() {}
86 36
87 void VideoDecoderVpx::Initialize(const webrtc::DesktopSize& screen_size) { 37 void VideoDecoderVpx::Initialize(const webrtc::DesktopSize& source_size) {
88 DCHECK(!screen_size.is_empty()); 38 // Nothing to do here; the codec handles resizing internally, and returns
89 39 // the source dimensions as part of the vpx_image_t.
90 screen_size_ = screen_size;
91
92 transparent_region_.SetRect(webrtc::DesktopRect::MakeSize(screen_size_));
93 } 40 }
94 41
95 bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet) { 42 bool VideoDecoderVpx::DecodePacket(const VideoPacket& packet) {
96 DCHECK(!screen_size_.is_empty()); 43 // Pass the packet to the codec to process.
97
98 // Do the actual decoding.
99 vpx_codec_err_t ret = vpx_codec_decode( 44 vpx_codec_err_t ret = vpx_codec_decode(
100 codec_.get(), reinterpret_cast<const uint8*>(packet.data().data()), 45 codec_.get(), reinterpret_cast<const uint8*>(packet.data().data()),
101 packet.data().size(), nullptr, 0); 46 packet.data().size(), nullptr, 0);
102 if (ret != VPX_CODEC_OK) { 47 if (ret != VPX_CODEC_OK) {
103 const char* error = vpx_codec_error(codec_.get()); 48 const char* error = vpx_codec_error(codec_.get());
104 const char* error_detail = vpx_codec_error_detail(codec_.get()); 49 const char* error_detail = vpx_codec_error_detail(codec_.get());
105 LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n" 50 LOG(ERROR) << "Decoding failed:" << (error ? error : "(NULL)") << "\n"
106 << "Details: " << (error_detail ? error_detail : "(NULL)"); 51 << "Details: " << (error_detail ? error_detail : "(NULL)");
107 return false; 52 return false;
108 } 53 }
109 54
110 // Gets the decoded data. 55 // Fetch the decoded video frame.
111 vpx_codec_iter_t iter = nullptr; 56 vpx_codec_iter_t iter = nullptr;
112 vpx_image_t* image = vpx_codec_get_frame(codec_.get(), &iter); 57 image_ = vpx_codec_get_frame(codec_.get(), &iter);
113 if (!image) { 58 if (!image_) {
114 LOG(ERROR) << "No video frame decoded"; 59 LOG(ERROR) << "No video frame decoded";
115 return false; 60 return false;
116 } 61 }
117 last_image_ = image; 62 DCHECK(!image_size().is_empty());
118 63
64 // Determine which areas have been updated.
119 webrtc::DesktopRegion region; 65 webrtc::DesktopRegion region;
120 for (int i = 0; i < packet.dirty_rects_size(); ++i) { 66 for (int i = 0; i < packet.dirty_rects_size(); ++i) {
121 Rect remoting_rect = packet.dirty_rects(i); 67 Rect remoting_rect = packet.dirty_rects(i);
122 region.AddRect(webrtc::DesktopRect::MakeXYWH( 68 region.AddRect(webrtc::DesktopRect::MakeXYWH(
123 remoting_rect.x(), remoting_rect.y(), 69 remoting_rect.x(), remoting_rect.y(),
124 remoting_rect.width(), remoting_rect.height())); 70 remoting_rect.width(), remoting_rect.height()));
125 } 71 }
126
127 updated_region_.AddRegion(region); 72 updated_region_.AddRegion(region);
128 73
129 // Update the desktop shape region. 74 // Process the frame shape, if supplied.
130 webrtc::DesktopRegion desktop_shape_region;
131 if (packet.has_use_desktop_shape()) { 75 if (packet.has_use_desktop_shape()) {
132 for (int i = 0; i < packet.desktop_shape_rects_size(); ++i) { 76 if (packet.use_desktop_shape()) {
133 Rect remoting_rect = packet.desktop_shape_rects(i); 77 if (!desktop_shape_)
134 desktop_shape_region.AddRect(webrtc::DesktopRect::MakeXYWH( 78 desktop_shape_ = make_scoped_ptr(new webrtc::DesktopRegion);
135 remoting_rect.x(), remoting_rect.y(), 79 desktop_shape_->Clear();
136 remoting_rect.width(), remoting_rect.height())); 80 for (int i = 0; i < packet.desktop_shape_rects_size(); ++i) {
81 Rect remoting_rect = packet.desktop_shape_rects(i);
82 desktop_shape_->AddRect(webrtc::DesktopRect::MakeXYWH(
83 remoting_rect.x(), remoting_rect.y(), remoting_rect.width(),
84 remoting_rect.height()));
85 }
86 } else {
87 desktop_shape_.reset();
137 } 88 }
138 } else {
139 // Fallback for the case when the host didn't include the desktop shape
140 // region.
141 desktop_shape_region =
142 webrtc::DesktopRegion(webrtc::DesktopRect::MakeSize(screen_size_));
143 } 89 }
144 90
145 UpdateImageShapeRegion(&desktop_shape_region);
146
147 return true; 91 return true;
148 } 92 }
149 93
150 void VideoDecoderVpx::Invalidate(const webrtc::DesktopSize& view_size, 94 void VideoDecoderVpx::Invalidate(const webrtc::DesktopSize& view_size,
151 const webrtc::DesktopRegion& region) { 95 const webrtc::DesktopRegion& region) {
152 DCHECK(!view_size.is_empty()); 96 DCHECK(!view_size.is_empty());
153 97
154 for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { 98 for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
155 updated_region_.AddRect(ScaleRect(i.rect(), view_size, screen_size_)); 99 updated_region_.AddRect(ScaleRect(i.rect(), view_size, image_size()));
156 } 100 }
157
158 // Updated areas outside of the new desktop shape region should be made
159 // transparent, not repainted.
160 webrtc::DesktopRegion difference = updated_region_;
161 difference.Subtract(desktop_shape_);
162 updated_region_.Subtract(difference);
163 transparent_region_.AddRegion(difference);
164 } 101 }
165 102
166 void VideoDecoderVpx::RenderFrame(const webrtc::DesktopSize& view_size, 103 void VideoDecoderVpx::RenderFrame(const webrtc::DesktopSize& view_size,
167 const webrtc::DesktopRect& clip_area, 104 const webrtc::DesktopRect& clip_area,
168 uint8* image_buffer, 105 uint8* image_buffer,
169 int image_stride, 106 int image_stride,
170 webrtc::DesktopRegion* output_region) { 107 webrtc::DesktopRegion* output_region) {
171 DCHECK(!screen_size_.is_empty()); 108 DCHECK(!image_size().is_empty());
172 DCHECK(!view_size.is_empty()); 109 DCHECK(!view_size.is_empty());
173 110
174 // Early-return and do nothing if we haven't yet decoded any frames. 111 // Early-return and do nothing if we haven't yet decoded any frames.
175 if (!last_image_) 112 if (!image_)
176 return; 113 return;
177 114
178 webrtc::DesktopRect source_clip = 115 webrtc::DesktopRect source_clip = webrtc::DesktopRect::MakeSize(image_size());
179 webrtc::DesktopRect::MakeWH(last_image_->d_w, last_image_->d_h);
180 116
181 // VP8 only outputs I420 frames, but VP9 can also produce I444. 117 // VP8 only outputs I420 frames, but VP9 can also produce I444.
182 switch (last_image_->fmt) { 118 switch (image_->fmt) {
183 case VPX_IMG_FMT_I444: { 119 case VPX_IMG_FMT_I444: {
184 // TODO(wez): Add scaling support to the I444 conversion path. 120 // TODO(wez): Add scaling support to the I444 conversion path.
185 if (view_size.equals(screen_size_)) { 121 if (view_size.equals(image_size())) {
186 for (webrtc::DesktopRegion::Iterator i(updated_region_); 122 for (webrtc::DesktopRegion::Iterator i(updated_region_);
187 !i.IsAtEnd(); i.Advance()) { 123 !i.IsAtEnd(); i.Advance()) {
188 // Determine the scaled area affected by this rectangle changing. 124 // Determine the scaled area affected by this rectangle changing.
189 webrtc::DesktopRect rect = i.rect(); 125 webrtc::DesktopRect rect = i.rect();
190 rect.IntersectWith(source_clip); 126 rect.IntersectWith(source_clip);
191 rect.IntersectWith(clip_area); 127 rect.IntersectWith(clip_area);
192 if (rect.is_empty()) 128 if (rect.is_empty())
193 continue; 129 continue;
194 130
195 int image_offset = image_stride * rect.top() + 131 int image_offset = image_stride * rect.top() +
196 rect.left() * VideoDecoder::kBytesPerPixel; 132 rect.left() * VideoDecoder::kBytesPerPixel;
197 int y_offset = last_image_->stride[0] * rect.top() + rect.left(); 133 int y_offset = image_->stride[0] * rect.top() + rect.left();
198 int u_offset = last_image_->stride[1] * rect.top() + rect.left(); 134 int u_offset = image_->stride[1] * rect.top() + rect.left();
199 int v_offset = last_image_->stride[2] * rect.top() + rect.left(); 135 int v_offset = image_->stride[2] * rect.top() + rect.left();
200 libyuv::I444ToARGB(last_image_->planes[0] + y_offset, 136 libyuv::I444ToARGB(image_->planes[0] + y_offset, image_->stride[0],
201 last_image_->stride[0], 137 image_->planes[1] + u_offset, image_->stride[1],
202 last_image_->planes[1] + u_offset, 138 image_->planes[2] + v_offset, image_->stride[2],
203 last_image_->stride[1],
204 last_image_->planes[2] + v_offset,
205 last_image_->stride[2],
206 image_buffer + image_offset, image_stride, 139 image_buffer + image_offset, image_stride,
207 rect.width(), rect.height()); 140 rect.width(), rect.height());
208 141
209 output_region->AddRect(rect); 142 output_region->AddRect(rect);
210 } 143 }
211 } 144 }
212 break; 145 break;
213 } 146 }
214 case VPX_IMG_FMT_I420: { 147 case VPX_IMG_FMT_I420: {
215 // ScaleYUVToRGB32WithRect does not currently support up-scaling. We 148 // ScaleYUVToRGB32WithRect does not currently support up-scaling. We
216 // won't be asked to up-scale except during resizes or if page zoom is 149 // won't be asked to up-scale except during resizes or if page zoom is
217 // >100%, so we work-around the limitation by using the slower 150 // >100%, so we work-around the limitation by using the slower
218 // ScaleYUVToRGB32. 151 // ScaleYUVToRGB32.
219 // TODO(wez): Remove this hack if/when ScaleYUVToRGB32WithRect can 152 // TODO(wez): Remove this hack if/when ScaleYUVToRGB32WithRect can
220 // up-scale. 153 // up-scale.
221 if (!updated_region_.is_empty() && 154 if (!updated_region_.is_empty() &&
222 (source_clip.width() < view_size.width() || 155 (source_clip.width() < view_size.width() ||
223 source_clip.height() < view_size.height())) { 156 source_clip.height() < view_size.height())) {
224 // We're scaling only |clip_area| into the |image_buffer|, so we need to 157 // We're scaling only |clip_area| into the |image_buffer|, so we need to
225 // work out which source rectangle that corresponds to. 158 // work out which source rectangle that corresponds to.
226 webrtc::DesktopRect source_rect = 159 webrtc::DesktopRect source_rect =
227 ScaleRect(clip_area, view_size, screen_size_); 160 ScaleRect(clip_area, view_size, image_size());
228 source_rect = webrtc::DesktopRect::MakeLTRB( 161 source_rect = webrtc::DesktopRect::MakeLTRB(
229 RoundToTwosMultiple(source_rect.left()), 162 RoundToTwosMultiple(source_rect.left()),
230 RoundToTwosMultiple(source_rect.top()), 163 RoundToTwosMultiple(source_rect.top()),
231 source_rect.right(), 164 source_rect.right(),
232 source_rect.bottom()); 165 source_rect.bottom());
233 166
234 // If there were no changes within the clip source area then don't 167 // If there were no changes within the clip source area then don't
235 // render. 168 // render.
236 webrtc::DesktopRegion intersection(source_rect); 169 webrtc::DesktopRegion intersection(source_rect);
237 intersection.IntersectWith(updated_region_); 170 intersection.IntersectWith(updated_region_);
238 if (intersection.is_empty()) 171 if (intersection.is_empty())
239 return; 172 return;
240 173
241 // Scale & convert the entire clip area. 174 // Scale & convert the entire clip area.
242 int y_offset = CalculateYOffset(source_rect.left(), source_rect.top(), 175 int y_offset = CalculateYOffset(source_rect.left(), source_rect.top(),
243 last_image_->stride[0]); 176 image_->stride[0]);
244 int uv_offset = CalculateUVOffset(source_rect.left(), source_rect.top(), 177 int uv_offset = CalculateUVOffset(source_rect.left(), source_rect.top(),
245 last_image_->stride[1]); 178 image_->stride[1]);
246 ScaleYUVToRGB32(last_image_->planes[0] + y_offset, 179 ScaleYUVToRGB32(
247 last_image_->planes[1] + uv_offset, 180 image_->planes[0] + y_offset, image_->planes[1] + uv_offset,
248 last_image_->planes[2] + uv_offset, 181 image_->planes[2] + uv_offset, image_buffer, source_rect.width(),
249 image_buffer, 182 source_rect.height(), clip_area.width(), clip_area.height(),
250 source_rect.width(), 183 image_->stride[0], image_->stride[1], image_stride, media::YV12,
251 source_rect.height(), 184 media::ROTATE_0, media::FILTER_BILINEAR);
252 clip_area.width(),
253 clip_area.height(),
254 last_image_->stride[0],
255 last_image_->stride[1],
256 image_stride,
257 media::YV12,
258 media::ROTATE_0,
259 media::FILTER_BILINEAR);
260 185
261 output_region->AddRect(clip_area); 186 output_region->AddRect(clip_area);
262 updated_region_.Subtract(source_rect); 187 updated_region_.Subtract(source_rect);
263 return; 188 return;
264 } 189 }
265 190
266 for (webrtc::DesktopRegion::Iterator i(updated_region_); 191 for (webrtc::DesktopRegion::Iterator i(updated_region_);
267 !i.IsAtEnd(); i.Advance()) { 192 !i.IsAtEnd(); i.Advance()) {
268 // Determine the scaled area affected by this rectangle changing. 193 // Determine the scaled area affected by this rectangle changing.
269 webrtc::DesktopRect rect = i.rect(); 194 webrtc::DesktopRect rect = i.rect();
270 rect.IntersectWith(source_clip); 195 rect.IntersectWith(source_clip);
271 if (rect.is_empty()) 196 if (rect.is_empty())
272 continue; 197 continue;
273 rect = ScaleRect(rect, screen_size_, view_size); 198 rect = ScaleRect(rect, image_size(), view_size);
274 rect.IntersectWith(clip_area); 199 rect.IntersectWith(clip_area);
275 if (rect.is_empty()) 200 if (rect.is_empty())
276 continue; 201 continue;
277 202
278 ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], 203 ConvertAndScaleYUVToRGB32Rect(
279 last_image_->planes[1], 204 image_->planes[0], image_->planes[1], image_->planes[2],
280 last_image_->planes[2], 205 image_->stride[0], image_->stride[1], image_size(), source_clip,
281 last_image_->stride[0], 206 image_buffer, image_stride, view_size, clip_area, rect);
282 last_image_->stride[1],
283 screen_size_,
284 source_clip,
285 image_buffer,
286 image_stride,
287 view_size,
288 clip_area,
289 rect);
290 207
291 output_region->AddRect(rect); 208 output_region->AddRect(rect);
292 } 209 }
293 210
294 updated_region_.Subtract(ScaleRect(clip_area, view_size, screen_size_)); 211 updated_region_.Subtract(ScaleRect(clip_area, view_size, image_size()));
295 break; 212 break;
296 } 213 }
297 default: { 214 default: {
298 LOG(ERROR) << "Unsupported image format:" << last_image_->fmt; 215 LOG(ERROR) << "Unsupported image format:" << image_->fmt;
299 return; 216 return;
300 } 217 }
301 } 218 }
302 219
303 for (webrtc::DesktopRegion::Iterator i(transparent_region_);
304 !i.IsAtEnd(); i.Advance()) {
305 // Determine the scaled area affected by this rectangle changing.
306 webrtc::DesktopRect rect = i.rect();
307 rect.IntersectWith(source_clip);
308 if (rect.is_empty())
309 continue;
310 rect = ScaleRect(rect, screen_size_, view_size);
311 rect.IntersectWith(clip_area);
312 if (rect.is_empty())
313 continue;
314
315 // Fill the rectange with transparent pixels.
316 FillRect(image_buffer, image_stride, rect, kTransparentColor);
317 output_region->AddRect(rect);
318 }
319
320 webrtc::DesktopRect scaled_clip_area = 220 webrtc::DesktopRect scaled_clip_area =
321 ScaleRect(clip_area, view_size, screen_size_); 221 ScaleRect(clip_area, view_size, image_size());
322 updated_region_.Subtract(scaled_clip_area); 222 updated_region_.Subtract(scaled_clip_area);
323 transparent_region_.Subtract(scaled_clip_area);
324 } 223 }
325 224
326 const webrtc::DesktopRegion* VideoDecoderVpx::GetImageShape() { 225 const webrtc::DesktopRegion* VideoDecoderVpx::GetImageShape() {
327 return &desktop_shape_; 226 return desktop_shape_.get();
328 } 227 }
329 228
330 VideoDecoderVpx::VideoDecoderVpx(ScopedVpxCodec codec) 229 VideoDecoderVpx::VideoDecoderVpx(vpx_codec_iface_t* codec) : image_(nullptr) {
331 : codec_(codec.Pass()), 230 codec_.reset(new vpx_codec_ctx_t);
332 last_image_(nullptr) { 231
333 DCHECK(codec_); 232 vpx_codec_dec_cfg config;
233 config.w = 0;
234 config.h = 0;
235 config.threads = 2;
236 vpx_codec_err_t ret = vpx_codec_dec_init(codec_.get(), codec, &config, 0);
237 CHECK_EQ(VPX_CODEC_OK, ret);
334 } 238 }
335 239
336 void VideoDecoderVpx::UpdateImageShapeRegion( 240 webrtc::DesktopSize VideoDecoderVpx::image_size() const {
337 webrtc::DesktopRegion* new_desktop_shape) { 241 return image_ ? webrtc::DesktopSize(image_->d_w, image_->d_h)
338 // Add all areas that have been updated or become transparent to the 242 : webrtc::DesktopSize();
339 // transparent region. Exclude anything within the new desktop shape.
340 transparent_region_.AddRegion(desktop_shape_);
341 transparent_region_.AddRegion(updated_region_);
342 transparent_region_.Subtract(*new_desktop_shape);
343
344 // Add newly exposed areas to the update region and limit updates to the new
345 // desktop shape.
346 webrtc::DesktopRegion difference = *new_desktop_shape;
347 difference.Subtract(desktop_shape_);
348 updated_region_.AddRegion(difference);
349 updated_region_.IntersectWith(*new_desktop_shape);
350
351 // Set the new desktop shape region.
352 desktop_shape_.Swap(new_desktop_shape);
353 } 243 }
354 244
355 } // namespace remoting 245 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/codec/video_decoder_vpx.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698