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

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

Issue 23440046: Remove dependency on Skia from chromoting client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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_vp8.h" 5 #include "remoting/codec/video_decoder_vp8.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
(...skipping 10 matching lines...) Expand all
21 21
22 namespace remoting { 22 namespace remoting {
23 23
24 enum { kBytesPerPixelRGB32 = 4 }; 24 enum { kBytesPerPixelRGB32 = 4 };
25 25
26 const uint32 kTransparent = 0; 26 const uint32 kTransparent = 0;
27 27
28 VideoDecoderVp8::VideoDecoderVp8() 28 VideoDecoderVp8::VideoDecoderVp8()
29 : state_(kUninitialized), 29 : state_(kUninitialized),
30 codec_(NULL), 30 codec_(NULL),
31 last_image_(NULL), 31 last_image_(NULL) {
32 screen_size_(SkISize::Make(0, 0)) {
33 } 32 }
34 33
35 VideoDecoderVp8::~VideoDecoderVp8() { 34 VideoDecoderVp8::~VideoDecoderVp8() {
36 if (codec_) { 35 if (codec_) {
37 vpx_codec_err_t ret = vpx_codec_destroy(codec_); 36 vpx_codec_err_t ret = vpx_codec_destroy(codec_);
38 CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; 37 CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec";
39 } 38 }
40 delete codec_; 39 delete codec_;
41 } 40 }
42 41
43 void VideoDecoderVp8::Initialize(const SkISize& screen_size) { 42 void VideoDecoderVp8::Initialize(const webrtc::DesktopSize& screen_size) {
44 DCHECK(!screen_size.isEmpty()); 43 DCHECK(!screen_size.is_empty());
45 44
46 screen_size_ = screen_size; 45 screen_size_ = screen_size;
47 state_ = kReady; 46 state_ = kReady;
48 47
49 transparent_region_.setRect(SkIRect::MakeSize(screen_size_)); 48 transparent_region_.SetRect(webrtc::DesktopRect::MakeSize(screen_size_));
50 } 49 }
51 50
52 VideoDecoder::DecodeResult VideoDecoderVp8::DecodePacket( 51 VideoDecoder::DecodeResult VideoDecoderVp8::DecodePacket(
53 const VideoPacket* packet) { 52 const VideoPacket* packet) {
54 DCHECK_EQ(kReady, state_); 53 DCHECK_EQ(kReady, state_);
55 54
56 // Initialize the codec as needed. 55 // Initialize the codec as needed.
57 if (!codec_) { 56 if (!codec_) {
58 codec_ = new vpx_codec_ctx_t(); 57 codec_ = new vpx_codec_ctx_t();
59 58
60 // TODO(hclam): Scale the number of threads with number of cores of the 59 // TODO(hclam): Scale the number of threads with number of cores of the
61 // machine. 60 // machine.
62 vpx_codec_dec_cfg config; 61 vpx_codec_dec_cfg config;
63 config.w = 0; 62 config.w = 0;
64 config.h = 0; 63 config.h = 0;
65 config.threads = 2; 64 config.threads = 2;
66 vpx_codec_err_t ret = 65 vpx_codec_err_t ret =
67 vpx_codec_dec_init( 66 vpx_codec_dec_init(codec_, vpx_codec_vp8_dx(), &config, 0);
68 codec_, vpx_codec_vp8_dx(), &config, 0);
69 if (ret != VPX_CODEC_OK) { 67 if (ret != VPX_CODEC_OK) {
70 LOG(INFO) << "Cannot initialize codec."; 68 LOG(INFO) << "Cannot initialize codec.";
71 delete codec_; 69 delete codec_;
72 codec_ = NULL; 70 codec_ = NULL;
73 state_ = kError; 71 state_ = kError;
74 return DECODE_ERROR; 72 return DECODE_ERROR;
75 } 73 }
76 } 74 }
77 75
78 // Do the actual decoding. 76 // Do the actual decoding.
79 vpx_codec_err_t ret = vpx_codec_decode( 77 vpx_codec_err_t ret = vpx_codec_decode(
80 codec_, reinterpret_cast<const uint8*>(packet->data().data()), 78 codec_, reinterpret_cast<const uint8*>(packet->data().data()),
81 packet->data().size(), NULL, 0); 79 packet->data().size(), NULL, 0);
82 if (ret != VPX_CODEC_OK) { 80 if (ret != VPX_CODEC_OK) {
83 LOG(INFO) << "Decoding failed:" << vpx_codec_err_to_string(ret) << "\n" 81 LOG(INFO) << "Decoding failed:" << vpx_codec_err_to_string(ret) << "\n"
84 << "Details: " << vpx_codec_error(codec_) << "\n" 82 << "Details: " << vpx_codec_error(codec_) << "\n"
85 << vpx_codec_error_detail(codec_); 83 << vpx_codec_error_detail(codec_);
86 return DECODE_ERROR; 84 return DECODE_ERROR;
87 } 85 }
88 86
89 // Gets the decoded data. 87 // Gets the decoded data.
90 vpx_codec_iter_t iter = NULL; 88 vpx_codec_iter_t iter = NULL;
91 vpx_image_t* image = vpx_codec_get_frame(codec_, &iter); 89 vpx_image_t* image = vpx_codec_get_frame(codec_, &iter);
92 if (!image) { 90 if (!image) {
93 LOG(INFO) << "No video frame decoded"; 91 LOG(INFO) << "No video frame decoded";
94 return DECODE_ERROR; 92 return DECODE_ERROR;
95 } 93 }
96 last_image_ = image; 94 last_image_ = image;
97 95
98 SkRegion region; 96 webrtc::DesktopRegion region;
99 for (int i = 0; i < packet->dirty_rects_size(); ++i) { 97 for (int i = 0; i < packet->dirty_rects_size(); ++i) {
100 Rect remoting_rect = packet->dirty_rects(i); 98 Rect remoting_rect = packet->dirty_rects(i);
101 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), 99 region.AddRect(webrtc::DesktopRect::MakeXYWH(
102 remoting_rect.y(), 100 remoting_rect.x(), remoting_rect.y(),
103 remoting_rect.width(), 101 remoting_rect.width(), remoting_rect.height()));
104 remoting_rect.height());
105 region.op(rect, SkRegion::kUnion_Op);
106 } 102 }
107 103
108 updated_region_.op(region, SkRegion::kUnion_Op); 104 updated_region_.AddRegion(region);
109 105
110 // Update the desktop shape region. 106 // Update the desktop shape region.
111 SkRegion desktop_shape_region; 107 webrtc::DesktopRegion desktop_shape_region;
112 if (packet->has_use_desktop_shape()) { 108 if (packet->has_use_desktop_shape()) {
113 for (int i = 0; i < packet->desktop_shape_rects_size(); ++i) { 109 for (int i = 0; i < packet->desktop_shape_rects_size(); ++i) {
114 Rect remoting_rect = packet->desktop_shape_rects(i); 110 Rect remoting_rect = packet->desktop_shape_rects(i);
115 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), 111 desktop_shape_region.AddRect(webrtc::DesktopRect::MakeXYWH(
116 remoting_rect.y(), 112 remoting_rect.x(), remoting_rect.y(),
117 remoting_rect.width(), 113 remoting_rect.width(), remoting_rect.height()));
118 remoting_rect.height());
119 desktop_shape_region.op(rect, SkRegion::kUnion_Op);
120 } 114 }
121 } else { 115 } else {
122 // Fallback for the case when the host didn't include the desktop shape 116 // Fallback for the case when the host didn't include the desktop shape
123 // region. 117 // region.
124 desktop_shape_region = SkRegion(SkIRect::MakeSize(screen_size_)); 118 desktop_shape_region =
119 webrtc::DesktopRegion(webrtc::DesktopRect::MakeSize(screen_size_));
125 } 120 }
126 121
127 UpdateImageShapeRegion(&desktop_shape_region); 122 UpdateImageShapeRegion(&desktop_shape_region);
128 123
129 return DECODE_DONE; 124 return DECODE_DONE;
130 } 125 }
131 126
132 bool VideoDecoderVp8::IsReadyForData() { 127 bool VideoDecoderVp8::IsReadyForData() {
alexeypa (please no reviews) 2013/09/18 23:04:05 nit: Move this method above VideoDecoderVp8::Initi
Sergey Ulanov 2013/09/18 23:26:58 Done.
133 return state_ == kReady; 128 return state_ == kReady;
134 } 129 }
135 130
136 VideoPacketFormat::Encoding VideoDecoderVp8::Encoding() { 131 VideoPacketFormat::Encoding VideoDecoderVp8::Encoding() {
137 return VideoPacketFormat::ENCODING_VP8; 132 return VideoPacketFormat::ENCODING_VP8;
138 } 133 }
139 134
140 void VideoDecoderVp8::Invalidate(const SkISize& view_size, 135 void VideoDecoderVp8::Invalidate(const webrtc::DesktopSize& view_size,
141 const SkRegion& region) { 136 const webrtc::DesktopRegion& region) {
142 DCHECK_EQ(kReady, state_); 137 DCHECK_EQ(kReady, state_);
143 DCHECK(!view_size.isEmpty()); 138 DCHECK(!view_size.is_empty());
144 139
145 for (SkRegion::Iterator i(region); !i.done(); i.next()) { 140 for (webrtc::DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
146 SkIRect rect = i.rect(); 141 updated_region_.AddRect(ScaleRect(i.rect(), view_size, screen_size_));
147 rect = ScaleRect(rect, view_size, screen_size_);
148 updated_region_.op(rect, SkRegion::kUnion_Op);
149 } 142 }
150 143
151 // Updated areas outside of the new desktop shape region should be made 144 // Updated areas outside of the new desktop shape region should be made
152 // transparent, not repainted. 145 // transparent, not repainted.
153 SkRegion difference = updated_region_; 146 webrtc::DesktopRegion difference = updated_region_;
154 difference.op(desktop_shape_, SkRegion::kDifference_Op); 147 difference.Subtract(desktop_shape_);
155 updated_region_.op(difference, SkRegion::kDifference_Op); 148 updated_region_.Subtract(difference);
156 transparent_region_.op(difference, SkRegion::kUnion_Op); 149 transparent_region_.AddRegion(difference);
157 } 150 }
158 151
159 void VideoDecoderVp8::RenderFrame(const SkISize& view_size, 152 void VideoDecoderVp8::RenderFrame(const webrtc::DesktopSize& view_size,
160 const SkIRect& clip_area, 153 const webrtc::DesktopRect& clip_area,
161 uint8* image_buffer, 154 uint8* image_buffer,
162 int image_stride, 155 int image_stride,
163 SkRegion* output_region) { 156 webrtc::DesktopRegion* output_region) {
164 DCHECK_EQ(kReady, state_); 157 DCHECK_EQ(kReady, state_);
165 DCHECK(!view_size.isEmpty()); 158 DCHECK(!view_size.is_empty());
166 159
167 // Early-return and do nothing if we haven't yet decoded any frames. 160 // Early-return and do nothing if we haven't yet decoded any frames.
168 if (!last_image_) 161 if (!last_image_)
169 return; 162 return;
170 163
171 SkIRect source_clip = SkIRect::MakeWH(last_image_->d_w, last_image_->d_h); 164 webrtc::DesktopRect source_clip =
165 webrtc::DesktopRect::MakeWH(last_image_->d_w, last_image_->d_h);
172 166
173 // ScaleYUVToRGB32WithRect does not currently support up-scaling. We won't 167 // ScaleYUVToRGB32WithRect does not currently support up-scaling. We won't
174 // be asked to up-scale except during resizes or if page zoom is >100%, so 168 // be asked to up-scale except during resizes or if page zoom is >100%, so
175 // we work-around the limitation by using the slower ScaleYUVToRGB32. 169 // we work-around the limitation by using the slower ScaleYUVToRGB32.
176 // TODO(wez): Remove this hack if/when ScaleYUVToRGB32WithRect can up-scale. 170 // TODO(wez): Remove this hack if/when ScaleYUVToRGB32WithRect can up-scale.
177 if (!updated_region_.isEmpty() && 171 if (!updated_region_.is_empty() &&
178 (source_clip.width() < view_size.width() || 172 (source_clip.width() < view_size.width() ||
179 source_clip.height() < view_size.height())) { 173 source_clip.height() < view_size.height())) {
180 // We're scaling only |clip_area| into the |image_buffer|, so we need to 174 // We're scaling only |clip_area| into the |image_buffer|, so we need to
181 // work out which source rectangle that corresponds to. 175 // work out which source rectangle that corresponds to.
182 SkIRect source_rect = ScaleRect(clip_area, view_size, screen_size_); 176 webrtc::DesktopRect source_rect =
183 source_rect = SkIRect::MakeLTRB(RoundToTwosMultiple(source_rect.left()), 177 ScaleRect(clip_area, view_size, screen_size_);
184 RoundToTwosMultiple(source_rect.top()), 178 source_rect = webrtc::DesktopRect::MakeLTRB(
185 source_rect.right(), 179 RoundToTwosMultiple(source_rect.left()),
186 source_rect.bottom()); 180 RoundToTwosMultiple(source_rect.top()),
181 source_rect.right(),
182 source_rect.bottom());
187 183
188 // If there were no changes within the clip source area then don't render. 184 // If there were no changes within the clip source area then don't render.
189 if (!updated_region_.intersects(source_rect)) 185 webrtc::DesktopRegion intersection(source_rect);
186 intersection.IntersectWith(updated_region_);
187 if (intersection.is_empty())
190 return; 188 return;
191 189
192 // Scale & convert the entire clip area. 190 // Scale & convert the entire clip area.
193 int y_offset = CalculateYOffset(source_rect.x(), 191 int y_offset = CalculateYOffset(source_rect.left(), source_rect.top(),
194 source_rect.y(),
195 last_image_->stride[0]); 192 last_image_->stride[0]);
196 int uv_offset = CalculateUVOffset(source_rect.x(), 193 int uv_offset = CalculateUVOffset(source_rect.left(), source_rect.top(),
197 source_rect.y(),
198 last_image_->stride[1]); 194 last_image_->stride[1]);
199 ScaleYUVToRGB32(last_image_->planes[0] + y_offset, 195 ScaleYUVToRGB32(last_image_->planes[0] + y_offset,
200 last_image_->planes[1] + uv_offset, 196 last_image_->planes[1] + uv_offset,
201 last_image_->planes[2] + uv_offset, 197 last_image_->planes[2] + uv_offset,
202 image_buffer, 198 image_buffer,
203 source_rect.width(), 199 source_rect.width(),
204 source_rect.height(), 200 source_rect.height(),
205 clip_area.width(), 201 clip_area.width(),
206 clip_area.height(), 202 clip_area.height(),
207 last_image_->stride[0], 203 last_image_->stride[0],
208 last_image_->stride[1], 204 last_image_->stride[1],
209 image_stride, 205 image_stride,
210 media::YV12, 206 media::YV12,
211 media::ROTATE_0, 207 media::ROTATE_0,
212 media::FILTER_BILINEAR); 208 media::FILTER_BILINEAR);
213 209
214 output_region->op(clip_area, SkRegion::kUnion_Op); 210 output_region->AddRect(clip_area);
215 updated_region_.op(source_rect, SkRegion::kDifference_Op); 211 updated_region_.Subtract(source_rect);
216 return; 212 return;
217 } 213 }
218 214
219 for (SkRegion::Iterator i(updated_region_); !i.done(); i.next()) { 215 for (webrtc::DesktopRegion::Iterator i(updated_region_);
216 !i.IsAtEnd(); i.Advance()) {
220 // Determine the scaled area affected by this rectangle changing. 217 // Determine the scaled area affected by this rectangle changing.
221 SkIRect rect = i.rect(); 218 webrtc::DesktopRect rect = i.rect();
222 if (!rect.intersect(source_clip)) 219 rect.IntersectWith(source_clip);
220 if (rect.is_empty())
223 continue; 221 continue;
224 rect = ScaleRect(rect, screen_size_, view_size); 222 rect = ScaleRect(rect, screen_size_, view_size);
225 if (!rect.intersect(clip_area)) 223 rect.IntersectWith(clip_area);
224 if (rect.is_empty())
226 continue; 225 continue;
227 226
228 ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], 227 ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0],
229 last_image_->planes[1], 228 last_image_->planes[1],
230 last_image_->planes[2], 229 last_image_->planes[2],
231 last_image_->stride[0], 230 last_image_->stride[0],
232 last_image_->stride[1], 231 last_image_->stride[1],
233 screen_size_, 232 screen_size_,
234 source_clip, 233 source_clip,
235 image_buffer, 234 image_buffer,
236 image_stride, 235 image_stride,
237 view_size, 236 view_size,
238 clip_area, 237 clip_area,
239 rect); 238 rect);
240 239
241 output_region->op(rect, SkRegion::kUnion_Op); 240 output_region->AddRect(rect);
242 } 241 }
243 242
244 updated_region_.op(ScaleRect(clip_area, view_size, screen_size_), 243 updated_region_.Subtract(ScaleRect(clip_area, view_size, screen_size_));
245 SkRegion::kDifference_Op);
246 244
247 for (SkRegion::Iterator i(transparent_region_); !i.done(); i.next()) { 245 for (webrtc::DesktopRegion::Iterator i(transparent_region_);
246 !i.IsAtEnd(); i.Advance()) {
248 // Determine the scaled area affected by this rectangle changing. 247 // Determine the scaled area affected by this rectangle changing.
249 SkIRect rect = i.rect(); 248 webrtc::DesktopRect rect = i.rect();
250 if (!rect.intersect(source_clip)) 249 rect.IntersectWith(source_clip);
250 if (rect.is_empty())
251 continue; 251 continue;
252 rect = ScaleRect(rect, screen_size_, view_size); 252 rect = ScaleRect(rect, screen_size_, view_size);
253 if (!rect.intersect(clip_area)) 253 rect.IntersectWith(clip_area);
254 if (rect.is_empty())
254 continue; 255 continue;
255 256
256 // Fill the rectange with transparent pixels. 257 // Fill the rectange with transparent pixels.
257 FillRect(image_buffer, image_stride, rect, kTransparent); 258 FillRect(image_buffer, image_stride, rect, kTransparent);
258 output_region->op(rect, SkRegion::kUnion_Op); 259 output_region->AddRect(rect);
259 } 260 }
260 261
261 SkIRect scaled_clip_area = ScaleRect(clip_area, view_size, screen_size_); 262 webrtc::DesktopRect scaled_clip_area =
262 updated_region_.op(scaled_clip_area, SkRegion::kDifference_Op); 263 ScaleRect(clip_area, view_size, screen_size_);
263 transparent_region_.op(scaled_clip_area, SkRegion::kDifference_Op); 264 updated_region_.Subtract(scaled_clip_area);
265 transparent_region_.Subtract(scaled_clip_area);
264 } 266 }
265 267
266 const SkRegion* VideoDecoderVp8::GetImageShape() { 268 const webrtc::DesktopRegion* VideoDecoderVp8::GetImageShape() {
267 return &desktop_shape_; 269 return &desktop_shape_;
268 } 270 }
269 271
270 void VideoDecoderVp8::FillRect(uint8* buffer, 272 void VideoDecoderVp8::FillRect(uint8* buffer,
271 int stride, 273 int stride,
272 const SkIRect& rect, 274 const webrtc::DesktopRect& rect,
273 uint32 color) { 275 uint32 color) {
274 uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) + 276 uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) +
275 (rect.left() * kBytesPerPixelRGB32)); 277 (rect.left() * kBytesPerPixelRGB32));
276 int width = rect.width(); 278 int width = rect.width();
277 for (int height = rect.height(); height > 0; --height) { 279 for (int height = rect.height(); height > 0; --height) {
278 std::fill(ptr, ptr + width, color); 280 std::fill(ptr, ptr + width, color);
279 ptr += stride / kBytesPerPixelRGB32; 281 ptr += stride / kBytesPerPixelRGB32;
280 } 282 }
281 } 283 }
282 284
283 void VideoDecoderVp8::UpdateImageShapeRegion(SkRegion* new_desktop_shape) { 285 void VideoDecoderVp8::UpdateImageShapeRegion(
286 webrtc::DesktopRegion* new_desktop_shape) {
284 // Add all areas that have been updated or become transparent to the 287 // Add all areas that have been updated or become transparent to the
285 // transparent region. Exclude anything within the new desktop shape. 288 // transparent region. Exclude anything within the new desktop shape.
286 transparent_region_.op(desktop_shape_, SkRegion::kUnion_Op); 289 transparent_region_.AddRegion(desktop_shape_);
287 transparent_region_.op(updated_region_, SkRegion::kUnion_Op); 290 transparent_region_.AddRegion(updated_region_);
288 transparent_region_.op(*new_desktop_shape, SkRegion::kDifference_Op); 291 transparent_region_.Subtract(*new_desktop_shape);
289 292
290 // Add newly exposed areas to the update region and limit updates to the new 293 // Add newly exposed areas to the update region and limit updates to the new
291 // desktop shape. 294 // desktop shape.
292 SkRegion difference = *new_desktop_shape; 295 webrtc::DesktopRegion difference = *new_desktop_shape;
293 difference.op(desktop_shape_, SkRegion::kDifference_Op); 296 difference.Subtract(desktop_shape_);
294 updated_region_.op(difference, SkRegion::kUnion_Op); 297 updated_region_.AddRegion(difference);
295 updated_region_.op(*new_desktop_shape, SkRegion::kIntersect_Op); 298 updated_region_.IntersectWith(*new_desktop_shape);
296 299
297 // Set the new desktop shape region. 300 // Set the new desktop shape region.
298 desktop_shape_.swap(*new_desktop_shape); 301 desktop_shape_.Swap(new_desktop_shape);
299 } 302 }
300 303
301 } // namespace remoting 304 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698