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