| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/encoder_vp8.h" | 5 #include "remoting/base/encoder_vp8.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "media/base/callback.h" | 8 #include "media/base/callback.h" |
| 9 #include "media/base/yuv_convert.h" | 9 #include "media/base/yuv_convert.h" |
| 10 #include "remoting/base/capture_data.h" | 10 #include "remoting/base/capture_data.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 namespace remoting { | 28 namespace remoting { |
| 29 | 29 |
| 30 EncoderVp8::EncoderVp8() | 30 EncoderVp8::EncoderVp8() |
| 31 : initialized_(false), | 31 : initialized_(false), |
| 32 codec_(NULL), | 32 codec_(NULL), |
| 33 image_(NULL), | 33 image_(NULL), |
| 34 active_map_width_(0), | 34 active_map_width_(0), |
| 35 active_map_height_(0), | 35 active_map_height_(0), |
| 36 last_timestamp_(0), | 36 last_timestamp_(0), |
| 37 size_(0, 0) { | 37 size_(SkISize::Make(0, 0)) { |
| 38 } | 38 } |
| 39 | 39 |
| 40 EncoderVp8::~EncoderVp8() { | 40 EncoderVp8::~EncoderVp8() { |
| 41 Destroy(); | 41 Destroy(); |
| 42 } | 42 } |
| 43 | 43 |
| 44 void EncoderVp8::Destroy() { | 44 void EncoderVp8::Destroy() { |
| 45 if (initialized_) { | 45 if (initialized_) { |
| 46 vpx_codec_err_t ret = vpx_codec_destroy(codec_.get()); | 46 vpx_codec_err_t ret = vpx_codec_destroy(codec_.get()); |
| 47 DCHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; | 47 DCHECK(ret == VPX_CODEC_OK) << "Failed to destroy codec"; |
| 48 initialized_ = false; | 48 initialized_ = false; |
| 49 } | 49 } |
| 50 } | 50 } |
| 51 | 51 |
| 52 bool EncoderVp8::Init(const gfx::Size& size) { | 52 bool EncoderVp8::Init(const SkISize& size) { |
| 53 Destroy(); | 53 Destroy(); |
| 54 size_ = size; | 54 size_ = size; |
| 55 codec_.reset(new vpx_codec_ctx_t()); | 55 codec_.reset(new vpx_codec_ctx_t()); |
| 56 image_.reset(new vpx_image_t()); | 56 image_.reset(new vpx_image_t()); |
| 57 memset(image_.get(), 0, sizeof(vpx_image_t)); | 57 memset(image_.get(), 0, sizeof(vpx_image_t)); |
| 58 | 58 |
| 59 image_->fmt = VPX_IMG_FMT_YV12; | 59 image_->fmt = VPX_IMG_FMT_YV12; |
| 60 | 60 |
| 61 // libvpx seems to require both to be assigned. | 61 // libvpx seems to require both to be assigned. |
| 62 image_->d_w = size.width(); | 62 image_->d_w = size.width(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 128 return false; | 128 return false; |
| 129 | 129 |
| 130 // Use the lowest level of noise sensitivity so as to spend less time | 130 // Use the lowest level of noise sensitivity so as to spend less time |
| 131 // on motion estimation and inter-prediction mode. | 131 // on motion estimation and inter-prediction mode. |
| 132 if (vpx_codec_control(codec_.get(), VP8E_SET_NOISE_SENSITIVITY, 0)) | 132 if (vpx_codec_control(codec_.get(), VP8E_SET_NOISE_SENSITIVITY, 0)) |
| 133 return false; | 133 return false; |
| 134 return true; | 134 return true; |
| 135 } | 135 } |
| 136 | 136 |
| 137 // static | 137 // static |
| 138 gfx::Rect EncoderVp8::AlignAndClipRect(const gfx::Rect& rect, | 138 SkIRect EncoderVp8::AlignAndClipRect(const SkIRect& rect, |
| 139 int width, int height) { | 139 int width, int height) { |
| 140 gfx::Rect screen(RoundToTwosMultiple(width), RoundToTwosMultiple(height)); | 140 SkIRect screen(SkIRect::MakeWH(RoundToTwosMultiple(width), |
| 141 return screen.Intersect(AlignRect(rect)); | 141 RoundToTwosMultiple(height))); |
| 142 if (!screen.intersect(AlignRect(rect))) { |
| 143 screen = SkIRect::MakeWH(0, 0); |
| 144 } |
| 145 return screen; |
| 142 } | 146 } |
| 143 | 147 |
| 144 bool EncoderVp8::PrepareImage(scoped_refptr<CaptureData> capture_data, | 148 bool EncoderVp8::PrepareImage(scoped_refptr<CaptureData> capture_data, |
| 145 std::vector<gfx::Rect>* updated_rects) { | 149 RectVector* updated_rects) { |
| 146 // Perform RGB->YUV conversion. | 150 // Perform RGB->YUV conversion. |
| 147 if (capture_data->pixel_format() != media::VideoFrame::RGB32) { | 151 if (capture_data->pixel_format() != media::VideoFrame::RGB32) { |
| 148 LOG(ERROR) << "Only RGB32 is supported"; | 152 LOG(ERROR) << "Only RGB32 is supported"; |
| 149 return false; | 153 return false; |
| 150 } | 154 } |
| 151 | 155 |
| 152 const SkRegion& region = capture_data->dirty_region(); | 156 const SkRegion& region = capture_data->dirty_region(); |
| 153 const uint8* in = capture_data->data_planes().data[0]; | 157 const uint8* in = capture_data->data_planes().data[0]; |
| 154 const int in_stride = capture_data->data_planes().strides[0]; | 158 const int in_stride = capture_data->data_planes().strides[0]; |
| 155 const int plane_size = | 159 const int plane_size = |
| 156 capture_data->size().width() * capture_data->size().height(); | 160 capture_data->size().width() * capture_data->size().height(); |
| 157 uint8* y_out = yuv_image_.get(); | 161 uint8* y_out = yuv_image_.get(); |
| 158 uint8* u_out = yuv_image_.get() + plane_size; | 162 uint8* u_out = yuv_image_.get() + plane_size; |
| 159 uint8* v_out = yuv_image_.get() + plane_size + plane_size / 4; | 163 uint8* v_out = yuv_image_.get() + plane_size + plane_size / 4; |
| 160 const int y_stride = image_->stride[0]; | 164 const int y_stride = image_->stride[0]; |
| 161 const int uv_stride = image_->stride[1]; | 165 const int uv_stride = image_->stride[1]; |
| 162 | 166 |
| 163 DCHECK(updated_rects->empty()); | 167 DCHECK(updated_rects->empty()); |
| 164 for (SkRegion::Iterator r(region); !r.done(); r.next()) { | 168 for (SkRegion::Iterator r(region); !r.done(); r.next()) { |
| 165 // Align the rectangle, report it as updated. | 169 // Align the rectangle, report it as updated. |
| 166 SkIRect skRect = r.rect(); | 170 SkIRect rect = r.rect(); |
| 167 gfx::Rect rect(skRect.fLeft, skRect.fTop, skRect.width(), skRect.height()); | |
| 168 rect = AlignAndClipRect(rect, image_->w, image_->h); | 171 rect = AlignAndClipRect(rect, image_->w, image_->h); |
| 169 if (!rect.IsEmpty()) | 172 if (!rect.isEmpty()) |
| 170 updated_rects->push_back(rect); | 173 updated_rects->push_back(rect); |
| 171 | 174 |
| 172 ConvertRGB32ToYUVWithRect(in, | 175 ConvertRGB32ToYUVWithRect(in, |
| 173 y_out, | 176 y_out, |
| 174 u_out, | 177 u_out, |
| 175 v_out, | 178 v_out, |
| 176 rect.x(), | 179 rect.fLeft, |
| 177 rect.y(), | 180 rect.fTop, |
| 178 rect.width(), | 181 rect.width(), |
| 179 rect.height(), | 182 rect.height(), |
| 180 in_stride, | 183 in_stride, |
| 181 y_stride, | 184 y_stride, |
| 182 uv_stride); | 185 uv_stride); |
| 183 } | 186 } |
| 184 return true; | 187 return true; |
| 185 } | 188 } |
| 186 | 189 |
| 187 void EncoderVp8::PrepareActiveMap( | 190 void EncoderVp8::PrepareActiveMap(const RectVector& updated_rects) { |
| 188 const std::vector<gfx::Rect>& updated_rects) { | |
| 189 // Clear active map first. | 191 // Clear active map first. |
| 190 memset(active_map_.get(), 0, active_map_width_ * active_map_height_); | 192 memset(active_map_.get(), 0, active_map_width_ * active_map_height_); |
| 191 | 193 |
| 192 // Mark blocks at active. | 194 // Mark blocks at active. |
| 193 for (size_t i = 0; i < updated_rects.size(); ++i) { | 195 for (size_t i = 0; i < updated_rects.size(); ++i) { |
| 194 const gfx::Rect& r = updated_rects[i]; | 196 const SkIRect& r = updated_rects[i]; |
| 195 CHECK(r.width() && r.height()); | 197 CHECK(r.width() && r.height()); |
| 196 | 198 |
| 197 int left = r.x() / kMacroBlockSize; | 199 int left = r.fLeft / kMacroBlockSize; |
| 198 int right = (r.right() - 1) / kMacroBlockSize; | 200 int right = (r.fRight - 1) / kMacroBlockSize; |
| 199 int top = r.y() / kMacroBlockSize; | 201 int top = r.fTop / kMacroBlockSize; |
| 200 int bottom = (r.bottom() - 1) / kMacroBlockSize; | 202 int bottom = (r.fBottom - 1) / kMacroBlockSize; |
| 201 CHECK(right < active_map_width_); | 203 CHECK(right < active_map_width_); |
| 202 CHECK(bottom < active_map_height_); | 204 CHECK(bottom < active_map_height_); |
| 203 | 205 |
| 204 uint8* map = active_map_.get() + top * active_map_width_; | 206 uint8* map = active_map_.get() + top * active_map_width_; |
| 205 for (int y = top; y <= bottom; ++y) { | 207 for (int y = top; y <= bottom; ++y) { |
| 206 for (int x = left; x <= right; ++x) | 208 for (int x = left; x <= right; ++x) |
| 207 map[x] = 1; | 209 map[x] = 1; |
| 208 map += active_map_width_; | 210 map += active_map_width_; |
| 209 } | 211 } |
| 210 } | 212 } |
| 211 } | 213 } |
| 212 | 214 |
| 213 void EncoderVp8::Encode(scoped_refptr<CaptureData> capture_data, | 215 void EncoderVp8::Encode(scoped_refptr<CaptureData> capture_data, |
| 214 bool key_frame, | 216 bool key_frame, |
| 215 DataAvailableCallback* data_available_callback) { | 217 DataAvailableCallback* data_available_callback) { |
| 216 if (!initialized_ || (capture_data->size() != size_)) { | 218 if (!initialized_ || (capture_data->size() != size_)) { |
| 217 bool ret = Init(capture_data->size()); | 219 bool ret = Init(capture_data->size()); |
| 218 // TODO(hclam): Handle error better. | 220 // TODO(hclam): Handle error better. |
| 219 DCHECK(ret) << "Initialization of encoder failed"; | 221 DCHECK(ret) << "Initialization of encoder failed"; |
| 220 initialized_ = ret; | 222 initialized_ = ret; |
| 221 } | 223 } |
| 222 | 224 |
| 223 std::vector<gfx::Rect> updated_rects; | 225 RectVector updated_rects; |
| 224 if (!PrepareImage(capture_data, &updated_rects)) { | 226 if (!PrepareImage(capture_data, &updated_rects)) { |
| 225 NOTREACHED() << "Can't image data for encoding"; | 227 NOTREACHED() << "Can't image data for encoding"; |
| 226 } | 228 } |
| 227 | 229 |
| 228 // Update active map based on updated rectangles. | 230 // Update active map based on updated rectangles. |
| 229 PrepareActiveMap(updated_rects); | 231 PrepareActiveMap(updated_rects); |
| 230 | 232 |
| 231 // Apply active map to the encoder. | 233 // Apply active map to the encoder. |
| 232 vpx_active_map_t act_map; | 234 vpx_active_map_t act_map; |
| 233 act_map.rows = active_map_height_; | 235 act_map.rows = active_map_height_; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 | 278 |
| 277 message->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); | 279 message->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); |
| 278 message->set_flags(VideoPacket::FIRST_PACKET | VideoPacket::LAST_PACKET | | 280 message->set_flags(VideoPacket::FIRST_PACKET | VideoPacket::LAST_PACKET | |
| 279 VideoPacket::LAST_PARTITION); | 281 VideoPacket::LAST_PARTITION); |
| 280 message->mutable_format()->set_screen_width(capture_data->size().width()); | 282 message->mutable_format()->set_screen_width(capture_data->size().width()); |
| 281 message->mutable_format()->set_screen_height(capture_data->size().height()); | 283 message->mutable_format()->set_screen_height(capture_data->size().height()); |
| 282 message->set_capture_time_ms(capture_data->capture_time_ms()); | 284 message->set_capture_time_ms(capture_data->capture_time_ms()); |
| 283 message->set_client_sequence_number(capture_data->client_sequence_number()); | 285 message->set_client_sequence_number(capture_data->client_sequence_number()); |
| 284 for (size_t i = 0; i < updated_rects.size(); ++i) { | 286 for (size_t i = 0; i < updated_rects.size(); ++i) { |
| 285 Rect* rect = message->add_dirty_rects(); | 287 Rect* rect = message->add_dirty_rects(); |
| 286 rect->set_x(updated_rects[i].x()); | 288 rect->set_x(updated_rects[i].fLeft); |
| 287 rect->set_y(updated_rects[i].y()); | 289 rect->set_y(updated_rects[i].fTop); |
| 288 rect->set_width(updated_rects[i].width()); | 290 rect->set_width(updated_rects[i].width()); |
| 289 rect->set_height(updated_rects[i].height()); | 291 rect->set_height(updated_rects[i].height()); |
| 290 } | 292 } |
| 291 | 293 |
| 292 data_available_callback->Run(message); | 294 data_available_callback->Run(message); |
| 293 delete data_available_callback; | 295 delete data_available_callback; |
| 294 } | 296 } |
| 295 | 297 |
| 296 } // namespace remoting | 298 } // namespace remoting |
| OLD | NEW |