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/base/decoder_vp8.h" | 5 #include "remoting/base/decoder_vp8.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "media/base/media.h" | 10 #include "media/base/media.h" |
11 #include "media/base/yuv_convert.h" | 11 #include "media/base/yuv_convert.h" |
12 #include "remoting/base/util.h" | 12 #include "remoting/base/util.h" |
13 | 13 |
14 extern "C" { | 14 extern "C" { |
15 #define VPX_CODEC_DISABLE_COMPAT 1 | 15 #define VPX_CODEC_DISABLE_COMPAT 1 |
16 #include "third_party/libvpx/libvpx.h" | 16 #include "third_party/libvpx/libvpx.h" |
17 } | 17 } |
18 | 18 |
19 namespace remoting { | 19 namespace remoting { |
20 | 20 |
21 DecoderVp8::DecoderVp8() | 21 DecoderVp8::DecoderVp8() |
22 : state_(kUninitialized), | 22 : state_(kUninitialized), |
23 codec_(NULL), | 23 codec_(NULL), |
24 last_image_(NULL), | 24 last_image_(NULL), |
25 clip_rect_(SkIRect::MakeEmpty()), | 25 screen_size_(SkISize::Make(0, 0)) { |
26 output_size_(SkISize::Make(0, 0)) { | |
27 } | 26 } |
28 | 27 |
29 DecoderVp8::~DecoderVp8() { | 28 DecoderVp8::~DecoderVp8() { |
30 if (codec_) { | 29 if (codec_) { |
31 vpx_codec_err_t ret = vpx_codec_destroy(codec_); | 30 vpx_codec_err_t ret = vpx_codec_destroy(codec_); |
32 CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; | 31 CHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; |
33 } | 32 } |
34 delete codec_; | 33 delete codec_; |
35 } | 34 } |
36 | 35 |
37 void DecoderVp8::Initialize(scoped_refptr<media::VideoFrame> frame) { | 36 void DecoderVp8::Initialize(const SkISize& screen_size) { |
38 DCHECK_EQ(kUninitialized, state_); | 37 DCHECK_EQ(kUninitialized, state_); |
39 | 38 |
40 if (frame->format() != media::VideoFrame::RGB32) { | 39 screen_size_ = screen_size; |
41 LOG(INFO) << "DecoderVp8 only supports RGB32 as output"; | |
42 state_ = kError; | |
43 return; | |
44 } | |
45 frame_ = frame; | |
46 | |
47 state_ = kReady; | 40 state_ = kReady; |
48 } | 41 } |
49 | 42 |
50 Decoder::DecodeResult DecoderVp8::DecodePacket(const VideoPacket* packet) { | 43 Decoder::DecodeResult DecoderVp8::DecodePacket(const VideoPacket* packet) { |
51 DCHECK_EQ(kReady, state_); | 44 DCHECK_EQ(kReady, state_); |
52 | 45 |
53 // Initialize the codec as needed. | 46 // Initialize the codec as needed. |
54 if (!codec_) { | 47 if (!codec_) { |
55 codec_ = new vpx_codec_ctx_t(); | 48 codec_ = new vpx_codec_ctx_t(); |
56 | 49 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 SkRegion region; | 88 SkRegion region; |
96 for (int i = 0; i < packet->dirty_rects_size(); ++i) { | 89 for (int i = 0; i < packet->dirty_rects_size(); ++i) { |
97 Rect remoting_rect = packet->dirty_rects(i); | 90 Rect remoting_rect = packet->dirty_rects(i); |
98 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), | 91 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), |
99 remoting_rect.y(), | 92 remoting_rect.y(), |
100 remoting_rect.width(), | 93 remoting_rect.width(), |
101 remoting_rect.height()); | 94 remoting_rect.height()); |
102 region.op(rect, SkRegion::kUnion_Op); | 95 region.op(rect, SkRegion::kUnion_Op); |
103 } | 96 } |
104 | 97 |
105 RefreshRegion(region); | 98 UpdateRegion(region); |
106 return DECODE_DONE; | 99 return DECODE_DONE; |
107 } | 100 } |
108 | 101 |
109 void DecoderVp8::GetUpdatedRegion(SkRegion* region) { | |
110 region->swap(updated_region_); | |
111 } | |
112 | |
113 void DecoderVp8::Reset() { | 102 void DecoderVp8::Reset() { |
114 frame_ = NULL; | |
115 state_ = kUninitialized; | 103 state_ = kUninitialized; |
Wez
2012/02/07 01:56:31
Do we need this, since when we use it, we immediat
alexeypa (please no reviews)
2012/02/15 23:06:22
Done.
| |
116 } | 104 } |
117 | 105 |
118 bool DecoderVp8::IsReadyForData() { | 106 bool DecoderVp8::IsReadyForData() { |
119 return state_ == kReady; | 107 return state_ == kReady; |
120 } | 108 } |
121 | 109 |
122 VideoPacketFormat::Encoding DecoderVp8::Encoding() { | 110 VideoPacketFormat::Encoding DecoderVp8::Encoding() { |
123 return VideoPacketFormat::ENCODING_VP8; | 111 return VideoPacketFormat::ENCODING_VP8; |
124 } | 112 } |
125 | 113 |
126 void DecoderVp8::SetOutputSize(const SkISize& size) { | 114 void DecoderVp8::UpdateRegion(const SkRegion& region) { |
127 output_size_ = size; | 115 updated_region_.op(region, SkRegion::kUnion_Op); |
128 } | 116 } |
129 | 117 |
130 void DecoderVp8::SetClipRect(const SkIRect& clip_rect) { | 118 void DecoderVp8::Draw(const SkISize& view_size, |
131 clip_rect_ = clip_rect; | 119 const SkIRect& clip_area, |
132 } | 120 uint8* image_buffer, |
121 int image_stride, | |
122 SkRegion* output_region) { | |
123 output_region->setEmpty(); | |
133 | 124 |
134 void DecoderVp8::RefreshRegion(const SkRegion& region) { | |
135 // TODO(wez): Fix the rest of the decode pipeline not to assume the frame | |
136 // size is the host dimensions, since it's not when scaling. If the host | |
137 // gets smaller, then the output size will be too big and we'll overrun the | |
138 // frame, so currently we render 1:1 in that case; the app will see the | |
139 // host size change and resize us if need be. | |
140 if (output_size_.width() > static_cast<int>(frame_->width())) | |
141 output_size_.set(frame_->width(), output_size_.height()); | |
142 if (output_size_.height() > static_cast<int>(frame_->height())) | |
143 output_size_.set(output_size_.width(), frame_->height()); | |
144 | |
145 if (!DoScaling()) { | |
146 ConvertRegion(region, &updated_region_); | |
147 } else { | |
148 ScaleAndConvertRegion(region, &updated_region_); | |
149 } | |
150 } | |
151 | |
152 bool DecoderVp8::DoScaling() const { | |
153 DCHECK(last_image_); | |
154 return !output_size_.equals(last_image_->d_w, last_image_->d_h); | |
155 } | |
156 | |
157 void DecoderVp8::ConvertRegion(const SkRegion& input_region, | |
158 SkRegion* output_region) { | |
159 if (!last_image_) | 125 if (!last_image_) |
160 return; | 126 return; |
161 | 127 |
162 output_region->setEmpty(); | 128 SkIRect source_clip = SkIRect::MakeWH(last_image_->d_w, last_image_->d_h); |
163 | 129 |
164 // Clip based on both the output dimensions and Pepper clip rect. | 130 for (SkRegion::Iterator i(updated_region_); !i.done(); i.next()) { |
165 // ConvertYUVToRGB32WithRect() requires even X and Y coordinates, so we align | 131 // Determine the scaled area affected by this rectangle changing. |
166 // |clip_rect| to prevent clipping from breaking alignment. We then clamp it | 132 SkIRect rect = i.rect(); |
167 // to the image dimensions, which may lead to odd width & height, which we | 133 if (!rect.intersect(source_clip)) |
168 // can cope with. | 134 continue; |
169 SkIRect clip_rect = AlignRect(clip_rect_); | 135 rect = ScaleRect(rect, screen_size_, view_size); |
170 if (!clip_rect.intersect(SkIRect::MakeWH(last_image_->d_w, last_image_->d_h))) | 136 if (!rect.intersect(clip_area)) |
171 return; | |
172 | |
173 uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); | |
174 const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); | |
175 | |
176 for (SkRegion::Iterator i(input_region); !i.done(); i.next()) { | |
177 // Align the rectangle so the top-left coordinates are even, for | |
178 // ConvertYUVToRGB32WithRect(). | |
179 SkIRect dest_rect(AlignRect(i.rect())); | |
180 | |
181 // Clip the rectangle, preserving alignment since |clip_rect| is aligned. | |
182 if (!dest_rect.intersect(clip_rect)) | |
183 continue; | 137 continue; |
184 | 138 |
185 ConvertYUVToRGB32WithRect(last_image_->planes[0], | 139 ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], |
186 last_image_->planes[1], | 140 last_image_->planes[1], |
187 last_image_->planes[2], | 141 last_image_->planes[2], |
188 output_rgb_buf, | 142 last_image_->stride[0], |
189 dest_rect, | 143 last_image_->stride[1], |
190 last_image_->stride[0], | 144 screen_size_, |
191 last_image_->stride[1], | 145 source_clip, |
192 output_stride); | 146 image_buffer, |
147 image_stride, | |
148 view_size, | |
149 clip_area, | |
150 rect); | |
193 | 151 |
194 output_region->op(dest_rect, SkRegion::kUnion_Op); | 152 output_region->op(rect, SkRegion::kUnion_Op); |
195 } | 153 } |
196 } | |
197 | 154 |
198 void DecoderVp8::ScaleAndConvertRegion(const SkRegion& input_region, | 155 updated_region_.setEmpty(); |
199 SkRegion* output_region) { | |
200 if (!last_image_) | |
201 return; | |
202 | |
203 DCHECK(output_size_.width() <= static_cast<int>(frame_->width())); | |
204 DCHECK(output_size_.height() <= static_cast<int>(frame_->height())); | |
205 | |
206 output_region->setEmpty(); | |
207 | |
208 // Clip based on both the output dimensions and Pepper clip rect. | |
209 SkIRect clip_rect = clip_rect_; | |
210 if (!clip_rect.intersect(SkIRect::MakeSize(output_size_))) | |
211 return; | |
212 | |
213 SkISize image_size = SkISize::Make(last_image_->d_w, last_image_->d_h); | |
214 uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); | |
215 const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); | |
216 | |
217 for (SkRegion::Iterator i(input_region); !i.done(); i.next()) { | |
218 // Determine the scaled area affected by this rectangle changing. | |
219 SkIRect output_rect = ScaleRect(i.rect(), image_size, output_size_); | |
220 if (!output_rect.intersect(clip_rect)) | |
221 continue; | |
222 | |
223 // The scaler will not to read outside the input dimensions. | |
224 media::ScaleYUVToRGB32WithRect(last_image_->planes[0], | |
225 last_image_->planes[1], | |
226 last_image_->planes[2], | |
227 output_rgb_buf, | |
228 image_size.width(), | |
229 image_size.height(), | |
230 output_size_.width(), | |
231 output_size_.height(), | |
232 output_rect.x(), | |
233 output_rect.y(), | |
234 output_rect.right(), | |
235 output_rect.bottom(), | |
236 last_image_->stride[0], | |
237 last_image_->stride[1], | |
238 output_stride); | |
239 | |
240 output_region->op(output_rect, SkRegion::kUnion_Op); | |
241 } | |
242 } | 156 } |
243 | 157 |
244 } // namespace remoting | 158 } // namespace remoting |
OLD | NEW |