OLD | NEW |
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> |
| 10 |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "media/base/media.h" | 12 #include "media/base/media.h" |
11 #include "media/base/yuv_convert.h" | 13 #include "media/base/yuv_convert.h" |
12 #include "remoting/base/util.h" | 14 #include "remoting/base/util.h" |
13 | 15 |
14 extern "C" { | 16 extern "C" { |
15 #define VPX_CODEC_DISABLE_COMPAT 1 | 17 #define VPX_CODEC_DISABLE_COMPAT 1 |
16 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" | 18 #include "third_party/libvpx/source/libvpx/vpx/vpx_decoder.h" |
17 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" | 19 #include "third_party/libvpx/source/libvpx/vpx/vp8dx.h" |
18 } | 20 } |
19 | 21 |
20 namespace remoting { | 22 namespace remoting { |
21 | 23 |
| 24 enum { kBytesPerPixelRGB32 = 4 }; |
| 25 |
| 26 const uint32 kTransparent = 0; |
| 27 |
22 VideoDecoderVp8::VideoDecoderVp8() | 28 VideoDecoderVp8::VideoDecoderVp8() |
23 : state_(kUninitialized), | 29 : state_(kUninitialized), |
24 codec_(NULL), | 30 codec_(NULL), |
25 last_image_(NULL), | 31 last_image_(NULL), |
26 screen_size_(SkISize::Make(0, 0)) { | 32 screen_size_(SkISize::Make(0, 0)) { |
27 } | 33 } |
28 | 34 |
29 VideoDecoderVp8::~VideoDecoderVp8() { | 35 VideoDecoderVp8::~VideoDecoderVp8() { |
30 if (codec_) { | 36 if (codec_) { |
31 vpx_codec_err_t ret = vpx_codec_destroy(codec_); | 37 vpx_codec_err_t ret = vpx_codec_destroy(codec_); |
32 CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; | 38 CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; |
33 } | 39 } |
34 delete codec_; | 40 delete codec_; |
35 } | 41 } |
36 | 42 |
37 void VideoDecoderVp8::Initialize(const SkISize& screen_size) { | 43 void VideoDecoderVp8::Initialize(const SkISize& screen_size) { |
38 DCHECK(!screen_size.isEmpty()); | 44 DCHECK(!screen_size.isEmpty()); |
39 | 45 |
40 screen_size_ = screen_size; | 46 screen_size_ = screen_size; |
41 state_ = kReady; | 47 state_ = kReady; |
| 48 |
| 49 transparent_region_.setRect(SkIRect::MakeSize(screen_size_)); |
42 } | 50 } |
43 | 51 |
44 VideoDecoder::DecodeResult VideoDecoderVp8::DecodePacket( | 52 VideoDecoder::DecodeResult VideoDecoderVp8::DecodePacket( |
45 const VideoPacket* packet) { | 53 const VideoPacket* packet) { |
46 DCHECK_EQ(kReady, state_); | 54 DCHECK_EQ(kReady, state_); |
47 | 55 |
48 // Initialize the codec as needed. | 56 // Initialize the codec as needed. |
49 if (!codec_) { | 57 if (!codec_) { |
50 codec_ = new vpx_codec_ctx_t(); | 58 codec_ = new vpx_codec_ctx_t(); |
51 | 59 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 for (int i = 0; i < packet->dirty_rects_size(); ++i) { | 99 for (int i = 0; i < packet->dirty_rects_size(); ++i) { |
92 Rect remoting_rect = packet->dirty_rects(i); | 100 Rect remoting_rect = packet->dirty_rects(i); |
93 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), | 101 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), |
94 remoting_rect.y(), | 102 remoting_rect.y(), |
95 remoting_rect.width(), | 103 remoting_rect.width(), |
96 remoting_rect.height()); | 104 remoting_rect.height()); |
97 region.op(rect, SkRegion::kUnion_Op); | 105 region.op(rect, SkRegion::kUnion_Op); |
98 } | 106 } |
99 | 107 |
100 updated_region_.op(region, SkRegion::kUnion_Op); | 108 updated_region_.op(region, SkRegion::kUnion_Op); |
| 109 |
| 110 // Update the desktop shape region. |
| 111 SkRegion desktop_shape_region; |
| 112 if (packet->has_use_desktop_shape()) { |
| 113 for (int i = 0; i < packet->desktop_shape_rects_size(); ++i) { |
| 114 Rect remoting_rect = packet->desktop_shape_rects(i); |
| 115 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), |
| 116 remoting_rect.y(), |
| 117 remoting_rect.width(), |
| 118 remoting_rect.height()); |
| 119 desktop_shape_region.op(rect, SkRegion::kUnion_Op); |
| 120 } |
| 121 } else { |
| 122 // Fallback for the case when the host didn't include the desktop shape |
| 123 // region. |
| 124 desktop_shape_region = SkRegion(SkIRect::MakeSize(screen_size_)); |
| 125 } |
| 126 |
| 127 UpdateImageShapeRegion(&desktop_shape_region); |
| 128 |
101 return DECODE_DONE; | 129 return DECODE_DONE; |
102 } | 130 } |
103 | 131 |
104 bool VideoDecoderVp8::IsReadyForData() { | 132 bool VideoDecoderVp8::IsReadyForData() { |
105 return state_ == kReady; | 133 return state_ == kReady; |
106 } | 134 } |
107 | 135 |
108 VideoPacketFormat::Encoding VideoDecoderVp8::Encoding() { | 136 VideoPacketFormat::Encoding VideoDecoderVp8::Encoding() { |
109 return VideoPacketFormat::ENCODING_VP8; | 137 return VideoPacketFormat::ENCODING_VP8; |
110 } | 138 } |
111 | 139 |
112 void VideoDecoderVp8::Invalidate(const SkISize& view_size, | 140 void VideoDecoderVp8::Invalidate(const SkISize& view_size, |
113 const SkRegion& region) { | 141 const SkRegion& region) { |
114 DCHECK_EQ(kReady, state_); | 142 DCHECK_EQ(kReady, state_); |
115 DCHECK(!view_size.isEmpty()); | 143 DCHECK(!view_size.isEmpty()); |
116 | 144 |
117 for (SkRegion::Iterator i(region); !i.done(); i.next()) { | 145 for (SkRegion::Iterator i(region); !i.done(); i.next()) { |
118 SkIRect rect = i.rect(); | 146 SkIRect rect = i.rect(); |
119 rect = ScaleRect(rect, view_size, screen_size_); | 147 rect = ScaleRect(rect, view_size, screen_size_); |
120 updated_region_.op(rect, SkRegion::kUnion_Op); | 148 updated_region_.op(rect, SkRegion::kUnion_Op); |
121 } | 149 } |
| 150 |
| 151 // Updated areas outside of the new desktop shape region should be made |
| 152 // transparent, not repainted. |
| 153 SkRegion difference = updated_region_; |
| 154 difference.op(desktop_shape_, SkRegion::kDifference_Op); |
| 155 updated_region_.op(difference, SkRegion::kDifference_Op); |
| 156 transparent_region_.op(difference, SkRegion::kUnion_Op); |
122 } | 157 } |
123 | 158 |
124 void VideoDecoderVp8::RenderFrame(const SkISize& view_size, | 159 void VideoDecoderVp8::RenderFrame(const SkISize& view_size, |
125 const SkIRect& clip_area, | 160 const SkIRect& clip_area, |
126 uint8* image_buffer, | 161 uint8* image_buffer, |
127 int image_stride, | 162 int image_stride, |
128 SkRegion* output_region) { | 163 SkRegion* output_region) { |
129 DCHECK_EQ(kReady, state_); | 164 DCHECK_EQ(kReady, state_); |
130 DCHECK(!view_size.isEmpty()); | 165 DCHECK(!view_size.isEmpty()); |
131 | 166 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 image_stride, | 236 image_stride, |
202 view_size, | 237 view_size, |
203 clip_area, | 238 clip_area, |
204 rect); | 239 rect); |
205 | 240 |
206 output_region->op(rect, SkRegion::kUnion_Op); | 241 output_region->op(rect, SkRegion::kUnion_Op); |
207 } | 242 } |
208 | 243 |
209 updated_region_.op(ScaleRect(clip_area, view_size, screen_size_), | 244 updated_region_.op(ScaleRect(clip_area, view_size, screen_size_), |
210 SkRegion::kDifference_Op); | 245 SkRegion::kDifference_Op); |
| 246 |
| 247 for (SkRegion::Iterator i(transparent_region_); !i.done(); i.next()) { |
| 248 // Determine the scaled area affected by this rectangle changing. |
| 249 SkIRect rect = i.rect(); |
| 250 if (!rect.intersect(source_clip)) |
| 251 continue; |
| 252 rect = ScaleRect(rect, screen_size_, view_size); |
| 253 if (!rect.intersect(clip_area)) |
| 254 continue; |
| 255 |
| 256 // Fill the rectange with transparent pixels. |
| 257 FillRect(image_buffer, image_stride, rect, kTransparent); |
| 258 output_region->op(rect, SkRegion::kUnion_Op); |
| 259 } |
| 260 |
| 261 SkIRect scaled_clip_area = ScaleRect(clip_area, view_size, screen_size_); |
| 262 updated_region_.op(scaled_clip_area, SkRegion::kDifference_Op); |
| 263 transparent_region_.op(scaled_clip_area, SkRegion::kDifference_Op); |
| 264 } |
| 265 |
| 266 const SkRegion* VideoDecoderVp8::GetImageShape() { |
| 267 return &desktop_shape_; |
| 268 } |
| 269 |
| 270 void VideoDecoderVp8::FillRect(uint8* buffer, |
| 271 int stride, |
| 272 const SkIRect& rect, |
| 273 uint32 color) { |
| 274 uint32* ptr = reinterpret_cast<uint32*>(buffer + (rect.top() * stride) + |
| 275 (rect.left() * kBytesPerPixelRGB32)); |
| 276 int width = rect.width(); |
| 277 for (int height = rect.height(); height > 0; --height) { |
| 278 std::fill(ptr, ptr + width, color); |
| 279 ptr += stride / kBytesPerPixelRGB32; |
| 280 } |
| 281 } |
| 282 |
| 283 void VideoDecoderVp8::UpdateImageShapeRegion(SkRegion* new_desktop_shape) { |
| 284 // Add all areas that have been updated or become transparent to the |
| 285 // transparent region. Exclude anything within the new desktop shape. |
| 286 transparent_region_.op(desktop_shape_, SkRegion::kUnion_Op); |
| 287 transparent_region_.op(updated_region_, SkRegion::kUnion_Op); |
| 288 transparent_region_.op(*new_desktop_shape, SkRegion::kDifference_Op); |
| 289 |
| 290 // Add newly exposed areas to the update region and limit updates to the new |
| 291 // desktop shape. |
| 292 SkRegion difference = *new_desktop_shape; |
| 293 difference.op(desktop_shape_, SkRegion::kDifference_Op); |
| 294 updated_region_.op(difference, SkRegion::kUnion_Op); |
| 295 updated_region_.op(*new_desktop_shape, SkRegion::kIntersect_Op); |
| 296 |
| 297 // Set the new desktop shape region. |
| 298 desktop_shape_.swap(*new_desktop_shape); |
211 } | 299 } |
212 | 300 |
213 } // namespace remoting | 301 } // namespace remoting |
OLD | NEW |