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

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

Powered by Google App Engine
This is Rietveld 408576698