| 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 screen_size_ = screen_size; |
| 39 | |
| 40 if (frame->format() != media::VideoFrame::RGB32) { | |
| 41 LOG(INFO) << "DecoderVp8 only supports RGB32 as output"; | |
| 42 state_ = kError; | |
| 43 return; | |
| 44 } | |
| 45 frame_ = frame; | |
| 46 | |
| 47 state_ = kReady; | 38 state_ = kReady; |
| 48 } | 39 } |
| 49 | 40 |
| 50 Decoder::DecodeResult DecoderVp8::DecodePacket(const VideoPacket* packet) { | 41 Decoder::DecodeResult DecoderVp8::DecodePacket(const VideoPacket* packet) { |
| 51 DCHECK_EQ(kReady, state_); | 42 DCHECK_EQ(kReady, state_); |
| 52 | 43 |
| 53 // Initialize the codec as needed. | 44 // Initialize the codec as needed. |
| 54 if (!codec_) { | 45 if (!codec_) { |
| 55 codec_ = new vpx_codec_ctx_t(); | 46 codec_ = new vpx_codec_ctx_t(); |
| 56 | 47 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 SkRegion region; | 86 SkRegion region; |
| 96 for (int i = 0; i < packet->dirty_rects_size(); ++i) { | 87 for (int i = 0; i < packet->dirty_rects_size(); ++i) { |
| 97 Rect remoting_rect = packet->dirty_rects(i); | 88 Rect remoting_rect = packet->dirty_rects(i); |
| 98 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), | 89 SkIRect rect = SkIRect::MakeXYWH(remoting_rect.x(), |
| 99 remoting_rect.y(), | 90 remoting_rect.y(), |
| 100 remoting_rect.width(), | 91 remoting_rect.width(), |
| 101 remoting_rect.height()); | 92 remoting_rect.height()); |
| 102 region.op(rect, SkRegion::kUnion_Op); | 93 region.op(rect, SkRegion::kUnion_Op); |
| 103 } | 94 } |
| 104 | 95 |
| 105 RefreshRegion(region); | 96 updated_region_.op(region, SkRegion::kUnion_Op); |
| 106 return DECODE_DONE; | 97 return DECODE_DONE; |
| 107 } | 98 } |
| 108 | 99 |
| 109 void DecoderVp8::GetUpdatedRegion(SkRegion* region) { | |
| 110 region->swap(updated_region_); | |
| 111 } | |
| 112 | |
| 113 void DecoderVp8::Reset() { | |
| 114 frame_ = NULL; | |
| 115 state_ = kUninitialized; | |
| 116 } | |
| 117 | |
| 118 bool DecoderVp8::IsReadyForData() { | 100 bool DecoderVp8::IsReadyForData() { |
| 119 return state_ == kReady; | 101 return state_ == kReady; |
| 120 } | 102 } |
| 121 | 103 |
| 122 VideoPacketFormat::Encoding DecoderVp8::Encoding() { | 104 VideoPacketFormat::Encoding DecoderVp8::Encoding() { |
| 123 return VideoPacketFormat::ENCODING_VP8; | 105 return VideoPacketFormat::ENCODING_VP8; |
| 124 } | 106 } |
| 125 | 107 |
| 126 void DecoderVp8::SetOutputSize(const SkISize& size) { | 108 void DecoderVp8::Invalidate(const SkISize& view_size, |
| 127 output_size_ = size; | 109 const SkRegion& region) { |
| 110 for (SkRegion::Iterator i(region); !i.done(); i.next()) { |
| 111 SkIRect rect = i.rect(); |
| 112 rect = ScaleRect(rect, view_size, screen_size_); |
| 113 updated_region_.op(rect, SkRegion::kUnion_Op); |
| 114 } |
| 128 } | 115 } |
| 129 | 116 |
| 130 void DecoderVp8::SetClipRect(const SkIRect& clip_rect) { | 117 void DecoderVp8::RenderFrame(const SkISize& view_size, |
| 131 clip_rect_ = clip_rect; | 118 const SkIRect& clip_area, |
| 132 } | 119 uint8* image_buffer, |
| 120 int image_stride, |
| 121 SkRegion* output_region) { |
| 122 SkIRect source_clip = SkIRect::MakeWH(last_image_->d_w, last_image_->d_h); |
| 133 | 123 |
| 134 void DecoderVp8::RefreshRegion(const SkRegion& region) { | 124 for (SkRegion::Iterator i(updated_region_); !i.done(); i.next()) { |
| 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 (!last_image_) | |
| 146 return; | |
| 147 | |
| 148 updated_region_.setEmpty(); | |
| 149 | |
| 150 // Clip based on both the output dimensions and Pepper clip rect. | |
| 151 // ConvertAndScaleYUVToRGB32Rect() requires even X and Y coordinates, so we | |
| 152 // align |clip_rect| to prevent clipping from breaking alignment. We then | |
| 153 // clamp it to the image dimensions, which may lead to odd width & height, | |
| 154 // which we can cope with. | |
| 155 SkIRect clip_rect = AlignRect(clip_rect_); | |
| 156 if (!clip_rect.intersect(SkIRect::MakeSize(output_size_))) | |
| 157 return; | |
| 158 | |
| 159 SkISize image_size = SkISize::Make(last_image_->d_w, last_image_->d_h); | |
| 160 uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); | |
| 161 const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); | |
| 162 | |
| 163 for (SkRegion::Iterator i(region); !i.done(); i.next()) { | |
| 164 // Determine the scaled area affected by this rectangle changing. | 125 // Determine the scaled area affected by this rectangle changing. |
| 165 // Align the rectangle so the top-left coordinates are even, for | 126 SkIRect rect = i.rect(); |
| 166 // ConvertAndScaleYUVToRGB32Rect(). | 127 if (!rect.intersect(source_clip)) |
| 167 SkIRect output_rect = ScaleRect(AlignRect(i.rect()), | 128 continue; |
| 168 image_size, output_size_); | 129 rect = ScaleRect(rect, screen_size_, view_size); |
| 169 if (!output_rect.intersect(clip_rect)) | 130 if (!rect.intersect(clip_area)) |
| 170 continue; | 131 continue; |
| 171 | 132 |
| 172 // The scaler will not to read outside the input dimensions. | |
| 173 ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], | 133 ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], |
| 174 last_image_->planes[1], | 134 last_image_->planes[1], |
| 175 last_image_->planes[2], | 135 last_image_->planes[2], |
| 176 last_image_->stride[0], | 136 last_image_->stride[0], |
| 177 last_image_->stride[1], | 137 last_image_->stride[1], |
| 178 image_size, | 138 screen_size_, |
| 179 SkIRect::MakeSize(image_size), | 139 source_clip, |
| 180 output_rgb_buf, | 140 image_buffer, |
| 181 output_stride, | 141 image_stride, |
| 182 output_size_, | 142 view_size, |
| 183 SkIRect::MakeSize(output_size_), | 143 clip_area, |
| 184 output_rect); | 144 rect); |
| 185 | 145 |
| 186 updated_region_.op(output_rect, SkRegion::kUnion_Op); | 146 output_region->op(rect, SkRegion::kUnion_Op); |
| 187 } | 147 } |
| 148 |
| 149 updated_region_.op(ScaleRect(clip_area, view_size, screen_size_), |
| 150 SkRegion::kDifference_Op); |
| 188 } | 151 } |
| 189 | 152 |
| 190 } // namespace remoting | 153 } // namespace remoting |
| OLD | NEW |