16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "remoting/host/fake_desktop_capturer.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/bind.h"
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/memory/ref_counted.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace remoting {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// FakeDesktopCapturer generates a white picture of size kWidth x kHeight
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with a rectangle of size kBoxWidth x kBoxHeight. The rectangle moves kSpeed
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// pixels per frame along both axes, and bounces off the sides of the screen.
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)static const int kWidth = FakeDesktopCapturer::kWidth;
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)static const int kHeight = FakeDesktopCapturer::kHeight;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kBoxWidth = 140;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kBoxHeight = 140;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSpeed = 20;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT(kBoxWidth < kWidth && kBoxHeight < kHeight, bad_box_size);
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMPILE_ASSERT((kBoxWidth % kSpeed == 0) && (kWidth % kSpeed == 0) &&
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               (kBoxHeight % kSpeed == 0) && (kHeight % kSpeed == 0),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               sizes_must_be_multiple_of_kSpeed);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class DefaultFrameGenerator
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : public base::RefCountedThreadSafe<DefaultFrameGenerator> {
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public:
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DefaultFrameGenerator()
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      : bytes_per_row_(0),
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        box_pos_x_(0),
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        box_pos_y_(0),
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        box_speed_x_(kSpeed),
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        box_speed_y_(kSpeed),
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        first_frame_(true) {}
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> GenerateFrame(
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      webrtc::DesktopCapturer::Callback* callback);
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private:
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  friend class base::RefCountedThreadSafe<DefaultFrameGenerator>;
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ~DefaultFrameGenerator() {}
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  webrtc::DesktopSize size_;
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int bytes_per_row_;
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int box_pos_x_;
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int box_pos_y_;
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int box_speed_x_;
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int box_speed_y_;
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool first_frame_;
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DefaultFrameGenerator);
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)scoped_ptr<webrtc::DesktopFrame> DefaultFrameGenerator::GenerateFrame(
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    webrtc::DesktopCapturer::Callback* callback) {
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int kBytesPerPixel = webrtc::DesktopFrame::kBytesPerPixel;
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int buffer_size = kWidth * kHeight * kBytesPerPixel;
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  webrtc::SharedMemory* shared_memory =
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      callback->CreateSharedMemory(buffer_size);
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame;
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (shared_memory) {
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame.reset(new webrtc::SharedMemoryDesktopFrame(
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        webrtc::DesktopSize(kWidth, kHeight), bytes_per_row_, shared_memory));
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame.reset(
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)));
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Move the box.
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool old_box_pos_x = box_pos_x_;
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  box_pos_x_ += box_speed_x_;
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (box_pos_x_ + kBoxWidth >= kWidth || box_pos_x_ == 0)
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    box_speed_x_ = -box_speed_x_;
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool old_box_pos_y = box_pos_y_;
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  box_pos_y_ += box_speed_y_;
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (box_pos_y_ + kBoxHeight >= kHeight || box_pos_y_ == 0)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    box_speed_y_ = -box_speed_y_;
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  memset(frame->data(), 0xff, kHeight * frame->stride());
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Draw rectangle with the following colors in its corners:
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //     cyan....yellow
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //     ..............
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //     blue.......red
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  uint8* row = frame->data() +
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      (box_pos_y_ * size_.width() + box_pos_x_) * kBytesPerPixel;
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (int y = 0; y < kBoxHeight; ++y) {
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for (int x = 0; x < kBoxWidth; ++x) {
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int r = x * 255 / kBoxWidth;
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int g = y * 255 / kBoxHeight;
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      int b = 255 - (x * 255 / kBoxWidth);
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      row[x * kBytesPerPixel] = r;
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      row[x * kBytesPerPixel + 1] = g;
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      row[x * kBytesPerPixel + 2] = b;
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      row[x * kBytesPerPixel + 3] = 0xff;
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    row += frame->stride();
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (first_frame_) {
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame->mutable_updated_region()->SetRect(
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        webrtc::DesktopRect::MakeXYWH(0, 0, kWidth, kHeight));
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    first_frame_ = false;
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame->mutable_updated_region()->SetRect(webrtc::DesktopRect::MakeXYWH(
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        old_box_pos_x, old_box_pos_y, kBoxWidth, kBoxHeight));
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    frame->mutable_updated_region()->AddRect(webrtc::DesktopRect::MakeXYWH(
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        box_pos_x_, box_pos_y_, kBoxWidth, kBoxHeight));
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return frame.Pass();
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)FakeDesktopCapturer::FakeDesktopCapturer()
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : callback_(NULL) {
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  frame_generator_ = base::Bind(&DefaultFrameGenerator::GenerateFrame,
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                new DefaultFrameGenerator());
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)FakeDesktopCapturer::~FakeDesktopCapturer() {}
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void FakeDesktopCapturer::set_frame_generator(
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const FrameGenerator& frame_generator) {
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(!callback_);
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  frame_generator_ = frame_generator;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void FakeDesktopCapturer::Start(Callback* callback) {
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(!callback_);
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(callback);
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  callback_ = callback;
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void FakeDesktopCapturer::Capture(const webrtc::DesktopRegion& region) {
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::Time capture_start_time = base::Time::Now();
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<webrtc::DesktopFrame> frame = frame_generator_.Run(callback_);
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  frame->set_capture_time_ms(
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  callback_->OnCaptureCompleted(frame.release());
14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace remoting
152