Chromium Code Reviews| 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 |