OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 <deque> |
| 6 #include <stdlib.h> |
| 7 |
| 8 #include "gfx/rect.h" |
| 9 #include "media/base/video_frame.h" |
| 10 #include "remoting/base/codec_test.h" |
| 11 #include "remoting/base/encoder.h" |
| 12 #include "remoting/base/mock_objects.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" |
| 14 |
| 15 static const int kWidth = 320; |
| 16 static const int kHeight = 240; |
| 17 static const int kBytesPerPixel = 4; |
| 18 |
| 19 // Some sample rects for testing. |
| 20 static const gfx::Rect kTestRects[] = { |
| 21 gfx::Rect(0, 0, kWidth, kHeight), |
| 22 gfx::Rect(0, 0, kWidth / 2, kHeight / 2), |
| 23 gfx::Rect(kWidth / 2, kHeight / 2, kWidth / 2, kHeight / 2), |
| 24 gfx::Rect(16, 16, 16, 16), |
| 25 gfx::Rect(128, 64, 32, 32) |
| 26 }; |
| 27 |
| 28 namespace remoting { |
| 29 |
| 30 // A class to test that the state transition of the Encoder is correct. |
| 31 class EncoderStateTester { |
| 32 public: |
| 33 EncoderStateTester() |
| 34 : next_state_(Encoder::EncodingStarting) { |
| 35 } |
| 36 |
| 37 ~EncoderStateTester() { |
| 38 EXPECT_EQ(Encoder::EncodingStarting, next_state_); |
| 39 } |
| 40 |
| 41 // Set the state output of the Encoder. |
| 42 void ReceivedState(Encoder::EncodingState state) { |
| 43 if (state & Encoder::EncodingStarting) { |
| 44 EXPECT_EQ(Encoder::EncodingStarting, next_state_); |
| 45 next_state_ = Encoder::EncodingInProgress | Encoder::EncodingEnded; |
| 46 } else { |
| 47 EXPECT_FALSE(next_state_ & Encoder::EncodingStarting); |
| 48 } |
| 49 |
| 50 if (state & Encoder::EncodingInProgress) { |
| 51 EXPECT_TRUE(next_state_ & Encoder::EncodingInProgress); |
| 52 } |
| 53 |
| 54 if (state & Encoder::EncodingEnded) { |
| 55 EXPECT_TRUE(next_state_ & Encoder::EncodingEnded); |
| 56 next_state_ = Encoder::EncodingStarting; |
| 57 } |
| 58 } |
| 59 |
| 60 private: |
| 61 Encoder::EncodingState next_state_; |
| 62 |
| 63 DISALLOW_COPY_AND_ASSIGN(EncoderStateTester); |
| 64 }; |
| 65 |
| 66 // A class to test the message output of the encoder. |
| 67 class EncoderMessageTester { |
| 68 public: |
| 69 EncoderMessageTester() |
| 70 : begin_rect_(0), |
| 71 rect_data_(0), |
| 72 end_rect_(0), |
| 73 state_(kWaitingForBeginRect), |
| 74 strict_(false) { |
| 75 } |
| 76 |
| 77 ~EncoderMessageTester() { |
| 78 EXPECT_EQ(begin_rect_, end_rect_); |
| 79 EXPECT_EQ(kWaitingForBeginRect, state_); |
| 80 } |
| 81 |
| 82 // Test that we received the correct message. |
| 83 void ReceivedMessage(HostMessage* message) { |
| 84 EXPECT_TRUE(message->has_update_stream_packet()); |
| 85 |
| 86 if (state_ == kWaitingForBeginRect) { |
| 87 EXPECT_TRUE(message->update_stream_packet().has_begin_rect()); |
| 88 state_ = kWaitingForRectData; |
| 89 ++begin_rect_; |
| 90 |
| 91 if (strict_) { |
| 92 gfx::Rect rect = rects_.front(); |
| 93 rects_.pop_front(); |
| 94 EXPECT_EQ(rect.x(), message->update_stream_packet().begin_rect().x()); |
| 95 EXPECT_EQ(rect.y(), message->update_stream_packet().begin_rect().y()); |
| 96 EXPECT_EQ(rect.width(), |
| 97 message->update_stream_packet().begin_rect().width()); |
| 98 EXPECT_EQ(rect.height(), |
| 99 message->update_stream_packet().begin_rect().height()); |
| 100 } |
| 101 } else { |
| 102 EXPECT_FALSE(message->update_stream_packet().has_begin_rect()); |
| 103 } |
| 104 |
| 105 if (state_ == kWaitingForRectData) { |
| 106 if (message->update_stream_packet().has_rect_data()) { |
| 107 ++rect_data_; |
| 108 } |
| 109 |
| 110 if (message->update_stream_packet().has_end_rect()) { |
| 111 // Expect that we have received some data. |
| 112 EXPECT_GT(rect_data_, 0); |
| 113 rect_data_ = 0; |
| 114 state_ = kWaitingForBeginRect; |
| 115 ++end_rect_; |
| 116 } |
| 117 } |
| 118 } |
| 119 |
| 120 void set_strict(bool strict) { |
| 121 strict_ = strict; |
| 122 } |
| 123 |
| 124 void AddRects(const gfx::Rect* rects, int count) { |
| 125 rects_.insert(rects_.begin() + rects_.size(), rects, rects + count); |
| 126 } |
| 127 |
| 128 private: |
| 129 enum State { |
| 130 kWaitingForBeginRect, |
| 131 kWaitingForRectData, |
| 132 }; |
| 133 |
| 134 int begin_rect_; |
| 135 int rect_data_; |
| 136 int end_rect_; |
| 137 State state_; |
| 138 bool strict_; |
| 139 |
| 140 std::deque<gfx::Rect> rects_; |
| 141 |
| 142 DISALLOW_COPY_AND_ASSIGN(EncoderMessageTester); |
| 143 }; |
| 144 |
| 145 class DecoderTester { |
| 146 public: |
| 147 DecoderTester(Decoder* decoder) |
| 148 : strict_(false), |
| 149 decoder_(decoder), |
| 150 decode_done_(false) { |
| 151 media::VideoFrame::CreateFrame(media::VideoFrame::RGB32, |
| 152 kWidth, kHeight, |
| 153 base::TimeDelta(), |
| 154 base::TimeDelta(), &frame_); |
| 155 EXPECT_TRUE(frame_.get()); |
| 156 } |
| 157 |
| 158 void ReceivedMessage(HostMessage* message) { |
| 159 if (message->has_begin_update_stream()) { |
| 160 delete message; |
| 161 decoder_->BeginDecode( |
| 162 frame_, &update_rects_, |
| 163 NewRunnableMethod(this, &DecoderTester::OnPartialDecodeDone), |
| 164 NewRunnableMethod(this, &DecoderTester::OnDecodeDone)); |
| 165 } |
| 166 |
| 167 if (message->has_update_stream_packet()) { |
| 168 decoder_->PartialDecode(message); |
| 169 } |
| 170 |
| 171 if (message->has_end_update_stream()) { |
| 172 delete message; |
| 173 decoder_->EndDecode(); |
| 174 } |
| 175 } |
| 176 |
| 177 void set_strict(bool strict) { |
| 178 strict_ = strict; |
| 179 } |
| 180 |
| 181 void set_capture_data(scoped_refptr<CaptureData> data) { |
| 182 capture_data_ = data; |
| 183 } |
| 184 |
| 185 void AddRects(const gfx::Rect* rects, int count) { |
| 186 rects_.insert(rects_.begin() + rects_.size(), rects, rects + count); |
| 187 } |
| 188 |
| 189 bool decode_done() const { return decode_done_; } |
| 190 void reset_decode_done() { decode_done_ = false; } |
| 191 |
| 192 private: |
| 193 void OnPartialDecodeDone() { |
| 194 if (!strict_) |
| 195 return; |
| 196 for (size_t i = 0; i < update_rects_.size(); ++i) { |
| 197 EXPECT_FALSE(rects_.empty()); |
| 198 gfx::Rect rect = rects_.front(); |
| 199 rects_.pop_front(); |
| 200 EXPECT_EQ(rect, update_rects_[i]); |
| 201 } |
| 202 } |
| 203 |
| 204 void OnDecodeDone() { |
| 205 decode_done_ = true; |
| 206 if (!strict_) |
| 207 return; |
| 208 |
| 209 EXPECT_TRUE(capture_data_.get()); |
| 210 for (int i = 0; i < DataPlanes::kPlaneCount; ++i) { |
| 211 if (!frame_->data(i) || !capture_data_->data_planes().data[i]) |
| 212 continue; |
| 213 // TODO(hclam): HAndle YUV. |
| 214 int size = capture_data_->data_planes().strides[i] * kHeight; |
| 215 EXPECT_EQ(0, memcmp(capture_data_->data_planes().data[i], |
| 216 frame_->data(i), size)); |
| 217 } |
| 218 } |
| 219 |
| 220 bool strict_; |
| 221 std::deque<gfx::Rect> rects_; |
| 222 UpdatedRects update_rects_; |
| 223 Decoder* decoder_; |
| 224 scoped_refptr<media::VideoFrame> frame_; |
| 225 scoped_refptr<CaptureData> capture_data_; |
| 226 bool decode_done_; |
| 227 |
| 228 DISALLOW_COPY_AND_ASSIGN(DecoderTester); |
| 229 }; |
| 230 |
| 231 class EncoderTester { |
| 232 public: |
| 233 EncoderTester(EncoderMessageTester* message_tester, |
| 234 EncoderStateTester* state_tester) |
| 235 : message_tester_(message_tester), |
| 236 state_tester_(state_tester), |
| 237 data_available_(0) { |
| 238 } |
| 239 |
| 240 ~EncoderTester() { |
| 241 EXPECT_GT(data_available_, 0); |
| 242 } |
| 243 |
| 244 void DataAvailable(HostMessage* message, |
| 245 Encoder::EncodingState state) { |
| 246 ++data_available_; |
| 247 message_tester_->ReceivedMessage(message); |
| 248 state_tester_->ReceivedState(state); |
| 249 |
| 250 // Send the message to the DecoderTester. |
| 251 if (decoder_tester_) { |
| 252 if (state & Encoder::EncodingStarting) { |
| 253 HostMessage* begin_update = new HostMessage(); |
| 254 begin_update->mutable_begin_update_stream(); |
| 255 decoder_tester_->ReceivedMessage(begin_update); |
| 256 } |
| 257 |
| 258 if (state & Encoder::EncodingInProgress) { |
| 259 decoder_tester_->ReceivedMessage(message); |
| 260 } |
| 261 |
| 262 if (state & Encoder::EncodingEnded) { |
| 263 HostMessage* end_update = new HostMessage(); |
| 264 end_update->mutable_end_update_stream(); |
| 265 decoder_tester_->ReceivedMessage(end_update); |
| 266 } |
| 267 return; |
| 268 } |
| 269 delete message; |
| 270 } |
| 271 |
| 272 void AddRects(const gfx::Rect* rects, int count) { |
| 273 message_tester_->AddRects(rects, count); |
| 274 } |
| 275 |
| 276 void set_decoder_tester(DecoderTester* decoder_tester) { |
| 277 decoder_tester_ = decoder_tester; |
| 278 } |
| 279 |
| 280 private: |
| 281 EncoderMessageTester* message_tester_; |
| 282 EncoderStateTester* state_tester_; |
| 283 DecoderTester* decoder_tester_; |
| 284 int data_available_; |
| 285 |
| 286 DISALLOW_COPY_AND_ASSIGN(EncoderTester); |
| 287 }; |
| 288 |
| 289 scoped_refptr<CaptureData> PrepareEncodeData(PixelFormat format, |
| 290 uint8** memory) { |
| 291 // TODO(hclam): Support also YUV format. |
| 292 CHECK(format == PixelFormatRgb32); |
| 293 int size = kWidth * kHeight * kBytesPerPixel; |
| 294 |
| 295 *memory = new uint8[size]; |
| 296 srand(0); |
| 297 for (int i = 0; i < size; ++i) { |
| 298 (*memory)[i] = rand() % 256; |
| 299 } |
| 300 |
| 301 DataPlanes planes; |
| 302 memset(planes.data, 0, sizeof(planes.data)); |
| 303 memset(planes.strides, 0, sizeof(planes.strides)); |
| 304 planes.data[0] = *memory; |
| 305 planes.strides[0] = kWidth * kBytesPerPixel; |
| 306 |
| 307 scoped_refptr<CaptureData> data = |
| 308 new CaptureData(planes, kWidth, kHeight, format); |
| 309 return data; |
| 310 } |
| 311 |
| 312 static void TestEncodingRects(Encoder* encoder, |
| 313 EncoderTester* tester, |
| 314 scoped_refptr<CaptureData> data, |
| 315 const gfx::Rect* rects, int count) { |
| 316 data->mutable_dirty_rects().clear(); |
| 317 data->mutable_dirty_rects().insert( |
| 318 data->mutable_dirty_rects().begin(), rects, rects + count); |
| 319 tester->AddRects(rects, count); |
| 320 |
| 321 encoder->Encode(data, true, |
| 322 NewCallback(tester, &EncoderTester::DataAvailable)); |
| 323 } |
| 324 |
| 325 void TestEncoder(Encoder* encoder, bool strict) { |
| 326 EncoderMessageTester message_tester; |
| 327 message_tester.set_strict(strict); |
| 328 |
| 329 EncoderStateTester state_tester; |
| 330 EncoderTester tester(&message_tester, &state_tester); |
| 331 |
| 332 uint8* memory; |
| 333 scoped_refptr<CaptureData> data = |
| 334 PrepareEncodeData(PixelFormatRgb32, &memory); |
| 335 |
| 336 TestEncodingRects(encoder, &tester, data, kTestRects, 1); |
| 337 TestEncodingRects(encoder, &tester, data, kTestRects + 1, 1); |
| 338 TestEncodingRects(encoder, &tester, data, kTestRects + 2, 1); |
| 339 TestEncodingRects(encoder, &tester, data, kTestRects + 3, 2); |
| 340 delete memory; |
| 341 } |
| 342 |
| 343 static void TestEncodingRects(Encoder* encoder, |
| 344 EncoderTester* encoder_tester, |
| 345 DecoderTester* decoder_tester, |
| 346 scoped_refptr<CaptureData> data, |
| 347 const gfx::Rect* rects, int count) { |
| 348 data->mutable_dirty_rects().clear(); |
| 349 data->mutable_dirty_rects().insert( |
| 350 data->mutable_dirty_rects().begin(), rects, rects + count); |
| 351 encoder_tester->AddRects(rects, count); |
| 352 decoder_tester->AddRects(rects, count); |
| 353 decoder_tester->reset_decode_done(); |
| 354 |
| 355 encoder->Encode(data, true, |
| 356 NewCallback(encoder_tester, &EncoderTester::DataAvailable)); |
| 357 EXPECT_TRUE(decoder_tester->decode_done()); |
| 358 } |
| 359 |
| 360 void TestEncoderDecoder(Encoder* encoder, Decoder* decoder, bool strict) { |
| 361 EncoderMessageTester message_tester; |
| 362 message_tester.set_strict(strict); |
| 363 |
| 364 EncoderStateTester state_tester; |
| 365 EncoderTester encoder_tester(&message_tester, &state_tester); |
| 366 |
| 367 uint8* memory; |
| 368 scoped_refptr<CaptureData> data = |
| 369 PrepareEncodeData(PixelFormatRgb32, &memory); |
| 370 DecoderTester decoder_tester(decoder); |
| 371 decoder_tester.set_strict(strict); |
| 372 decoder_tester.set_capture_data(data); |
| 373 encoder_tester.set_decoder_tester(&decoder_tester); |
| 374 |
| 375 TestEncodingRects(encoder, &encoder_tester, &decoder_tester, data, |
| 376 kTestRects, 1); |
| 377 TestEncodingRects(encoder, &encoder_tester, &decoder_tester, data, |
| 378 kTestRects + 1, 1); |
| 379 TestEncodingRects(encoder, &encoder_tester, &decoder_tester, data, |
| 380 kTestRects + 2, 1); |
| 381 TestEncodingRects(encoder, &encoder_tester, &decoder_tester, data, |
| 382 kTestRects + 3, 2); |
| 383 delete memory; |
| 384 } |
| 385 |
| 386 } // namespace remoting |
| 387 |
| 388 DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::DecoderTester); |
OLD | NEW |