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 3 // found in the LICENSE file. 4 5 #include "remoting/codec/video_decoder_verbatim.h" 6 7 #include "base/logging.h" 8 #include "remoting/base/util.h" 9 10 namespace remoting { 11 12 namespace { 13 // Both input and output data are assumed to be RGBA32. 14 const int kBytesPerPixel = 4; 15 } // namespace 16 17 18 VideoDecoderVerbatim::VideoDecoderVerbatim() 19 : state_(kUninitialized), 20 clip_(SkIRect::MakeEmpty()), 21 row_pos_(0), 22 row_y_(0), 23 screen_size_(SkISize::Make(0, 0)) { 24 } 25 26 VideoDecoderVerbatim::~VideoDecoderVerbatim() { 27 } 28 29 bool VideoDecoderVerbatim::IsReadyForData() { 30 switch (state_) { 31 case kUninitialized: 32 case kError: 33 return false; 34 case kReady: 35 case kProcessing: 36 case kPartitionDone: 37 case kDone: 38 return true; 39 } 40 NOTREACHED(); 41 return false; 42 } 43 44 void VideoDecoderVerbatim::Initialize(const SkISize& screen_size) { 45 updated_region_.setEmpty(); 46 screen_buffer_.reset(); 47 48 screen_size_ = screen_size; 49 // Allocate the screen buffer, if necessary. 50 if (!screen_size_.isEmpty()) { 51 screen_buffer_.reset(new uint8[ 52 screen_size_.width() * screen_size_.height() * kBytesPerPixel]); 53 } 54 55 state_ = kReady; 56 } 57 58 VideoDecoder::DecodeResult VideoDecoderVerbatim::DecodePacket( 59 const VideoPacket* packet) { 60 UpdateStateForPacket(packet); 61 62 if (state_ == kError) { 63 return DECODE_ERROR; 64 } 65 66 const uint8* in = reinterpret_cast<const uint8*>(packet->data().data()); 67 const int in_size = packet->data().size(); 68 const int row_size = clip_.width() * kBytesPerPixel; 69 70 int out_stride = screen_size_.width() * kBytesPerPixel; 71 uint8* out = screen_buffer_.get() + out_stride * (clip_.top() + row_y_) + 72 kBytesPerPixel * clip_.left(); 73 74 // Consume all the data in the message. 75 int used = 0; 76 while (used < in_size) { 77 if (row_y_ >= clip_.height()) { 78 state_ = kError; 79 LOG(WARNING) << "Too much data is received for the given rectangle."; 80 return DECODE_ERROR; 81 } 82 83 int bytes_to_copy = std::min(in_size - used, row_size - row_pos_); 84 memcpy(out + row_pos_, in + used, bytes_to_copy); 85 86 used += bytes_to_copy; 87 row_pos_ += bytes_to_copy; 88 89 // If this row is completely filled then move onto the next row. 90 if (row_pos_ == row_size) { 91 ++row_y_; 92 row_pos_ = 0; 93 out += out_stride; 94 } 95 } 96 97 if (state_ == kPartitionDone || state_ == kDone) { 98 if (row_y_ < clip_.height()) { 99 state_ = kError; 100 LOG(WARNING) << "Received LAST_PACKET, but didn't get enough data."; 101 return DECODE_ERROR; 102 } 103 104 updated_region_.op(clip_, SkRegion::kUnion_Op); 105 } 106 107 if (state_ == kDone) { 108 return DECODE_DONE; 109 } else { 110 return DECODE_IN_PROGRESS; 111 } 112 } 113 114 void VideoDecoderVerbatim::UpdateStateForPacket(const VideoPacket* packet) { 115 if (state_ == kError) { 116 return; 117 } 118 119 if (packet->flags() & VideoPacket::FIRST_PACKET) { 120 if (state_ != kReady && state_ != kDone && state_ != kPartitionDone) { 121 state_ = kError; 122 LOG(WARNING) << "Received unexpected FIRST_PACKET."; 123 return; 124 } 125 126 // Reset the buffer location status variables on the first packet. 127 clip_.setXYWH(packet->format().x(), packet->format().y(), 128 packet->format().width(), packet->format().height()); 129 if (!SkIRect::MakeSize(screen_size_).contains(clip_)) { 130 state_ = kError; 131 LOG(WARNING) << "Invalid clipping area received."; 132 return; 133 } 134 135 state_ = kProcessing; 136 row_pos_ = 0; 137 row_y_ = 0; 138 } 139 140 if (state_ != kProcessing) { 141 state_ = kError; 142 LOG(WARNING) << "Received unexpected packet."; 143 return; 144 } 145 146 if (packet->flags() & VideoPacket::LAST_PACKET) { 147 if (state_ != kProcessing) { 148 state_ = kError; 149 LOG(WARNING) << "Received unexpected LAST_PACKET."; 150 return; 151 } 152 state_ = kPartitionDone; 153 } 154 155 if (packet->flags() & VideoPacket::LAST_PARTITION) { 156 if (state_ != kPartitionDone) { 157 state_ = kError; 158 LOG(WARNING) << "Received unexpected LAST_PARTITION."; 159 return; 160 } 161 state_ = kDone; 162 } 163 164 return; 165 } 166 167 VideoPacketFormat::Encoding VideoDecoderVerbatim::Encoding() { 168 return VideoPacketFormat::ENCODING_VERBATIM; 169 } 170 171 void VideoDecoderVerbatim::Invalidate(const SkISize& view_size, 172 const SkRegion& region) { 173 updated_region_.op(region, SkRegion::kUnion_Op); 174 } 175 176 void VideoDecoderVerbatim::RenderFrame(const SkISize& view_size, 177 const SkIRect& clip_area, 178 uint8* image_buffer, 179 int image_stride, 180 SkRegion* output_region) { 181 output_region->setEmpty(); 182 183 // TODO(alexeypa): scaling is not implemented. 184 SkIRect clip_rect = SkIRect::MakeSize(screen_size_); 185 if (!clip_rect.intersect(clip_area)) 186 return; 187 188 int screen_stride = screen_size_.width() * kBytesPerPixel; 189 190 for (SkRegion::Iterator i(updated_region_); !i.done(); i.next()) { 191 SkIRect rect(i.rect()); 192 if (!rect.intersect(clip_rect)) 193 continue; 194 195 CopyRGB32Rect(screen_buffer_.get(), screen_stride, 196 clip_rect, 197 image_buffer, image_stride, 198 clip_area, 199 rect); 200 output_region->op(rect, SkRegion::kUnion_Op); 201 } 202 203 updated_region_.setEmpty(); 204 } 205 206 const SkRegion* VideoDecoderVerbatim::GetImageShape() { 207 return NULL; 208 } 209 210 } // namespace remoting 211